http://sourceware.org/gdb/wiki/ProjectArcher http://sourceware.org/gdb/wiki/ArcherBranchManagement GIT snapshot: commit 543fb2154d3bd551344b990b911be5c6cc703504 branch `archer' - the merge of branches: archer-jankratochvil-merge-expr archer-keiths-expr-cumulative (archer-swagiaal-using-directive) archer-jankratochvil-misc archer-jankratochvil-python archer-jankratochvil-type-refcount archer-tromey-python archer-jankratochvil-vla archer-jankratochvil-type-refcount archer-pmuldoon-exception-rewind-master archer-sergio-catch-syscall archer-tromey-charset archer-tromey-delayed-symfile diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 74aa72e..c84a4ac 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -167,11 +167,20 @@ INTL_CFLAGS = @INCINTL@ # Where is the ICONV library? This can be empty if libc has iconv. LIBICONV = @LIBICONV@ +LIBICONV_INCLUDE = @LIBICONV_INCLUDE@ +LIBICONV_LIBDIR = @LIBICONV_LIBDIR@ # Did the user give us a --with-sysroot option? TARGET_SYSTEM_ROOT = @TARGET_SYSTEM_ROOT@ TARGET_SYSTEM_ROOT_DEFINE = @TARGET_SYSTEM_ROOT_DEFINE@ +# Did the user give us a --with-gdb-datadir option? +GDB_DATADIR_PATH = @GDB_DATADIR_PATH@ + +# The argument to --with-pythondir. If not given, this is +# GDB_DATADIR_PATH/python. +pythondir = @pythondir@ + # Helper code from gnulib. LIBGNU = gnulib/libgnu.a INCGNU = -I$(srcdir)/gnulib -Ignulib @@ -270,12 +279,34 @@ SUBDIR_TUI_CFLAGS= \ # SUBDIR_PYTHON_OBS = \ python.o \ + python-block.o \ + python-breakpoint.o \ python-cmd.o \ + python-frame.o \ + python-function.o \ + python-hooks.o \ + python-membuf.o \ + python-objfile.o \ + python-param.o \ + python-symbol.o \ + python-symtab.o \ + python-type.o \ python-utils.o \ python-value.o SUBDIR_PYTHON_SRCS = \ python/python.c \ + python/python-block.c \ + python/python-breakpoint.c \ python/python-cmd.c \ + python/python-frame.c \ + python/python-function.c \ + python/python-hooks.c \ + python/python-membuf.c \ + python/python-objfile.c \ + python/python-param.c \ + python/python-symbol.c \ + python/python-symtab.c \ + python/python-type.c \ python/python-utils.c \ python/python-value.c SUBDIR_PYTHON_DEPS = @@ -390,7 +421,8 @@ INTERNAL_CFLAGS_BASE = \ $(CFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \ $(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \ $(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \ - $(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) + $(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) \ + $(LIBICONV_INCLUDE) INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS) INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS) @@ -402,7 +434,7 @@ LDFLAGS = @LDFLAGS@ # I think it's perfectly reasonable for a user to set -pg in CFLAGS # and have it work; that's why CFLAGS is here. # PROFILE_CFLAGS is _not_ included, however, because we use monstartup. -INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_LDFLAGS) +INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_LDFLAGS) $(LIBICONV_LIBDIR) # If your system is missing alloca(), or, more likely, it's there but # it doesn't work, then refer to libiberty. @@ -663,6 +695,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ valarith.c valops.c valprint.c value.c varobj.c vec.c \ wrapper.c \ xml-tdesc.c xml-support.c \ + xml-syscall.c \ inferior.c LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c @@ -733,7 +766,8 @@ config/sparc/nm-sol2.h config/nm-linux.h config/mips/nm-irix5.h \ config/rs6000/nm-rs6000.h top.h bsd-kvm.h gdb-stabs.h reggroups.h \ annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h \ remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \ -sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h +sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h xml-syscall.h \ +python/python.h python/python-internal.h # Header files that already have srcdir in them, or which are in objdir. @@ -812,10 +846,16 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ trad-frame.o \ tramp-frame.o \ solib.o solib-null.o \ - prologue-value.o memory-map.o xml-support.o \ + prologue-value.o memory-map.o xml-support.o xml-syscall.o \ target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \ inferior.o osdata.o +# Definitions for the syscall's XML files and dir +XML_SYSCALLS_DIR = syscalls/ +XML_SYSCALLS_FILES = gdb-syscalls.dtd \ + ppc-linux.xml ppc64-linux.xml \ + i386-linux.xml amd64-linux.xml + TSOBS = inflow.o SUBDIRS = @subdirs@ @@ -849,11 +889,38 @@ generated_files = config.h observer.h observer.inc ada-lex.c \ $(COMPILE) $< $(POSTCOMPILE) -all: gdb$(EXEEXT) $(CONFIG_ALL) +all: gdb$(EXEEXT) $(CONFIG_ALL) .gdbinit xml-syscall-copy @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do .PHONY: all-tui all-tui: $(TUI)$(EXEEXT) +xml-syscall-copy: + if [ "`cd $(srcdir) && pwd`" != "`pwd`" ] ; then \ + mkdir -p ./$(XML_SYSCALLS_DIR) ; \ + list='$(XML_SYSCALLS_FILES)' ; \ + for file in $$list ; do \ + f=$(srcdir)/$(XML_SYSCALLS_DIR)/$$file ; \ + if test -f $$f ; then \ + $(INSTALL_DATA) $$f \ + ./$(XML_SYSCALLS_DIR) ; \ + fi ; \ + done ; \ + fi ; + +# This target is responsible for properly installing the syscalls' +# XML files in the system. +xml-syscall-install: + $(SHELL) $(srcdir)/../mkinstalldirs \ + $(DESTDIR)$(GDB_DATADIR_PATH)/$(XML_SYSCALLS_DIR) ; \ + list='$(XML_SYSCALLS_FILES)' ; \ + for file in $$list ; do \ + f=$(srcdir)/$(XML_SYSCALLS_DIR)/$$file ; \ + if test -f $$f ; then \ + $(INSTALL_DATA) $$f \ + $(DESTDIR)$(GDB_DATADIR_PATH)/$(XML_SYSCALLS_DIR) ; \ + fi ; \ + done ; + installcheck: # The check target can not use subdir_do, because subdir_do does not @@ -907,8 +974,11 @@ gdb.z:gdb.1 # source file and doesn't care about rebuilding or just wants to save the # time it takes for make to check that all is up to date. # install-only is intended to address that need. -install: all install-only -install-only: $(CONFIG_INSTALL) +install: all install-only + +# The "install-only" target also installs the syscalls' XML files in +# the system. +install-only: $(CONFIG_INSTALL) xml-syscall-install transformed_name=`t='$(program_transform_name)'; \ echo gdb | sed -e "$$t"` ; \ if test "x$$transformed_name" = x; then \ @@ -1202,6 +1272,12 @@ stamp-h: config.in config.status CONFIG_LINKS= \ $(SHELL) config.status +.gdbinit: gdbinit.in config.status + CONFIG_FILES=".gdbinit:gdbinit.in" \ + CONFIG_COMMANDS= \ + CONFIG_HEADERS= \ + $(SHELL) config.status + config.status: configure configure.tgt configure.host $(SHELL) config.status --recheck @@ -1845,10 +1921,54 @@ python.o: $(srcdir)/python/python.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c $(POSTCOMPILE) +python-block.o: $(srcdir)/python/python-block.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-block.c + $(POSTCOMPILE) + +python-breakpoint.o: $(srcdir)/python/python-breakpoint.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-breakpoint.c + $(POSTCOMPILE) + python-cmd.o: $(srcdir)/python/python-cmd.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-cmd.c $(POSTCOMPILE) +python-frame.o: $(srcdir)/python/python-frame.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-frame.c + $(POSTCOMPILE) + +python-function.o: $(srcdir)/python/python-function.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-function.c + $(POSTCOMPILE) + +python-hooks.o: $(srcdir)/python/python-hooks.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-hooks.c + $(POSTCOMPILE) + +python-membuf.o: $(srcdir)/python/python-membuf.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-membuf.c + $(POSTCOMPILE) + +python-objfile.o: $(srcdir)/python/python-objfile.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c + $(POSTCOMPILE) + +python-param.o: $(srcdir)/python/python-param.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-param.c + $(POSTCOMPILE) + +python-symbol.o: $(srcdir)/python/python-symbol.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-symbol.c + $(POSTCOMPILE) + +python-symtab.o: $(srcdir)/python/python-symtab.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-symtab.c + $(POSTCOMPILE) + +python-type.o: $(srcdir)/python/python-type.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-type.c + $(POSTCOMPILE) + python-utils.o: $(srcdir)/python/python-utils.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-utils.c $(POSTCOMPILE) @@ -1857,6 +1977,38 @@ python-value.o: $(srcdir)/python/python-value.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-value.c $(POSTCOMPILE) +# All python library files, with the "python/lib" stripped off. +# Note that we should only install files in the "gdb" module. +PY_FILES = gdb/FrameIterator.py gdb/command/alias.py \ + gdb/command/backtrace.py gdb/command/require.py \ + gdb/command/pahole.py gdb/command/__init__.py \ + gdb/command/ignore_errors.py gdb/command/save_breakpoints.py \ + gdb/libstdcxx/v6/printers.py gdb/libstdcxx/v6/__init__.py \ + gdb/libstdcxx/__init__.py gdb/function/caller_is.py \ + gdb/function/in_scope.py gdb/function/__init__.py gdb/backtrace.py \ + gdb/__init__.py + +# Install the Python library. Python library files go under +# $(pythondir). +install-python: + files='$(PY_FILES)'; for file in $$files; do \ + dir=`echo "$$file" | sed 's,/[^/]*$$,,'`; \ + $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(pythondir)/$$dir; \ + $(INSTALL_DATA) $(srcdir)/python/lib/$$file $(DESTDIR)$(pythondir)/$$file; \ + done + +# Other packages may have their files installed in $(pythondir). +uninstall-python: + files='$(PY_FILES)'; for file in $$files; do \ + slashdir=`echo "/$$file" | sed 's,/[^/]*$$,,'`; \ + rm -f $(DESTDIR)$(pythondir)/$$file; \ + while test "x$$file" != "x$$slashdir"; do \ + rmdir 2>/dev/null "$(DESTDIR)$(pythondir)$$slashdir"; \ + file="$$slashdir"; \ + slashdir=`echo "$$file" | sed 's,/[^/]*$$,,'`; \ + done \ + done + # # Dependency tracking. Most of this is conditional on GNU Make being # found by configure; if GNU Make is not found, we fall back to a diff --git a/gdb/NEWS b/gdb/NEWS index 9078412..3f084e7 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,13 @@ *** Changes since GDB 6.8 +* GDB now has support for multi-byte and wide character sets on the +target. Strings whose character type is wchar_t, char16_t, or +char32_t are now correctly printed. GDB supports wide- and unicode- +literals in C, that is, L'x', L"string", u'x', u"string", U'x', and +U"string" syntax. And, GDB allows the "%ls" and "%lc" formats in +`printf'. + * GDB now supports automatic retrieval of shared library files from remote targets. To use this feature, specify a system root that begins with the `remote:' prefix, either via the `set sysroot' command or via @@ -182,6 +189,11 @@ set target-async with GDB while the target is running. "show target-async" displays the current state of asynchronous execution of the target. +set target-wide-charset +show target-wide-charset + The target-wide-charset is the name of the character set that GDB + uses when printing characters whose type is wchar_t. + set tcp auto-retry (on|off) show tcp auto-retry set tcp connect-timeout diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4 index 81b5d47..c2bd043 100644 --- a/gdb/acinclude.m4 +++ b/gdb/acinclude.m4 @@ -29,6 +29,9 @@ sinclude([../config/depstand.m4]) dnl For AM_LC_MESSAGES sinclude([../config/lcmessage.m4]) +dnl For AM_LANGINFO_CODESET. +sinclude([../config/codeset.m4]) + # # Sometimes the native compiler is a bogus stub for gcc or /usr/ucb/cc. This # makes configure think it's cross compiling. If --target wasn't used, then @@ -174,8 +177,8 @@ AC_DEFUN([AM_ICONV], AC_ARG_WITH([libiconv-prefix], [ --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib], [ for dir in `echo "$withval" | tr : ' '`; do - if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi - if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi + if test -d $dir/include; then LIBICONV_INCLUDE="-I$dir/include"; CPPFLAGS="$CPPFLAGS -I$dir/include"; fi + if test -d $dir/lib; then LIBICONV_LIBDIR="-L$dir/lib"; LDFLAGS="$LDFLAGS -L$dir/lib"; fi done ]) @@ -230,6 +233,8 @@ size_t iconv(); LIBICONV="-liconv" fi AC_SUBST(LIBICONV) + AC_SUBST(LIBICONV_INCLUDE) + AC_SUBST(LIBICONV_LIBDIR) ]) dnl written by Guido Draheim , original by Alexandre Oliva diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 671cb35..edcee3f 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -486,7 +486,7 @@ coerce_unspec_val_to_type (struct value *val, struct type *type) set_value_component_location (result, val); set_value_bitsize (result, value_bitsize (val)); set_value_bitpos (result, value_bitpos (val)); - VALUE_ADDRESS (result) += value_offset (val); + set_value_address (result, value_address (val)); if (value_lazy (val) || TYPE_LENGTH (type) > TYPE_LENGTH (value_type (val))) set_value_lazy (result, 1); @@ -1328,7 +1328,7 @@ thin_data_pntr (struct value *val) value_copy (val)); else return value_from_longest (desc_data_type (thin_descriptor_type (type)), - VALUE_ADDRESS (val) + value_offset (val)); + value_address (val)); } /* True iff TYPE indicates a "thick" array pointer type. */ @@ -1393,7 +1393,7 @@ desc_bounds (struct value *arr) if (TYPE_CODE (type) == TYPE_CODE_PTR) addr = value_as_long (arr); else - addr = VALUE_ADDRESS (arr) + value_offset (arr); + addr = value_address (arr); return value_from_longest (lookup_pointer_type (bounds_type), @@ -1666,8 +1666,8 @@ ada_type_of_array (struct value *arr, int bounds) return NULL; while (arity > 0) { - struct type *range_type = alloc_type (objf); - struct type *array_type = alloc_type (objf); + struct type *range_type = alloc_type (objf, NULL); + struct type *array_type = alloc_type (objf, NULL); struct value *low = desc_one_bound (descriptor, arity, 0); struct value *high = desc_one_bound (descriptor, arity, 1); arity -= 1; @@ -1774,9 +1774,9 @@ packed_array_type (struct type *type, long *elt_bits) if (TYPE_CODE (type) != TYPE_CODE_ARRAY) return type; - new_type = alloc_type (TYPE_OBJFILE (type)); new_elt_type = packed_array_type (ada_check_typedef (TYPE_TARGET_TYPE (type)), elt_bits); + new_type = alloc_type (TYPE_OBJFILE (type), new_elt_type); create_array_type (new_type, new_elt_type, TYPE_INDEX_TYPE (type)); TYPE_FIELD_BITSIZE (new_type, 0) = *elt_bits; TYPE_NAME (new_type) = ada_type_name (type); @@ -1831,6 +1831,7 @@ decode_packed_array_type (struct type *type) return NULL; } shadow_type = SYMBOL_TYPE (sym); + CHECK_TYPEDEF (shadow_type); if (TYPE_CODE (shadow_type) != TYPE_CODE_ARRAY) { @@ -2005,10 +2006,9 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr, } else if (VALUE_LVAL (obj) == lval_memory && value_lazy (obj)) { - v = value_at (type, - VALUE_ADDRESS (obj) + value_offset (obj) + offset); + v = value_at (type, value_address (obj) + offset); bytes = (unsigned char *) alloca (len); - read_memory (VALUE_ADDRESS (v), bytes, len); + read_memory (value_address (v), bytes, len); } else { @@ -2018,15 +2018,18 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr, if (obj != NULL) { + CORE_ADDR new_addr; + set_value_component_location (v, obj); - VALUE_ADDRESS (v) += value_offset (obj) + offset; + new_addr = value_address (obj) + offset; set_value_bitpos (v, bit_offset + value_bitpos (obj)); set_value_bitsize (v, bit_size); if (value_bitpos (v) >= HOST_CHAR_BIT) { - VALUE_ADDRESS (v) += 1; + new_addr++; set_value_bitpos (v, value_bitpos (v) - HOST_CHAR_BIT); } + set_value_address (v, new_addr); } else set_value_bitsize (v, bit_size); @@ -2218,7 +2221,7 @@ ada_value_assign (struct value *toval, struct value *fromval) int from_size; char *buffer = (char *) alloca (len); struct value *val; - CORE_ADDR to_addr = VALUE_ADDRESS (toval) + value_offset (toval); + CORE_ADDR to_addr = value_address (toval); if (TYPE_CODE (type) == TYPE_CODE_FLT) fromval = value_cast (type, fromval); @@ -2259,8 +2262,7 @@ value_assign_to_component (struct value *container, struct value *component, struct value *val) { LONGEST offset_in_container = - (LONGEST) (VALUE_ADDRESS (component) + value_offset (component) - - VALUE_ADDRESS (container) - value_offset (container)); + (LONGEST) (value_address (component) - value_address (container)); int bit_offset_in_container = value_bitpos (component) - value_bitpos (container); int bits; @@ -3788,7 +3790,7 @@ parse_old_style_renaming (struct type *type, /* Return an lvalue containing the value VAL. This is the identity on lvalues, and otherwise has the side-effect of pushing a copy of VAL on the stack, using and updating *SP as the stack pointer, and - returning an lvalue whose VALUE_ADDRESS points to the copy. */ + returning an lvalue whose value_address points to the copy. */ static struct value * ensure_lval (struct value *val, CORE_ADDR *sp) @@ -3802,12 +3804,12 @@ ensure_lval (struct value *val, CORE_ADDR *sp) indicated. */ if (gdbarch_inner_than (current_gdbarch, 1, 2)) { - /* Stack grows downward. Align SP and VALUE_ADDRESS (val) after + /* Stack grows downward. Align SP and value_address (val) after reserving sufficient space. */ *sp -= len; if (gdbarch_frame_align_p (current_gdbarch)) *sp = gdbarch_frame_align (current_gdbarch, *sp); - VALUE_ADDRESS (val) = *sp; + set_value_address (val, *sp); } else { @@ -3815,14 +3817,14 @@ ensure_lval (struct value *val, CORE_ADDR *sp) then again, re-align the frame. */ if (gdbarch_frame_align_p (current_gdbarch)) *sp = gdbarch_frame_align (current_gdbarch, *sp); - VALUE_ADDRESS (val) = *sp; + set_value_address (val, *sp); *sp += len; if (gdbarch_frame_align_p (current_gdbarch)) *sp = gdbarch_frame_align (current_gdbarch, *sp); } VALUE_LVAL (val) = lval_memory; - write_memory (VALUE_ADDRESS (val), value_contents_raw (val), len); + write_memory (value_address (val), value_contents_raw (val), len); } return val; @@ -3911,12 +3913,12 @@ make_array_descriptor (struct type *type, struct value *arr, CORE_ADDR *sp) bounds = ensure_lval (bounds, sp); modify_general_field (value_contents_writeable (descriptor), - VALUE_ADDRESS (ensure_lval (arr, sp)), + value_address (ensure_lval (arr, sp)), fat_pntr_data_bitpos (desc_type), fat_pntr_data_bitsize (desc_type)); modify_general_field (value_contents_writeable (descriptor), - VALUE_ADDRESS (bounds), + value_address (bounds), fat_pntr_bounds_bitpos (desc_type), fat_pntr_bounds_bitsize (desc_type)); @@ -6790,7 +6792,7 @@ variant_field_index (struct type *type) static struct type * empty_record (struct objfile *objfile) { - struct type *type = alloc_type (objfile); + struct type *type = alloc_type (objfile, NULL); TYPE_CODE (type) = TYPE_CODE_STRUCT; TYPE_NFIELDS (type) = 0; TYPE_FIELDS (type) = NULL; @@ -6847,7 +6849,7 @@ ada_template_to_fixed_record_type_1 (struct type *type, nfields++; } - rtype = alloc_type (TYPE_OBJFILE (type)); + rtype = alloc_type (TYPE_OBJFILE (type), NULL); TYPE_CODE (rtype) = TYPE_CODE_STRUCT; INIT_CPLUS_SPECIFIC (rtype); TYPE_NFIELDS (rtype) = nfields; @@ -7034,7 +7036,8 @@ template_to_static_fixed_type (struct type *type0) new_type = static_unwrap_type (field_type); if (type == type0 && new_type != field_type) { - TYPE_TARGET_TYPE (type0) = type = alloc_type (TYPE_OBJFILE (type0)); + TYPE_TARGET_TYPE (type0) = type = alloc_type (TYPE_OBJFILE (type0), + NULL); TYPE_CODE (type) = TYPE_CODE (type0); INIT_CPLUS_SPECIFIC (type); TYPE_NFIELDS (type) = nfields; @@ -7079,7 +7082,7 @@ to_record_with_fixed_variant_part (struct type *type, const gdb_byte *valaddr, else dval = dval0; - rtype = alloc_type (TYPE_OBJFILE (type)); + rtype = alloc_type (TYPE_OBJFILE (type), NULL); TYPE_CODE (rtype) = TYPE_CODE_STRUCT; INIT_CPLUS_SPECIFIC (rtype); TYPE_NFIELDS (rtype) = nfields; @@ -7251,7 +7254,7 @@ to_fixed_array_type (struct type *type0, struct value *dval, if (elt_type0 == elt_type) result = type0; else - result = create_array_type (alloc_type (TYPE_OBJFILE (type0)), + result = create_array_type (alloc_type (TYPE_OBJFILE (type0), NULL), elt_type, TYPE_INDEX_TYPE (type0)); } else @@ -7281,7 +7284,7 @@ to_fixed_array_type (struct type *type0, struct value *dval, struct type *range_type = to_fixed_range_type (TYPE_FIELD_NAME (index_type_desc, i), dval, TYPE_OBJFILE (type0)); - result = create_array_type (alloc_type (TYPE_OBJFILE (type0)), + result = create_array_type (alloc_type (TYPE_OBJFILE (type0), NULL), result, range_type); } if (!ignore_too_big && TYPE_LENGTH (result) > varsize_limit) @@ -7523,7 +7526,7 @@ static struct value * ada_to_fixed_value (struct value *val) { return ada_to_fixed_value_create (value_type (val), - VALUE_ADDRESS (val) + value_offset (val), + value_address (val), val); } @@ -7869,7 +7872,7 @@ unwrap_value (struct value *val) return coerce_unspec_val_to_type (val, ada_to_fixed_type (raw_real_type, 0, - VALUE_ADDRESS (val) + value_offset (val), + value_address (val), NULL, 1)); } } @@ -9546,7 +9549,7 @@ to_fixed_range_type (char *name, struct value *dval, struct objfile *objfile) if (L < INT_MIN || U > INT_MAX) return raw_type; else - return create_range_type (alloc_type (objfile), raw_type, + return create_range_type (alloc_type (objfile, NULL), raw_type, discrete_type_low_bound (raw_type), discrete_type_high_bound (raw_type)); } @@ -9611,7 +9614,7 @@ to_fixed_range_type (char *name, struct value *dval, struct objfile *objfile) if (objfile == NULL) objfile = TYPE_OBJFILE (base_type); - type = create_range_type (alloc_type (objfile), base_type, L, U); + type = create_range_type (alloc_type (objfile, NULL), base_type, L, U); TYPE_NAME (type) = name; return type; } @@ -11009,9 +11012,9 @@ ada_language_arch_info (struct gdbarch *gdbarch, /* Not really used, but needed in the ada_language_defn. */ static void -emit_char (int c, struct ui_file *stream, int quoter) +emit_char (int c, struct type *type, struct ui_file *stream, int quoter) { - ada_emit_char (c, stream, quoter, 1); + ada_emit_char (c, type, stream, quoter, 1); } static int diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h index c7cc62a..fac027b 100644 --- a/gdb/ada-lang.h +++ b/gdb/ada-lang.h @@ -257,12 +257,12 @@ extern int ada_value_print (struct value *, struct ui_file *, /* Defined in ada-lang.c */ -extern void ada_emit_char (int, struct ui_file *, int, int); +extern void ada_emit_char (int, struct type *, struct ui_file *, int, int); -extern void ada_printchar (int, struct ui_file *); +extern void ada_printchar (int, struct type *, struct ui_file *); -extern void ada_printstr (struct ui_file *, const gdb_byte *, - unsigned int, int, int, +extern void ada_printstr (struct ui_file *, struct type *, const gdb_byte *, + unsigned int, int, const struct value_print_options *); struct value *ada_convert_actual (struct value *actual, diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c index 61ed06e..8b1639e 100644 --- a/gdb/ada-tasks.c +++ b/gdb/ada-tasks.c @@ -293,7 +293,7 @@ read_fat_string_value (char *dest, struct value *val, int max_len) /* Extract LEN characters from the fat string. */ array_val = value_ind (value_field (val, array_fieldno)); - read_memory (VALUE_ADDRESS (array_val), dest, len); + read_memory (value_address (array_val), dest, len); /* Add the NUL character to close the string. */ dest[len] = '\0'; diff --git a/gdb/ada-typeprint.c b/gdb/ada-typeprint.c index f00824a..ef665c4 100644 --- a/gdb/ada-typeprint.c +++ b/gdb/ada-typeprint.c @@ -357,16 +357,17 @@ print_array_type (struct type *type, struct ui_file *stream, int show, bitsize = 0; fprintf_filtered (stream, "array ("); + if (type == NULL) + { + fprintf_filtered (stream, _("")); + return; + } + n_indices = -1; if (show < 0) fprintf_filtered (stream, "..."); else { - if (type == NULL) - { - fprintf_filtered (stream, _("")); - return; - } if (ada_is_simple_array_type (type)) { struct type *range_desc_type = diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c index 9647971..cfa94a2 100644 --- a/gdb/ada-valprint.c +++ b/gdb/ada-valprint.c @@ -269,7 +269,8 @@ printable_val_type (struct type *type, const gdb_byte *valaddr) (1 or 2) of the character. */ void -ada_emit_char (int c, struct ui_file *stream, int quoter, int type_len) +ada_emit_char (int c, struct type *type, struct ui_file *stream, + int quoter, int type_len) { if (type_len != 2) type_len = 1; @@ -366,10 +367,10 @@ ada_print_floating (const gdb_byte *valaddr, struct type *type, } void -ada_printchar (int c, struct ui_file *stream) +ada_printchar (int c, struct type *type, struct ui_file *stream) { fputs_filtered ("'", stream); - ada_emit_char (c, stream, '\'', 1); + ada_emit_char (c, type, stream, '\'', 1); fputs_filtered ("'", stream); } @@ -411,7 +412,7 @@ ada_print_scalar (struct type *type, LONGEST val, struct ui_file *stream) break; case TYPE_CODE_CHAR: - LA_PRINT_CHAR ((unsigned char) val, stream); + LA_PRINT_CHAR ((unsigned char) val, type, stream); break; case TYPE_CODE_BOOL: @@ -454,7 +455,7 @@ ada_print_scalar (struct type *type, LONGEST val, struct ui_file *stream) */ static void -printstr (struct ui_file *stream, const gdb_byte *string, +printstr (struct ui_file *stream, struct type *elttype, const gdb_byte *string, unsigned int length, int force_ellipses, int type_len, const struct value_print_options *options) { @@ -506,7 +507,7 @@ printstr (struct ui_file *stream, const gdb_byte *string, in_quotes = 0; } fputs_filtered ("'", stream); - ada_emit_char (char_at (string, i, type_len), stream, '\'', + ada_emit_char (char_at (string, i, type_len), elttype, stream, '\'', type_len); fputs_filtered ("'", stream); fprintf_filtered (stream, _(" "), reps); @@ -524,7 +525,7 @@ printstr (struct ui_file *stream, const gdb_byte *string, fputs_filtered ("\"", stream); in_quotes = 1; } - ada_emit_char (char_at (string, i, type_len), stream, '"', + ada_emit_char (char_at (string, i, type_len), elttype, stream, '"', type_len); things_printed += 1; } @@ -544,11 +545,12 @@ printstr (struct ui_file *stream, const gdb_byte *string, } void -ada_printstr (struct ui_file *stream, const gdb_byte *string, - unsigned int length, int width, int force_ellipses, +ada_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string, + unsigned int length, int force_ellipses, const struct value_print_options *options) { - printstr (stream, string, length, force_ellipses, width, options); + printstr (stream, type, string, length, force_ellipses, TYPE_LENGTH (type), + options); } @@ -637,7 +639,7 @@ ada_val_print_array (struct type *type, const gdb_byte *valaddr, len = temp_len; } - printstr (stream, valaddr, len, 0, eltlen, options); + printstr (stream, elttype, valaddr, len, 0, eltlen, options); result = len; } else @@ -688,7 +690,7 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr0, } else retn = ada_val_print_1 (value_type (val), value_contents (val), 0, - VALUE_ADDRESS (val), stream, recurse, options); + value_address (val), stream, recurse, options); value_free_to_mark (mark); return retn; } @@ -817,7 +819,7 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr0, { fputs_filtered (" ", stream); ada_printchar ((unsigned char) unpack_long (type, valaddr), - stream); + type, stream); } } return 0; @@ -904,7 +906,7 @@ ada_val_print_1 (struct type *type, const gdb_byte *valaddr0, deref_val_int)); val_print (value_type (deref_val), value_contents (deref_val), 0, - VALUE_ADDRESS (deref_val), stream, recurse + 1, + value_address (deref_val), stream, recurse + 1, options, current_language); } else @@ -944,7 +946,7 @@ ada_value_print (struct value *val0, struct ui_file *stream, const struct value_print_options *options) { const gdb_byte *valaddr = value_contents (val0); - CORE_ADDR address = VALUE_ADDRESS (val0) + value_offset (val0); + CORE_ADDR address = value_address (val0); struct type *type = ada_to_fixed_type (value_type (val0), valaddr, address, NULL, 1); struct value *val = diff --git a/gdb/auxv.c b/gdb/auxv.c index 5007cd0..241a6ac 100644 --- a/gdb/auxv.c +++ b/gdb/auxv.c @@ -247,7 +247,8 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops) get_user_print_options (&opts); if (opts.addressprint) fprintf_filtered (file, "0x%s", paddr_nz (val)); - val_print_string (val, -1, 1, file, &opts); + val_print_string (builtin_type (target_gdbarch)->builtin_char, + val, -1, file, &opts); fprintf_filtered (file, "\n"); } break; diff --git a/gdb/block.c b/gdb/block.c index 8f0140c..d451769 100644 --- a/gdb/block.c +++ b/gdb/block.c @@ -207,24 +207,16 @@ block_set_scope (struct block *block, const char *scope, } /* This returns the first using directives associated to BLOCK, if - any. */ - -/* FIXME: carlton/2003-04-23: This uses the fact that we currently - only have using directives in static blocks, because we only - generate using directives from anonymous namespaces. Eventually, - when we support using directives everywhere, we'll want to replace - this by some iterator functions. */ + any. Each BLOCK_NAMESPACE()->USING already contains all the namespaces + imported at that code point - even those from its parent blocks. */ struct using_direct * block_using (const struct block *block) { - const struct block *static_block = block_static_block (block); - - if (static_block == NULL - || BLOCK_NAMESPACE (static_block) == NULL) + if (block == NULL || BLOCK_NAMESPACE (block) == NULL) return NULL; else - return BLOCK_NAMESPACE (static_block)->using; + return BLOCK_NAMESPACE (block)->using; } /* Set BLOCK's using member to USING; if needed, allocate memory via diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index b23b294..38a17a1 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -191,6 +191,8 @@ static int is_hardware_watchpoint (struct breakpoint *bpt); static void insert_breakpoint_locations (void); +static int syscall_catchpoint_p (struct breakpoint *b); + static const char * bpdisp_text (enum bpdisp disp) { @@ -341,6 +343,18 @@ set_breakpoint_count (int num) value_from_longest (builtin_type_int32, (LONGEST) num)); } +/* Used in run_command to reset syscall catchpoints fields. */ + +void +clear_syscall_catchpoints_info (void) +{ + struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (syscall_catchpoint_p (b)) + b->syscall_number = UNKNOWN_SYSCALL; +} + /* Used in run_command to zero the hit count when a new run starts. */ void @@ -523,6 +537,53 @@ get_number_or_range (char **pp) +/* Set break condition of breakpoint B to EXP. */ + +void +set_breakpoint_condition (struct breakpoint *b, char *exp, int from_tty) +{ + struct bp_location *loc = b->loc; + + for (; loc; loc = loc->next) + { + if (loc->cond) + { + xfree (loc->cond); + loc->cond = 0; + } + } + + if (b->cond_string != NULL) + xfree (b->cond_string); + + if (*exp == 0) + { + b->cond_string = NULL; + if (from_tty) + printf_filtered (_("Breakpoint %d now unconditional.\n"), b->number); + } + else + { + char *arg = exp; + + /* I don't know if it matters whether this is the string the user + typed in or the decompiled expression. */ + b->cond_string = savestring (arg, strlen (arg)); + b->condition_not_parsed = 0; + for (loc = b->loc; loc; loc = loc->next) + { + arg = exp; + loc->cond = + parse_exp_1 (&arg, block_for_pc (loc->address), 0); + if (*arg) + error (_("Junk at end of expression")); + } + } + + breakpoints_changed (); + observer_notify_breakpoint_modified (b->number); +} + /* condition N EXP -- set break condition of breakpoint N to EXP. */ static void @@ -543,42 +604,7 @@ condition_command (char *arg, int from_tty) ALL_BREAKPOINTS (b) if (b->number == bnum) { - struct bp_location *loc = b->loc; - for (; loc; loc = loc->next) - { - if (loc->cond) - { - xfree (loc->cond); - loc->cond = 0; - } - } - if (b->cond_string != NULL) - xfree (b->cond_string); - - if (*p == 0) - { - b->cond_string = NULL; - if (from_tty) - printf_filtered (_("Breakpoint %d now unconditional.\n"), bnum); - } - else - { - arg = p; - /* I don't know if it matters whether this is the string the user - typed in or the decompiled expression. */ - b->cond_string = savestring (arg, strlen (arg)); - b->condition_not_parsed = 0; - for (loc = b->loc; loc; loc = loc->next) - { - arg = p; - loc->cond = - parse_exp_1 (&arg, block_for_pc (loc->address), 0); - if (*arg) - error (_("Junk at end of expression")); - } - } - breakpoints_changed (); - observer_notify_breakpoint_modified (b->number); + set_breakpoint_condition (b, p, from_tty); return; } @@ -961,7 +987,7 @@ update_watchpoint (struct breakpoint *b, int reparse) int len, type; struct bp_location *loc, **tmp; - addr = VALUE_ADDRESS (v) + value_offset (v); + addr = value_address (v); len = TYPE_LENGTH (value_type (v)); type = hw_write; if (b->type == bp_read_watchpoint) @@ -3948,8 +3974,8 @@ check_duplicates_for (CORE_ADDR address, struct obj_section *section) } /* If we found a permanent breakpoint at this address, go over the - list again and declare all the other breakpoints there to be the - duplicates. */ + list again and declare all the other breakpoints there (except + other permanent breakpoints) to be the duplicates. */ if (perm_bp) { perm_bp->duplicate = 0; @@ -3963,7 +3989,8 @@ check_duplicates_for (CORE_ADDR address, struct obj_section *section) ALL_BP_LOCATIONS (b) if (b != perm_bp) { - if (b->owner->enable_state != bp_disabled + if (b->owner->enable_state != bp_permanent + && b->owner->enable_state != bp_disabled && b->owner->enable_state != bp_call_disabled && b->enabled && !b->shlib_disabled && b->address == address /* address / overlay match */ @@ -4134,6 +4161,8 @@ set_raw_breakpoint_without_location (enum bptype bptype) b->frame_id = null_frame_id; b->forked_inferior_pid = null_ptid; b->exec_pathname = NULL; + b->syscalls_to_be_caught = NULL; + b->syscall_number = UNKNOWN_SYSCALL; b->ops = NULL; b->condition_not_parsed = 0; @@ -4660,7 +4689,241 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops = print_mention_catch_vfork }; -/* Create a new breakpoint of the bp_catchpoint kind and return it. +/* We keep a count of the number of times the user has requested a + particular syscall to be tracked, and pass this information to the + target. This lets capable targets implement filtering directly. */ + +/* Number of times that "any" syscall is requested. */ +static int any_syscall_count; + +/* Count of each system call. */ +static int *syscalls_counts; + +/* Number of system entries in SYSCALLS_COUNTS. */ +static int syscalls_size; + +/* This counts all syscall catch requests, so we can readily determine + if any catching is necessary. */ +static int total_syscalls_count; + +/* Implement the "insert" breakpoint_ops method for syscall + catchpoints. */ + +static void +insert_catch_syscall (struct breakpoint *b) +{ + ++total_syscalls_count; + if (!b->syscalls_to_be_caught) + ++any_syscall_count; + else + { + struct syscall_filter *iter; + for (iter = b->syscalls_to_be_caught; iter; iter = iter->next) + { + if (iter->syscall >= syscalls_size) + { + syscalls_counts = xrealloc (syscalls_counts, + (iter->syscall + 1) * sizeof (int)); + memset (&syscalls_counts[syscalls_size], 0, + (iter->syscall + 1 - syscalls_size) * sizeof (int)); + } + ++syscalls_counts[iter->syscall]; + } + } + + target_set_syscall_catchpoint (PIDGET (inferior_ptid), + total_syscalls_count != 0, + any_syscall_count, + syscalls_size, + syscalls_counts); +} + +/* Implement the "remove" breakpoint_ops method for syscall + catchpoints. */ + +static int +remove_catch_syscall (struct breakpoint *b) +{ + --total_syscalls_count; + if (!b->syscalls_to_be_caught) + --any_syscall_count; + else + { + struct syscall_filter *iter; + for (iter = b->syscalls_to_be_caught; iter; iter = iter->next) + { + if (iter->syscall >= syscalls_size) + { + /* Shouldn't happen. */ + continue; + } + --syscalls_counts[iter->syscall]; + } + } + + return target_set_syscall_catchpoint (PIDGET (inferior_ptid), + total_syscalls_count != 0, + any_syscall_count, + syscalls_size, + syscalls_counts); +} + +/* Implement the "breakpoint_hit" breakpoint_ops method for syscall + catchpoints. */ + +static int +breakpoint_hit_catch_syscall (struct breakpoint *b) +{ + /* We must check if we are catching specific syscalls in this breakpoint. + If we are, then we must guarantee that the called syscall is the same + syscall we are catching. */ + int syscall_number = 0; + + if (!inferior_has_called_syscall (inferior_ptid, &syscall_number)) + return 0; + + /* Now, checking if the syscall is the same. */ + if (b->syscalls_to_be_caught) + { + struct syscall_filter *iter; + for (iter = b->syscalls_to_be_caught; iter; iter = iter->next) + if (syscall_number == iter->syscall) + break; + /* Not the same. */ + if (!iter) + return 0; + } + + /* It's the same syscall. We can update the breakpoint struct + with the correct information. */ + b->syscall_number = syscall_number; + + return 1; +} + +/* Implement the "print_it" breakpoint_ops method for syscall + catchpoints. */ + +static enum print_stop_action +print_it_catch_syscall (struct breakpoint *b) +{ + /* These are needed because we want to know in which state a + syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY + or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we + must print "called syscall" or "returned from syscall". */ + ptid_t ptid; + struct target_waitstatus last; + struct syscall s; + struct cleanup *old_chain; + char *syscall_id; + + gdbarch_get_syscall_by_number (current_gdbarch, b->syscall_number, &s); + + get_last_target_status (&ptid, &last); + + annotate_catchpoint (b->number); + + if (s.name == NULL) + syscall_id = xstrprintf ("%d", b->syscall_number); + else + syscall_id = xstrprintf ("'%s'", s.name); + + old_chain = make_cleanup (xfree, syscall_id); + + if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY) + printf_filtered (_("\nCatchpoint %d (call to syscall %s), "), + b->number, syscall_id); + else + printf_filtered (_("\nCatchpoint %d (returned from syscall %s), "), + b->number, syscall_id); + + do_cleanups (old_chain); + + return PRINT_SRC_AND_LOC; +} + +/* Implement the "print_one" breakpoint_ops method for syscall + catchpoints. */ + +static void +print_one_catch_syscall (struct breakpoint *b, CORE_ADDR *last_addr) +{ + struct value_print_options opts; + struct syscall s; + + gdbarch_get_syscall_by_number (current_gdbarch, b->syscall_number, &s); + + get_user_print_options (&opts); + /* Field 4, the address, is omitted (which makes the columns + not line up too nicely with the headers, but the effect + is relatively readable). */ + if (opts.addressprint) + ui_out_field_skip (uiout, "addr"); + annotate_field (5); + ui_out_text (uiout, "syscall \""); + if (b->syscall_number != UNKNOWN_SYSCALL) + { + if (s.name) + ui_out_field_string (uiout, "what", s.name); + else + ui_out_field_int (uiout, "what", b->syscall_number); + } + else + ui_out_field_string (uiout, "what", ""); + ui_out_text (uiout, "\" "); +} + +/* Implement the "print_mention" breakpoint_ops method for syscall + catchpoints. */ + +static void +print_mention_catch_syscall (struct breakpoint *b) +{ + if (b->syscalls_to_be_caught) + { + struct syscall_filter *iter; + printf_filtered (_("Catchpoint %d (syscall(s)"), b->number); + for (iter = b->syscalls_to_be_caught; iter; iter = iter->next) + { + struct syscall s; + gdbarch_get_syscall_by_number (current_gdbarch, iter->syscall, &s); + + if (s.name) + printf_filtered (" '%s'", s.name); + else + printf_filtered (" %d", iter->syscall); + } + printf_filtered (")"); + } + else + printf_filtered (_("Catchpoint %d (any syscall)"), + b->number); +} + +/* The breakpoint_ops structure to be used in syscall catchpoints. */ + +static struct breakpoint_ops catch_syscall_breakpoint_ops = +{ + insert_catch_syscall, + remove_catch_syscall, + breakpoint_hit_catch_syscall, + print_it_catch_syscall, + print_one_catch_syscall, + print_mention_catch_syscall +}; + +/* Returns non-zero if 'b' is a syscall catchpoint. */ + +static int +syscall_catchpoint_p (struct breakpoint *b) +{ + return (b->ops == &catch_syscall_breakpoint_ops); +} + +/* Create a new breakpoint of the bp_catchpoint kind and return it, + but does NOT mention it nor update the global location list. + This is useful if you need to fill more fields in the + struct breakpoint before calling mention. If TEMPFLAG is non-zero, then make the breakpoint temporary. If COND_STRING is not NULL, then store it in the breakpoint. @@ -4668,16 +4931,13 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops = to the catchpoint. */ static struct breakpoint * -create_catchpoint (int tempflag, char *cond_string, - struct breakpoint_ops *ops) +create_catchpoint_without_mention (int tempflag, char *cond_string, + struct breakpoint_ops *ops) { struct symtab_and_line sal; struct breakpoint *b; init_sal (&sal); - sal.pc = 0; - sal.symtab = NULL; - sal.line = 0; b = set_raw_breakpoint (sal, bp_catchpoint); set_breakpoint_count (breakpoint_count + 1); @@ -4691,6 +4951,23 @@ create_catchpoint (int tempflag, char *cond_string, b->disposition = tempflag ? disp_del : disp_donttouch; b->ops = ops; + return b; +} + +/* Create a new breakpoint of the bp_catchpoint kind and return it. + + If TEMPFLAG is non-zero, then make the breakpoint temporary. + If COND_STRING is not NULL, then store it in the breakpoint. + OPS, if not NULL, is the breakpoint_ops structure associated + to the catchpoint. */ + +static struct breakpoint * +create_catchpoint (int tempflag, char *cond_string, + struct breakpoint_ops *ops) +{ + struct breakpoint *b = + create_catchpoint_without_mention (tempflag, cond_string, ops); + mention (b); update_global_location_list (1); @@ -4775,6 +5052,23 @@ static struct breakpoint_ops catch_exec_breakpoint_ops = print_mention_catch_exec }; +static void +create_syscall_event_catchpoint (int tempflag, struct syscall_filter *filter, + struct breakpoint_ops *ops) +{ + struct breakpoint *b = + create_catchpoint_without_mention (tempflag, NULL, ops); + + b->syscalls_to_be_caught = filter; + /* We still don't know the syscall that will be caught :-). */ + b->syscall_number = UNKNOWN_SYSCALL; + + /* Now, we have to mention the breakpoint and update the global + location list. */ + mention (b); + update_global_location_list (1); +} + static int hw_breakpoint_used_count (void) { @@ -5310,8 +5604,6 @@ create_breakpoints (struct symtabs_and_lines sals, char **addr_string, cond_string, type, disposition, thread, ignore_count, ops, from_tty, enabled); } - - update_global_location_list (1); } /* Parse ARG which is assumed to be a SAL specification possibly @@ -5637,7 +5929,6 @@ break_command_really (char *arg, char *cond_string, int thread, b->ops = ops; b->enable_state = enabled ? bp_enabled : bp_disabled; - update_global_location_list (1); mention (b); } @@ -5649,6 +5940,11 @@ break_command_really (char *arg, char *cond_string, int thread, discard_cleanups (breakpoint_chain); /* But cleanup everything else. */ do_cleanups (old_chain); + + /* Have already BREAKPOINT_CHAIN discarded as we may get an exception while + inserting the breakpoints which would double-free the resources both by + BREAKPOINT_CHAIN now and during DELETE_BREAKPOINT in the future. */ + update_global_location_list (1); } /* Set a breakpoint. @@ -6131,7 +6427,7 @@ can_use_hardware_watchpoint (struct value *v) || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) { - CORE_ADDR vaddr = VALUE_ADDRESS (v) + value_offset (v); + CORE_ADDR vaddr = value_address (v); int len = TYPE_LENGTH (value_type (v)); if (!TARGET_REGION_OK_FOR_HW_WATCHPOINT (vaddr, len)) @@ -6668,6 +6964,122 @@ catch_ada_exception_command (char *arg, int from_tty, from_tty); } +/* Cleanup function for a syscall filter list. */ +static void +clean_up_filters (void *arg) +{ + struct syscall_filter *iter = *(struct syscall_filter **) arg; + while (iter) + { + struct syscall_filter *next = iter->next; + xfree (iter); + iter = next; + } +} + +/* Splits the argument using space as delimiter. Returns an xmalloc'd + filter list, or NULL if no filtering is required. */ +static struct syscall_filter * +catch_syscall_split_args (char *arg) +{ + struct syscall_filter *result = NULL; + struct cleanup *cleanup = make_cleanup (clean_up_filters, &result); + + while (*arg != '\0') + { + int i, syscall_number; + char *endptr; + char cur_name[128]; + struct syscall_filter *new_filter; + struct syscall s; + + /* Skip whitespace. */ + while (isspace (*arg)) + arg++; + + for (i = 0; arg[i] && !isspace (arg[i]); ++i) + cur_name[i] = arg[i]; + cur_name[i] = '\0'; + arg += i; + + /* Check if the user provided a syscall name or a number. */ + syscall_number = (int) strtol (cur_name, &endptr, 10); + if (*endptr == '\0') + { + gdbarch_get_syscall_by_number (current_gdbarch, + syscall_number, &s); + + if (s.name == NULL) + /* We can issue just a warning, but still create the catchpoint. + This is because, even not knowing the syscall name that + this number represents, we can still try to catch the syscall + number. */ + warning (_("The number '%d' does not represent a known syscall."), + syscall_number); + } + else + { + /* We have a name. Let's check if it's valid and convert it + to a number. */ + gdbarch_get_syscall_by_name (current_gdbarch, cur_name, &s); + + if (s.number == UNKNOWN_SYSCALL) + /* Here we have to issue an error instead of a warning, because + GDB cannot do anything useful if there's no syscall number to + be caught. */ + error (_("Unknown syscall name '%s'."), cur_name); + } + + /* Ok, it's valid. */ + new_filter = XNEW (struct syscall_filter); + new_filter->syscall = s.number; + new_filter->next = result; + result = new_filter; + } + + discard_cleanups (cleanup); + return result; +} + +/* Implement the "catch syscall" command. */ + +static void +catch_syscall_command_1 (char *arg, int from_tty, struct cmd_list_element *command) +{ + int tempflag; + struct syscall_filter *filter; + struct syscall s; + + /* Checking if the feature if supported. */ + if (gdbarch_get_syscall_number_p (current_gdbarch) == 0) + error (_("The feature 'catch syscall' is not supported on \ +this architeture yet.")); + + tempflag = get_cmd_context (command) == CATCH_TEMPORARY; + + ep_skip_leading_whitespace (&arg); + + /* We need to do this first "dummy" translation in order + to get the syscall XML file loaded or, most important, + to display a warning to the user if there's no XML file + for his/her architecture. */ + gdbarch_get_syscall_by_number (current_gdbarch, 0, &s); + + /* The allowed syntax is: + catch syscall + catch syscall [ ... ] + + Let's check if there's a syscall name. */ + + if (arg != NULL) + filter = catch_syscall_split_args (arg); + else + filter = NULL; + + create_syscall_event_catchpoint (tempflag, filter, + &catch_syscall_breakpoint_ops); +} + /* Implement the "catch assert" command. */ static void @@ -7134,6 +7546,7 @@ delete_breakpoint (struct breakpoint *bpt) xfree (bpt->source_file); if (bpt->exec_pathname != NULL) xfree (bpt->exec_pathname); + clean_up_filters (&bpt->syscalls_to_be_caught); /* Be sure no bpstat's are pointing at it after it's been freed. */ /* FIXME, how can we find all bpstat's? @@ -8041,6 +8454,56 @@ single_step_breakpoint_inserted_here_p (CORE_ADDR pc) return 0; } +/* Returns 0 if 'bp' is NOT a syscall catchpoint, + non-zero otherwise. */ +static int +is_syscall_catchpoint_enabled (struct breakpoint *bp) +{ + if (syscall_catchpoint_p (bp) + && bp->enable_state != bp_disabled + && bp->enable_state != bp_call_disabled) + return 1; + else + return 0; +} + +int +catch_syscall_enabled (void) +{ + return total_syscalls_count != 0; +} + +int +catching_syscall_number (int syscall_number) +{ + struct breakpoint *bp; + + ALL_BREAKPOINTS (bp) + if (is_syscall_catchpoint_enabled (bp)) + { + if (bp->syscalls_to_be_caught) + { + struct syscall_filter *iter; + for (iter = bp->syscalls_to_be_caught; iter; iter = iter->next) + if (syscall_number == iter->syscall) + return 1; + } + else + return 1; + } + + return 0; +} + +/* Complete syscall names. Used by "catch syscall". */ +static char ** +catch_syscall_completer (struct cmd_list_element *self, char *text, char *word) +{ + const char **list = + gdbarch_get_syscall_names (current_gdbarch); + return (list == NULL) ? NULL : complete_on_enum (list, text, word); +} + /* This help string is used for the break, hbreak, tbreak and thbreak commands. It is defined as a macro to prevent duplication. @@ -8073,6 +8536,8 @@ static void add_catch_command (char *name, char *docstring, void (*sfunc) (char *args, int from_tty, struct cmd_list_element *command), + char **(*completion_function) (struct cmd_list_element *self, + char *text, char *word), void *user_data_catch, void *user_data_tcatch) { @@ -8082,11 +8547,13 @@ add_catch_command (char *name, char *docstring, &catch_cmdlist); set_cmd_sfunc (command, sfunc); set_cmd_context (command, user_data_catch); + set_cmd_completer (command, completion_function); command = add_cmd (name, class_breakpoint, NULL, docstring, &tcatch_cmdlist); set_cmd_sfunc (command, sfunc); set_cmd_context (command, user_data_tcatch); + set_cmd_completer (command, completion_function); } void @@ -8361,36 +8828,50 @@ Set temporary catchpoints to catch events."), Catch an exception, when caught.\n\ With an argument, catch only exceptions with the given name."), catch_catch_command, + NULL, CATCH_PERMANENT, CATCH_TEMPORARY); add_catch_command ("throw", _("\ Catch an exception, when thrown.\n\ With an argument, catch only exceptions with the given name."), catch_throw_command, + NULL, CATCH_PERMANENT, CATCH_TEMPORARY); add_catch_command ("fork", _("Catch calls to fork."), catch_fork_command_1, + NULL, (void *) (uintptr_t) catch_fork_permanent, (void *) (uintptr_t) catch_fork_temporary); add_catch_command ("vfork", _("Catch calls to vfork."), catch_fork_command_1, + NULL, (void *) (uintptr_t) catch_vfork_permanent, (void *) (uintptr_t) catch_vfork_temporary); add_catch_command ("exec", _("Catch calls to exec."), catch_exec_command_1, + NULL, CATCH_PERMANENT, CATCH_TEMPORARY); + add_catch_command ("syscall", _("\ +Catch system calls.\n\ +With an argument, catch only that syscall."), + catch_syscall_command_1, + catch_syscall_completer, + CATCH_PERMANENT, + CATCH_TEMPORARY); add_catch_command ("exception", _("\ Catch Ada exceptions, when raised.\n\ With an argument, catch only exceptions with the given name."), catch_ada_exception_command, + NULL, CATCH_PERMANENT, CATCH_TEMPORARY); add_catch_command ("assert", _("\ Catch failed Ada assertions, when raised.\n\ With an argument, catch only exceptions with the given name."), catch_assert_command, + NULL, CATCH_PERMANENT, CATCH_TEMPORARY); diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 94287de..8552e1b 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -33,7 +33,8 @@ struct block; #define BREAKPOINT_MAX 16 -/* Type of breakpoint. */ + +/* Type of breakpoint. */ /* FIXME In the future, we should fold all other breakpoint-like things into here. This includes: @@ -337,6 +338,17 @@ enum watchpoint_triggered watch_triggered_yes }; +/* A syscall filter is represented as a linked list of syscall + numbers. */ +struct syscall_filter +{ + /* The system call to accept. */ + int syscall; + + /* The next filter. */ + struct syscall_filter *next; +}; + typedef struct bp_location *bp_location_p; DEF_VEC_P(bp_location_p); @@ -442,6 +454,20 @@ struct breakpoint triggered. */ char *exec_pathname; + /* Syscall number used for the 'catch syscall' feature. + If no syscall has been called, its value is UNKNOWN_SYSCALL. + Otherwise, it holds the system call number in the target. + + This field is only valid immediately after this catchpoint has + triggered. */ + int syscall_number; + + /* Syscall numbers used for the 'catch syscall' feature. + If no syscall has been specified for filtering, its value is NULL. + Otherwise, it holds a list of all syscalls to be caught. + The list elements are allocated with xmalloc. */ + struct syscall_filter *syscalls_to_be_caught; + /* Methods associated with this breakpoint. */ struct breakpoint_ops *ops; @@ -783,6 +809,8 @@ extern void enable_watchpoints_after_interactive_call_stop (void); extern enum command_control_type commands_from_control_command (char *arg, struct command_line *cmd); +extern void clear_syscall_catchpoints_info (void); + extern void clear_breakpoint_hit_counts (void); extern int get_number (char **); @@ -857,7 +885,19 @@ extern int breakpoints_always_inserted_mode (void); in our opinion won't ever trigger. */ extern void breakpoint_retire_moribund (void); +/* Checks if we are catching syscalls or not. + Returns 0 if not, greater than 0 if we are. */ +extern int catch_syscall_enabled (void); + +/* Checks if we are catching syscalls with the specific + syscall_number. Used for "filtering" the catchpoints. + Returns 0 if not, greater than 0 if we are. */ +extern int catching_syscall_number (int syscall_number); + /* Tell a breakpoint to be quiet. */ extern void make_breakpoint_silent (struct breakpoint *); +/* Set break condition of breakpoint B to EXP. */ +extern void set_breakpoint_condition (struct breakpoint *b, char *exp, int from_tty); + #endif /* !defined (BREAKPOINT_H) */ diff --git a/gdb/buildsym.c b/gdb/buildsym.c index 55ace15..2722daa 100644 --- a/gdb/buildsym.c +++ b/gdb/buildsym.c @@ -384,6 +384,8 @@ finish_block (struct symbol *symbol, struct pending **listhead, opblock = pblock; } + block_set_using (block, using_directives, &objfile->objfile_obstack); + record_pending_block (objfile, block, opblock); return block; @@ -815,10 +817,6 @@ start_symtab (char *name, char *dirname, CORE_ADDR start_addr) /* We shouldn't have any address map at this point. */ gdb_assert (! pending_addrmap); - /* Set up support for C++ namespace support, in case we need it. */ - - cp_initialize_namespace (); - /* Initialize the list of sub source files with one entry for this file (the top-level source file). */ @@ -1015,8 +1013,6 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section) finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr, objfile); blockvector = make_blockvector (objfile); - cp_finalize_namespace (BLOCKVECTOR_BLOCK (blockvector, STATIC_BLOCK), - &objfile->objfile_obstack); } /* Read the line table if it has to be read separately. */ @@ -1202,10 +1198,12 @@ push_context (int desc, CORE_ADDR valu) new->params = param_symbols; new->old_blocks = pending_blocks; new->start_addr = valu; + new->using_directives = using_directives; new->name = NULL; local_symbols = NULL; param_symbols = NULL; + using_directives = NULL; return new; } diff --git a/gdb/buildsym.h b/gdb/buildsym.h index bf23ecc..f542aca 100644 --- a/gdb/buildsym.h +++ b/gdb/buildsym.h @@ -125,6 +125,10 @@ EXTERN struct pending *local_symbols; EXTERN struct pending *param_symbols; +/* using directives local to lexical context */ + +EXTERN struct using_direct *using_directives; + /* Stack representing unclosed lexical contexts (that will become blocks, eventually). */ @@ -138,6 +142,10 @@ struct context_stack struct pending *params; + /* Pending using directives at the time we entered */ + + struct using_direct *using_directives; + /* Pointer into blocklist as of entry */ struct pending_block *old_blocks; diff --git a/gdb/c-exp.y b/gdb/c-exp.y index d4bbbcc..107452a 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -119,6 +119,8 @@ static int yylex (void); void yyerror (char *); +/* Cleanup for 'nonempty_typelist' */ +static struct cleanup *typelist_cleanup; %} /* Although the yacc "value" of an expression is not used, @@ -143,6 +145,7 @@ void yyerror (char *); struct symbol *sym; struct type *tval; struct stoken sval; + struct typed_stoken tsval; struct ttype tsym; struct symtoken ssym; int voidval; @@ -150,6 +153,7 @@ void yyerror (char *); enum exp_opcode opcode; struct internalvar *ivar; + struct stoken_vector svec; struct type **tvec; int *ivec; } @@ -182,11 +186,13 @@ static int parse_number (char *, int, int, YYSTYPE *); Contexts where this distinction is not important can use the nonterminal "name", which matches either NAME or TYPENAME. */ -%token STRING +%token STRING +%token CHAR %token NAME /* BLOCKNAME defined below to give it higher precedence. */ %token COMPLETE %token TYPENAME -%type name string_exp +%type name +%type string_exp %type name_not_typename %type typename @@ -399,6 +405,38 @@ arglist : arglist ',' exp %prec ABOVE_COMMA { arglist_len++; } ; +exp : exp '(' nonempty_typelist ')' + { int i; + /* What to do about freeing memory if + there is an error during parsing? */ + write_exp_elt_opcode (TYPE_INSTANCE); + write_exp_elt_longcst ((LONGEST) $3[0]); + for (i = 0; i < $3[0]; ++i) + write_exp_elt_type ($3[i + 1]); + write_exp_elt_longcst((LONGEST) $3[0]); + write_exp_elt_opcode (TYPE_INSTANCE); + do_cleanups (typelist_cleanup); + } + ; + +/* +exp : BLOCKNAME '(' nonempty_typelist ')' + { int i; + write_exp_elt_opcode (TYPE_INSTANCE_LOOKUP); + write_exp_elt_sym ($1.sym); + write_exp_elt_opcode (TYPE_INSTANCE_LOOKUP); + + write_exp_elt_opcode (TYPE_INSTANCE); + write_exp_elt_longcst ((LONGEST) $3[0]); + for (i = 0; i < $3[0]; ++i) + write_exp_elt_type ($3[i + 1]); + write_exp_elt_longcst((LONGEST) $3[0]); + write_exp_elt_opcode (TYPE_INSTANCE); + do_cleanups (typelist_cleanup); + } + ; +*/ + rcurly : '}' { $$ = end_arglist () - 1; } ; @@ -524,6 +562,15 @@ exp : INT write_exp_elt_opcode (OP_LONG); } ; +exp : CHAR + { + struct stoken_vector vec; + vec.len = 1; + vec.tokens = &$1; + write_exp_string_vector ($1.type, &vec); + } + ; + exp : NAME_OR_INT { YYSTYPE val; parse_number ($1.stoken.ptr, $1.stoken.length, 0, &val); @@ -572,48 +619,64 @@ string_exp: string. Note that we follow the NUL-termination convention of the lexer. */ - $$.length = $1.length; - $$.ptr = malloc ($1.length + 1); - memcpy ($$.ptr, $1.ptr, $1.length + 1); + struct typed_stoken *vec = XNEW (struct typed_stoken); + $$.len = 1; + $$.tokens = vec; + + vec->type = $1.type; + vec->length = $1.length; + vec->ptr = malloc ($1.length + 1); + memcpy (vec->ptr, $1.ptr, $1.length + 1); } | string_exp STRING { /* Note that we NUL-terminate here, but just for convenience. */ - struct stoken t; - t.length = $1.length + $2.length; - t.ptr = malloc (t.length + 1); - memcpy (t.ptr, $1.ptr, $1.length); - memcpy (t.ptr + $1.length, $2.ptr, $2.length + 1); - free ($1.ptr); - $$ = t; + char *p; + ++$$.len; + $$.tokens = realloc ($$.tokens, + $$.len * sizeof (struct typed_stoken)); + + p = malloc ($2.length + 1); + memcpy (p, $2.ptr, $2.length + 1); + + $$.tokens[$$.len - 1].type = $2.type; + $$.tokens[$$.len - 1].length = $2.length; + $$.tokens[$$.len - 1].ptr = p; } ; exp : string_exp - { /* C strings are converted into array constants with - an explicit null byte added at the end. Thus - the array upper bound is the string length. - There is no such thing in C as a completely empty - string. */ - char *sp = $1.ptr; int count = $1.length; - while (count-- > 0) + { + int i; + enum c_string_type type = C_STRING; + + for (i = 0; i < $1.len; ++i) { - write_exp_elt_opcode (OP_LONG); - write_exp_elt_type (parse_type->builtin_char); - write_exp_elt_longcst ((LONGEST)(*sp++)); - write_exp_elt_opcode (OP_LONG); + switch ($1.tokens[i].type) + { + case C_STRING: + break; + case C_WIDE_STRING: + case C_STRING_16: + case C_STRING_32: + if (type != C_STRING + && type != $1.tokens[i].type) + error ("Undefined string concatenation."); + type = $1.tokens[i].type; + break; + default: + /* internal error */ + internal_error (__FILE__, __LINE__, + "unrecognized type in string concatenation"); + } } - write_exp_elt_opcode (OP_LONG); - write_exp_elt_type (parse_type->builtin_char); - write_exp_elt_longcst ((LONGEST)'\0'); - write_exp_elt_opcode (OP_LONG); - write_exp_elt_opcode (OP_ARRAY); - write_exp_elt_longcst ((LONGEST) 0); - write_exp_elt_longcst ((LONGEST) ($1.length)); - write_exp_elt_opcode (OP_ARRAY); - free ($1.ptr); + + write_exp_string_vector (type, &$1); + for (i = 0; i < $1.len; ++i) + free ($1.tokens[i].ptr); + free ($1.tokens); } ; @@ -713,12 +776,13 @@ qualified_name: typebase COLONCOLON name ; variable: qualified_name + | COLONCOLON qualified_name | COLONCOLON name { char *name = copy_name ($2); struct symbol *sym; struct minimal_symbol *msymbol; - + sym = lookup_symbol (name, (const struct block *) NULL, VAR_DOMAIN, (int *) NULL); @@ -856,7 +920,7 @@ array_mod: '[' ']' func_mod: '(' ')' { $$ = 0; } | '(' nonempty_typelist ')' - { free ($2); $$ = 0; } + { do_cleanups (typelist_cleanup); $$ = 0; } ; /* We used to try to recognize pointer to member types here, but @@ -1057,12 +1121,15 @@ typename: TYPENAME nonempty_typelist : type { $$ = (struct type **) malloc (sizeof (struct type *) * 2); + typelist_cleanup = make_cleanup (free, $$); $$[0] = 1; /* Number of types in vector */ $$[1] = $1; } | nonempty_typelist ',' type { int len = sizeof (struct type *) * (++($1[0]) + 1); $$ = (struct type **) realloc ((char *) $1, len); + discard_cleanups (typelist_cleanup); + typelist_cleanup = make_cleanup (free, $$); $$[$$[0]] = $3; } ; @@ -1361,6 +1428,263 @@ parse_number (p, len, parsed_float, putithere) return INT; } +/* Temporary obstack used for holding strings. */ +static struct obstack tempbuf; +static int tempbuf_init; + +/* Parse a C escape sequence. The initial backslash of the sequence + is at (*PTR)[-1]. *PTR will be updated to point to just after the + last character of the sequence. If OUTPUT is not NULL, the + translated form of the escape sequence will be written there. If + OUTPUT is NULL, no output is written and the call will only affect + *PTR. If an escape sequence is expressed in target bytes, then the + entire sequence will simply be copied to OUTPUT. Return 1 if any + character was emitted, 0 otherwise. */ + +int +c_parse_escape (char **ptr, struct obstack *output) +{ + char *tokptr = *ptr; + int result = 1; + + /* Some escape sequences undergo character set conversion. Those we + translate here. */ + switch (*tokptr) + { + /* Hex escapes do not undergo character set conversion, so keep + the escape sequence for later. */ + case 'x': + if (output) + obstack_grow_str (output, "\\x"); + ++tokptr; + if (!isxdigit (*tokptr)) + error (_("\\x escape without a following hex digit")); + while (isxdigit (*tokptr)) + { + if (output) + obstack_1grow (output, *tokptr); + ++tokptr; + } + break; + + /* Octal escapes do not undergo character set conversion, so + keep the escape sequence for later. */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + if (output) + obstack_grow_str (output, "\\"); + while (isdigit (*tokptr) && *tokptr != '8' && *tokptr != '9') + { + if (output) + obstack_1grow (output, *tokptr); + ++tokptr; + } + break; + + /* We handle UCNs later. We could handle them here, but that + would mean a spurious error in the case where the UCN could + be converted to the target charset but not the host + charset. */ + case 'u': + case 'U': + { + char c = *tokptr; + int i, len = c == 'U' ? 8 : 4; + if (output) + { + obstack_1grow (output, '\\'); + obstack_1grow (output, *tokptr); + } + ++tokptr; + if (!isxdigit (*tokptr)) + error (_("\\%c escape without a following hex digit"), c); + for (i = 0; i < len && isxdigit (*tokptr); ++i) + { + if (output) + obstack_1grow (output, *tokptr); + ++tokptr; + } + } + break; + + /* We must pass backslash through so that it does not + cause quoting during the second expansion. */ + case '\\': + if (output) + obstack_grow_str (output, "\\\\"); + ++tokptr; + break; + + /* Escapes which undergo conversion. */ + case 'a': + if (output) + obstack_1grow (output, '\a'); + ++tokptr; + break; + case 'b': + if (output) + obstack_1grow (output, '\b'); + ++tokptr; + break; + case 'f': + if (output) + obstack_1grow (output, '\f'); + ++tokptr; + break; + case 'n': + if (output) + obstack_1grow (output, '\n'); + ++tokptr; + break; + case 'r': + if (output) + obstack_1grow (output, '\r'); + ++tokptr; + break; + case 't': + if (output) + obstack_1grow (output, '\t'); + ++tokptr; + break; + case 'v': + if (output) + obstack_1grow (output, '\v'); + ++tokptr; + break; + + /* GCC extension. */ + case 'e': + if (output) + obstack_1grow (output, HOST_ESCAPE_CHAR); + ++tokptr; + break; + + /* Backslash-newline expands to nothing at all. */ + case '\n': + ++tokptr; + result = 0; + break; + + /* A few escapes just expand to the character itself. */ + case '\'': + case '\"': + case '?': + /* GCC extensions. */ + case '(': + case '{': + case '[': + case '%': + /* Unrecognized escapes turn into the character itself. */ + default: + if (output) + obstack_1grow (output, *tokptr); + ++tokptr; + break; + } + *ptr = tokptr; + return result; +} + +/* Parse a string or character literal from TOKPTR. The string or + character may be wide or unicode. *OUTPTR is set to just after the + end of the literal in the input string. The resulting token is + stored in VALUE. This returns a token value, either STRING or + CHAR, depending on what was parsed. *HOST_CHARS is set to the + number of host characters in the literal. */ +static int +parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value, + int *host_chars) +{ + int quote, i; + enum c_string_type type; + + /* Build the gdb internal form of the input string in tempbuf. Note + that the buffer is null byte terminated *only* for the + convenience of debugging gdb itself and printing the buffer + contents when the buffer contains no embedded nulls. Gdb does + not depend upon the buffer being null byte terminated, it uses + the length string instead. This allows gdb to handle C strings + (as well as strings in other languages) with embedded null + bytes */ + + if (!tempbuf_init) + tempbuf_init = 1; + else + obstack_free (&tempbuf, NULL); + obstack_init (&tempbuf); + + /* Record the string type. */ + if (*tokptr == 'L') + { + type = C_WIDE_STRING; + ++tokptr; + } + else if (*tokptr == 'u') + { + type = C_STRING_16; + ++tokptr; + } + else if (*tokptr == 'U') + { + type = C_STRING_32; + ++tokptr; + } + else + type = C_STRING; + + /* Skip the quote. */ + quote = *tokptr; + if (quote == '\'') + type |= C_CHAR; + ++tokptr; + + *host_chars = 0; + + while (*tokptr) + { + char c = *tokptr; + if (c == '\\') + { + ++tokptr; + *host_chars += c_parse_escape (&tokptr, &tempbuf); + } + else if (c == quote) + break; + else + { + obstack_1grow (&tempbuf, c); + ++tokptr; + /* FIXME: this does the wrong thing with multi-byte host + characters. We could use mbrlen here, but that would + make "set host-charset" a bit less useful. */ + ++*host_chars; + } + } + + if (*tokptr != quote) + { + if (quote == '"') + error ("Unterminated string in expression."); + else + error ("Unmatched single quote."); + } + ++tokptr; + + value->type = type; + value->ptr = obstack_base (&tempbuf); + value->length = obstack_object_size (&tempbuf); + + *outptr = tokptr; + + return quote == '"' ? STRING : CHAR; +} + struct token { char *operator; @@ -1526,23 +1850,33 @@ static int last_was_structop; static int yylex () { + /* name_prefix stores the full qualification of a variable that is + specified in the expression. It is used to eleminate confusion + during lookup.*/ + static char* name_prefix = NULL; + static int name_prefix_len = 0; + static int terminate_prefix = 0; + int c; int namelen; unsigned int i; char *tokstart; - char *tokptr; - int tempbufindex; - static char *tempbuf; - static int tempbufsize; - char * token_string = NULL; - int class_prefix = 0; int saw_structop = last_was_structop; char *copy; last_was_structop = 0; - + retry: - + + if(terminate_prefix || + lexptr != name_prefix + name_prefix_len // Some token was skiped so clear name_prefix + ){ + name_prefix = NULL; + name_prefix_len = 0; + } + + terminate_prefix = 1; + /* Check if this is a macro invocation that we need to expand. */ if (! scanning_macro_expansion ()) { @@ -1570,10 +1904,19 @@ yylex () for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++) if (strncmp (tokstart, tokentab2[i].operator, 2) == 0) { + + if(tokentab2[i].token == COLONCOLON){ + name_prefix_len += 2; + terminate_prefix = 0; + if(name_prefix == NULL){ + name_prefix = lexptr; + } + } lexptr += 2; yylval.opcode = tokentab2[i].opcode; if (in_parse_field && tokentab2[i].token == ARROW) last_was_structop = 1; + return tokentab2[i].token; } @@ -1602,51 +1945,13 @@ yylex () return 0; case ' ': + name_prefix_len++; + terminate_prefix = 0; case '\t': case '\n': lexptr++; goto retry; - case '\'': - /* We either have a character constant ('0' or '\177' for example) - or we have a quoted symbol reference ('foo(int,int)' in C++ - for example). */ - lexptr++; - c = *lexptr++; - if (c == '\\') - c = parse_escape (&lexptr); - else if (c == '\'') - error ("Empty character constant."); - else if (! host_char_to_target (c, &c)) - { - int toklen = lexptr - tokstart + 1; - char *tok = alloca (toklen + 1); - memcpy (tok, tokstart, toklen); - tok[toklen] = '\0'; - error ("There is no character corresponding to %s in the target " - "character set `%s'.", tok, target_charset ()); - } - - yylval.typed_val_int.val = c; - yylval.typed_val_int.type = parse_type->builtin_char; - - c = *lexptr++; - if (c != '\'') - { - namelen = skip_quoted (tokstart) - tokstart; - if (namelen > 2) - { - lexptr = tokstart + namelen; - if (lexptr[-1] != '\'') - error ("Unmatched single quote."); - namelen -= 2; - tokstart++; - goto tryname; - } - error ("Invalid character constant."); - } - return INT; - case '(': paren_depth++; lexptr++; @@ -1764,70 +2069,33 @@ yylex () lexptr++; return c; + case 'L': + case 'u': + case 'U': + if (tokstart[1] != '"' && tokstart[1] != '\'') + break; + /* Fall through. */ + case '\'': case '"': - - /* Build the gdb internal form of the input string in tempbuf, - translating any standard C escape forms seen. Note that the - buffer is null byte terminated *only* for the convenience of - debugging gdb itself and printing the buffer contents when - the buffer contains no embedded nulls. Gdb does not depend - upon the buffer being null byte terminated, it uses the length - string instead. This allows gdb to handle C strings (as well - as strings in other languages) with embedded null bytes */ - - tokptr = ++tokstart; - tempbufindex = 0; - - do { - char *char_start_pos = tokptr; - - /* Grow the static temp buffer if necessary, including allocating - the first one on demand. */ - if (tempbufindex + 1 >= tempbufsize) - { - tempbuf = (char *) realloc (tempbuf, tempbufsize += 64); - } - switch (*tokptr) + { + int host_len; + int result = parse_string_or_char (tokstart, &lexptr, &yylval.tsval, + &host_len); + if (result == CHAR) { - case '\0': - case '"': - /* Do nothing, loop will terminate. */ - break; - case '\\': - tokptr++; - c = parse_escape (&tokptr); - if (c == -1) + if (host_len == 0) + error ("Empty character constant."); + else if (host_len > 2 && c == '\'') { - continue; + ++tokstart; + namelen = lexptr - tokstart - 1; + goto tryname; } - tempbuf[tempbufindex++] = c; - break; - default: - c = *tokptr++; - if (! host_char_to_target (c, &c)) - { - int len = tokptr - char_start_pos; - char *copy = alloca (len + 1); - memcpy (copy, char_start_pos, len); - copy[len] = '\0'; - - error ("There is no character corresponding to `%s' " - "in the target character set `%s'.", - copy, target_charset ()); - } - tempbuf[tempbufindex++] = c; - break; + else if (host_len > 1) + error ("Invalid character constant."); } - } while ((*tokptr != '"') && (*tokptr != '\0')); - if (*tokptr++ != '"') - { - error ("Unterminated string in expression."); - } - tempbuf[tempbufindex] = '\0'; /* See note above */ - yylval.sval.ptr = tempbuf; - yylval.sval.length = tempbufindex; - lexptr = tokptr; - return (STRING); + return result; + } } if (!(c == '_' || c == '$' @@ -1836,11 +2104,13 @@ yylex () error ("Invalid character '%c' in expression.", c); /* It's a name. See how long it is. */ + namelen = 0; for (c = tokstart[namelen]; (c == '_' || c == '$' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '<');) { + /* Template parameter lists are part of the name. FIXME: This mishandles `print $a<4&&$a>3'. */ @@ -1904,14 +2174,29 @@ yylex () currently as names of types; NAME for other symbols. The caller is not constrained to care about the distinction. */ { + char *tmp = copy; struct symbol *sym; int is_a_field_of_this = 0; int hextype; - sym = lookup_symbol (copy, expression_context_block, + if(name_prefix != NULL){ + tmp = savestring (name_prefix, name_prefix_len+namelen); + } + + sym = lookup_symbol (tmp, expression_context_block, VAR_DOMAIN, parse_language->la_language == language_cplus ? &is_a_field_of_this : (int *) NULL); + + /* keep this name as prefix for the next name */ + if(sym){ + if(name_prefix == NULL){ + name_prefix = tokstart; + } + name_prefix_len += namelen; + terminate_prefix = 0; + } + /* Call lookup_symtab, not lookup_partial_symtab, in case there are no psymtabs (coff, xcoff, or some future change to blow away the psymtabs once once symbols are read). */ @@ -1970,6 +2255,7 @@ yylex () yylval.ssym.is_a_field_of_this = is_a_field_of_this; if (in_parse_field && *lexptr == '\0') saw_name_at_eof = 1; + return NAME; } } diff --git a/gdb/c-lang.c b/gdb/c-lang.c index 8b5410f..188755b 100644 --- a/gdb/c-lang.c +++ b/gdb/c-lang.c @@ -33,48 +33,304 @@ #include "demangle.h" #include "cp-abi.h" #include "cp-support.h" +#include "gdb_obstack.h" +#include +#include +#include extern void _initialize_c_language (void); -static void c_emit_char (int c, struct ui_file * stream, int quoter); + +/* Given a C string type, STR_TYPE, return the corresponding target + character set name. */ + +static const char * +charset_for_string_type (enum c_string_type str_type) +{ + switch (str_type & ~C_CHAR) + { + case C_STRING: + return target_charset (); + case C_WIDE_STRING: + return target_wide_charset (); + case C_STRING_16: + /* FIXME: UCS-2 is not always correct. */ + if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) + return "UCS-2BE"; + else + return "UCS-2LE"; + case C_STRING_32: + /* FIXME: UCS-4 is not always correct. */ + if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) + return "UCS-4BE"; + else + return "UCS-4LE"; + } + internal_error (__FILE__, __LINE__, "unhandled c_string_type"); +} + +/* Classify ELTTYPE according to what kind of character it is. Return + the enum constant representing the character type. Also set + *ENCODING to the name of the character set to use when converting + characters of this type to the host character set. */ + +static enum c_string_type +classify_type (struct type *elttype, const char **encoding) +{ + struct type *saved_type; + enum c_string_type result; + + /* We do one or two passes -- one on ELTTYPE, and then maybe a + second one on a typedef target. */ + do + { + char *name = TYPE_NAME (elttype); + + if (TYPE_CODE (elttype) == TYPE_CODE_CHAR || !name) + { + result = C_CHAR; + goto done; + } + + if (!strcmp (name, "wchar_t")) + { + result = C_WIDE_CHAR; + goto done; + } + + if (!strcmp (name, "char16_t")) + { + result = C_CHAR_16; + goto done; + } + + if (!strcmp (name, "char32_t")) + { + result = C_CHAR_32; + goto done; + } + + saved_type = elttype; + CHECK_TYPEDEF (elttype); + } + while (elttype != saved_type); + + /* Punt. */ + result = C_CHAR; + + done: + *encoding = charset_for_string_type (result); + return result; +} + +/* Return true if print_wchar can display W without resorting to a + numeric escape, false otherwise. */ + +static int +wchar_printable (wchar_t w) +{ + return (iswprint (w) + || w == L'\a' || w == L'\b' || w == L'\f' || w == L'\n' + || w == L'\r' || w == L'\t' || w == L'\v'); +} + +/* A helper function that converts the contents of STRING to wide + characters and then appends them to OUTPUT. */ + +static void +append_string_as_wide (const char *string, struct obstack *output) +{ + for (; *string; ++string) + { + wchar_t w = btowc (*string); + obstack_grow (output, &w, sizeof (wchar_t)); + } +} + +/* Print a wide character W to OUTPUT. ORIG is a pointer to the + original (target) bytes representing the character, ORIG_LEN is the + number of valid bytes. WIDTH is the number of bytes in a base + characters of the type. OUTPUT is an obstack to which wide + characters are emitted. QUOTER is a (narrow) character indicating + the style of quotes surrounding the character to be printed. + NEED_ESCAPE is an in/out flag which is used to track numeric + escapes across calls. */ + +static void +print_wchar (wint_t w, const gdb_byte *orig, int orig_len, + int width, struct obstack *output, int quoter, + int *need_escapep) +{ + int need_escape = *need_escapep; + *need_escapep = 0; + if (iswprint (w) && (!need_escape || (!iswdigit (w) + && w != L'8' + && w != L'9'))) + { + if (w == btowc (quoter) || w == L'\\') + obstack_grow_wstr (output, L"\\"); + obstack_grow (output, &w, sizeof (wchar_t)); + } + else + { + switch (w) + { + case L'\a': + obstack_grow_wstr (output, L"\\a"); + break; + case L'\b': + obstack_grow_wstr (output, L"\\b"); + break; + case L'\f': + obstack_grow_wstr (output, L"\\f"); + break; + case L'\n': + obstack_grow_wstr (output, L"\\n"); + break; + case L'\r': + obstack_grow_wstr (output, L"\\r"); + break; + case L'\t': + obstack_grow_wstr (output, L"\\t"); + break; + case L'\v': + obstack_grow_wstr (output, L"\\v"); + break; + default: + { + int i; + + for (i = 0; i + width <= orig_len; i += width) + { + char octal[30]; + ULONGEST value = extract_unsigned_integer (&orig[i], width); + sprintf (octal, "\\%lo", (long) value); + append_string_as_wide (octal, output); + } + /* If we somehow have extra bytes, print them now. */ + while (i < orig_len) + { + char octal[5]; + sprintf (octal, "\\%.3o", orig[i] & 0xff); + append_string_as_wide (octal, output); + ++i; + } + + *need_escapep = 1; + } + break; + } + } +} /* Print the character C on STREAM as part of the contents of a literal string whose delimiter is QUOTER. Note that that format for printing characters and strings is language specific. */ static void -c_emit_char (int c, struct ui_file *stream, int quoter) +c_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) { - const char *escape; - int host_char; + struct obstack wchar_buf, output; + struct cleanup *cleanups; + const char *encoding; + gdb_byte *buf; + struct wchar_iterator *iter; + int need_escape = 0; - c &= 0xFF; /* Avoid sign bit follies */ + classify_type (type, &encoding); - escape = c_target_char_has_backslash_escape (c); - if (escape) - { - if (quoter == '"' && strcmp (escape, "0") == 0) - /* Print nulls embedded in double quoted strings as \000 to - prevent ambiguity. */ - fprintf_filtered (stream, "\\000"); - else - fprintf_filtered (stream, "\\%s", escape); - } - else if (target_char_to_host (c, &host_char) - && host_char_print_literally (host_char)) + buf = alloca (TYPE_LENGTH (type)); + pack_long (buf, type, c); + + iter = make_wchar_iterator (buf, TYPE_LENGTH (type), encoding, + TYPE_LENGTH (type)); + cleanups = make_cleanup_wchar_iterator (iter); + + /* This holds the printable form of the wchar_t data. */ + obstack_init (&wchar_buf); + make_cleanup_obstack_free (&wchar_buf); + + while (1) { - if (host_char == '\\' || host_char == quoter) - fputs_filtered ("\\", stream); - fprintf_filtered (stream, "%c", host_char); + int num_chars; + wchar_t *chars; + const gdb_byte *buf; + size_t buflen; + int print_escape = 1; + enum wchar_iterate_result result; + + num_chars = wchar_iterate (iter, &result, &chars, &buf, &buflen); + if (num_chars < 0) + break; + if (num_chars > 0) + { + /* If all characters are printable, print them. Otherwise, + we're going to have to print an escape sequence. We + check all characters because we want to print the target + bytes in the escape sequence, and we don't know character + boundaries there. */ + int i; + + print_escape = 0; + for (i = 0; i < num_chars; ++i) + if (!wchar_printable (chars[i])) + { + print_escape = 1; + break; + } + + if (!print_escape) + { + for (i = 0; i < num_chars; ++i) + print_wchar (chars[i], buf, buflen, TYPE_LENGTH (type), + &wchar_buf, quoter, &need_escape); + } + } + + /* This handles the NUM_CHARS == 0 case as well. */ + if (print_escape) + print_wchar (WEOF, buf, buflen, TYPE_LENGTH (type), &wchar_buf, quoter, + &need_escape); } - else - fprintf_filtered (stream, "\\%.3o", (unsigned int) c); + + /* The output in the host encoding. */ + obstack_init (&output); + make_cleanup_obstack_free (&output); + + convert_between_encodings ("wchar_t", host_charset (), + obstack_base (&wchar_buf), + obstack_object_size (&wchar_buf), + 1, &output, translit_char); + obstack_1grow (&output, '\0'); + + fputs_filtered (obstack_base (&output), stream); + + do_cleanups (cleanups); } void -c_printchar (int c, struct ui_file *stream) +c_printchar (int c, struct type *type, struct ui_file *stream) { + enum c_string_type str_type; + const char *encoding; + + str_type = classify_type (type, &encoding); + switch (str_type) + { + case C_CHAR: + break; + case C_WIDE_CHAR: + fputc_filtered ('L', stream); + break; + case C_CHAR_16: + fputc_filtered ('u', stream); + break; + case C_CHAR_32: + fputc_filtered ('U', stream); + break; + } + fputc_filtered ('\'', stream); - LA_EMIT_CHAR (c, stream, '\''); + LA_EMIT_CHAR (c, type, stream, '\''); fputc_filtered ('\'', stream); } @@ -85,87 +341,206 @@ c_printchar (int c, struct ui_file *stream) printing LENGTH characters, or if FORCE_ELLIPSES. */ void -c_printstr (struct ui_file *stream, const gdb_byte *string, - unsigned int length, int width, int force_ellipses, +c_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string, + unsigned int length, int force_ellipses, const struct value_print_options *options) { unsigned int i; unsigned int things_printed = 0; int in_quotes = 0; int need_comma = 0; + int width = TYPE_LENGTH (type); + struct obstack wchar_buf, output; + struct cleanup *cleanup; + enum c_string_type str_type; + const char *encoding; + struct wchar_iterator *iter; + int finished = 0; + int need_escape = 0; /* If the string was not truncated due to `set print elements', and the last byte of it is a null, we don't print that, in traditional C style. */ if (!force_ellipses && length > 0 - && (extract_unsigned_integer (string + (length - 1) * width, width) - == '\0')) + && (extract_unsigned_integer (string + (length - 1) * width, width) == 0)) length--; + str_type = classify_type (type, &encoding) & ~C_CHAR; + switch (str_type) + { + case C_STRING: + break; + case C_WIDE_STRING: + fputs_filtered ("L", stream); + break; + case C_STRING_16: + fputs_filtered ("u", stream); + break; + case C_STRING_32: + fputs_filtered ("U", stream); + break; + } + if (length == 0) { fputs_filtered ("\"\"", stream); return; } - for (i = 0; i < length && things_printed < options->print_max; ++i) + if (length == -1) + { + unsigned long current_char = 1; + for (i = 0; current_char; ++i) + { + QUIT; + current_char = extract_unsigned_integer (string + i * width, width); + } + length = i; + } + + /* Arrange to iterate over the characters, in wchar_t form. */ + iter = make_wchar_iterator (string, length * width, encoding, width); + cleanup = make_cleanup_wchar_iterator (iter); + + /* WCHAR_BUF is the obstack we use to represent the string in + wchar_t form. */ + obstack_init (&wchar_buf); + make_cleanup_obstack_free (&wchar_buf); + + while (!finished && things_printed < options->print_max) { - /* Position of the character we are examining - to see whether it is repeated. */ - unsigned int rep1; - /* Number of repetitions we have detected so far. */ - unsigned int reps; - unsigned long current_char; + int num_chars; + enum wchar_iterate_result result; + wchar_t *chars; + const gdb_byte *buf; + size_t buflen; QUIT; if (need_comma) { - fputs_filtered (", ", stream); + obstack_grow_wstr (&wchar_buf, L", "); need_comma = 0; } - current_char = extract_unsigned_integer (string + i * width, width); + num_chars = wchar_iterate (iter, &result, &chars, &buf, &buflen); + /* We only look at repetitions when we were able to convert a + single character in isolation. This makes the code simpler + and probably does the sensible thing in the majority of + cases. */ + while (num_chars == 1) + { + /* Count the number of repetitions. */ + unsigned int reps = 0; + wchar_t current_char = chars[0]; + const gdb_byte *orig_buf = buf; + int orig_len = buflen; - rep1 = i + 1; - reps = 1; - while (rep1 < length - && extract_unsigned_integer (string + rep1 * width, width) - == current_char) + if (need_comma) + { + obstack_grow_wstr (&wchar_buf, L", "); + need_comma = 0; + } + + while (num_chars == 1 && current_char == chars[0]) + { + num_chars = wchar_iterate (iter, &result, &chars, &buf, &buflen); + ++reps; + } + + /* Emit CURRENT_CHAR according to the repetition count and + options. */ + if (reps > options->repeat_count_threshold) + { + if (in_quotes) + { + if (options->inspect_it) + obstack_grow_wstr (&wchar_buf, L"\\\", "); + else + obstack_grow_wstr (&wchar_buf, L"\", "); + in_quotes = 0; + } + obstack_grow_wstr (&wchar_buf, L"'"); + need_escape = 0; + print_wchar (current_char, orig_buf, orig_len, width, + &wchar_buf, '\'', &need_escape); + obstack_grow_wstr (&wchar_buf, L"'"); + { + /* Painful gyrations. */ + int j; + char *s = xstrprintf (_(" "), reps); + for (j = 0; s[j]; ++j) + { + wchar_t w = btowc (s[j]); + obstack_grow (&wchar_buf, &w, sizeof (wchar_t)); + } + xfree (s); + } + things_printed += options->repeat_count_threshold; + need_comma = 1; + } + else + { + /* Saw the character one or more times, but fewer than + the repetition threshold. */ + if (!in_quotes) + { + if (options->inspect_it) + obstack_grow_wstr (&wchar_buf, L"\\\""); + else + obstack_grow_wstr (&wchar_buf, L"\""); + in_quotes = 1; + need_escape = 0; + } + + while (reps-- > 0) + { + print_wchar (current_char, orig_buf, orig_len, width, + &wchar_buf, '"', &need_escape); + ++things_printed; + } + } + } + + /* NUM_CHARS and the other outputs from wchar_iterate are valid + here regardless of which branch was taken above. */ + if (num_chars < 0) { - ++rep1; - ++reps; + /* Hit EOF. */ + finished = 1; + break; } - if (reps > options->repeat_count_threshold) + switch (result) { - if (in_quotes) + case wchar_iterate_invalid: + if (!in_quotes) { if (options->inspect_it) - fputs_filtered ("\\\", ", stream); + obstack_grow_wstr (&wchar_buf, L"\\\""); else - fputs_filtered ("\", ", stream); - in_quotes = 0; + obstack_grow_wstr (&wchar_buf, L"\""); + in_quotes = 1; } - LA_PRINT_CHAR (current_char, stream); - fprintf_filtered (stream, _(" "), reps); - i = rep1 - 1; - things_printed += options->repeat_count_threshold; - need_comma = 1; - } - else - { - if (!in_quotes) + need_escape = 0; + print_wchar (WEOF, buf, buflen, width, &wchar_buf, '"', &need_escape); + break; + + case wchar_iterate_incomplete: + if (in_quotes) { if (options->inspect_it) - fputs_filtered ("\\\"", stream); + obstack_grow_wstr (&wchar_buf, L"\\\","); else - fputs_filtered ("\"", stream); - in_quotes = 1; + obstack_grow_wstr (&wchar_buf, L"\","); + in_quotes = 0; } - LA_EMIT_CHAR (current_char, stream, '"'); - ++things_printed; + obstack_grow_wstr (&wchar_buf, L" "); + finished = 1; + break; } } @@ -173,13 +548,27 @@ c_printstr (struct ui_file *stream, const gdb_byte *string, if (in_quotes) { if (options->inspect_it) - fputs_filtered ("\\\"", stream); + obstack_grow_wstr (&wchar_buf, L"\\\""); else - fputs_filtered ("\"", stream); + obstack_grow_wstr (&wchar_buf, L"\""); } - if (force_ellipses || i < length) - fputs_filtered ("...", stream); + if (force_ellipses || !finished) + obstack_grow_wstr (&wchar_buf, L"..."); + + /* OUTPUT is where we collect `char's for printing. */ + obstack_init (&output); + make_cleanup_obstack_free (&output); + + convert_between_encodings ("wchar_t", host_charset (), + obstack_base (&wchar_buf), + obstack_object_size (&wchar_buf), + 1, &output, translit_char); + obstack_1grow (&output, '\0'); + + fputs_filtered (obstack_base (&output), stream); + + do_cleanups (cleanup); } /* Obtain a C string from the inferior storing it in a newly allocated @@ -298,7 +687,285 @@ c_get_string (struct value *value, gdb_byte **buffer, int *length, } -/* Preprocessing and parsing C and C++ expressions. */ +/* Evaluating C and C++ expressions. */ + +/* Convert a UCN. The digits of the UCN start at P and extend no + farther than LIMIT. DEST_CHARSET is the name of the character set + into which the UCN should be converted. The results are written to + OUTPUT. LENGTH is the maximum length of the UCN, either 4 or 8. + Returns a pointer to just after the final digit of the UCN. */ + +static char * +convert_ucn (char *p, char *limit, const char *dest_charset, + struct obstack *output, int length) +{ + unsigned long result = 0; + gdb_byte data[4]; + int i; + + for (i = 0; i < length && p < limit && isxdigit (*p); ++i, ++p) + result = (result << 4) + host_hex_value (*p); + + for (i = 3; i >= 0; --i) + { + data[i] = result & 0xff; + result >>= 8; + } + + convert_between_encodings ("UCS-4BE", dest_charset, data, 4, 4, output, + translit_none); + + return p; +} + +/* Emit a character, VALUE, which was specified numerically, to + OUTPUT. TYPE is the target character type. */ + +static void +emit_numeric_character (struct type *type, unsigned long value, + struct obstack *output) +{ + gdb_byte *buffer; + + buffer = alloca (TYPE_LENGTH (type)); + pack_long (buffer, type, value); + obstack_grow (output, buffer, TYPE_LENGTH (type)); +} + +/* Convert an octal escape sequence. TYPE is the target character + type. The digits of the escape sequence begin at P and extend no + farther than LIMIT. The result is written to OUTPUT. Returns a + pointer to just after the final digit of the escape sequence. */ + +static char * +convert_octal (struct type *type, char *p, char *limit, struct obstack *output) +{ + unsigned long value = 0; + + while (p < limit && isdigit (*p) && *p != '8' && *p != '9') + { + value = 8 * value + host_hex_value (*p); + ++p; + } + + emit_numeric_character (type, value, output); + + return p; +} + +/* Convert a hex escape sequence. TYPE is the target character type. + The digits of the escape sequence begin at P and extend no farther + than LIMIT. The result is written to OUTPUT. Returns a pointer to + just after the final digit of the escape sequence. */ + +static char * +convert_hex (struct type *type, char *p, char *limit, struct obstack *output) +{ + unsigned long value = 0; + + while (p < limit && isxdigit (*p)) + { + value = 16 * value + host_hex_value (*p); + ++p; + } + + emit_numeric_character (type, value, output); + + return p; +} + +#define ADVANCE \ + do { \ + ++p; \ + if (p == limit) \ + error (_("Malformed escape sequence")); \ + } while (0) + +/* Convert an escape sequence to a target format. TYPE is the target + character type to use, and DEST_CHARSET is the name of the target + character set. The backslash of the escape sequence is at *P, and + the escape sequence will not extend past LIMIT. The results are + written to OUTPUT. Returns a pointer to just past the final + character of the escape sequence. */ + +static char * +convert_escape (struct type *type, const char *dest_charset, + char *p, char *limit, struct obstack *output) +{ + /* Skip the backslash. */ + ADVANCE; + + switch (*p) + { + case '\\': + obstack_1grow (output, '\\'); + ++p; + break; + + case 'x': + ADVANCE; + if (!isxdigit (*p)) + error (_("\\x used with no following hex digits.")); + p = convert_hex (type, p, limit, output); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + p = convert_octal (type, p, limit, output); + break; + + case 'u': + case 'U': + { + int length = *p == 'u' ? 4 : 8; + ADVANCE; + if (!isxdigit (*p)) + error (_("\\u used with no following hex digits")); + p = convert_ucn (p, limit, dest_charset, output, length); + } + } + + return p; +} + +/* Given a single string from a (C-specific) OP_STRING list, convert + it to a target string, handling escape sequences specially. The + output is written to OUTPUT. DATA is the input string, which has + length LEN. DEST_CHARSET is the name of the target character set, + and TYPE is the type of target character to use. */ + +static void +parse_one_string (struct obstack *output, char *data, int len, + const char *dest_charset, struct type *type) +{ + char *limit; + + limit = data + len; + + while (data < limit) + { + char *p = data; + /* Look for next escape, or the end of the input. */ + while (p < limit && *p != '\\') + ++p; + /* If we saw a run of characters, convert them all. */ + if (p > data) + convert_between_encodings (host_charset (), dest_charset, + data, p - data, 1, output, translit_none); + /* If we saw an escape, convert it. */ + if (p < limit) + p = convert_escape (type, dest_charset, p, limit, output); + data = p; + } +} + +/* Expression evaluator for the C language family. Most operations + are delegated to evaluate_subexp_standard; see that function for a + description of the arguments. */ + +static struct value * +evaluate_subexp_c (struct type *expect_type, struct expression *exp, + int *pos, enum noside noside) +{ + enum exp_opcode op = exp->elts[*pos].opcode; + + switch (op) + { + case OP_STRING: + { + int oplen, limit; + struct type *type; + struct obstack output; + struct cleanup *cleanup; + struct value *result; + enum c_string_type dest_type; + const char *dest_charset; + + obstack_init (&output); + cleanup = make_cleanup_obstack_free (&output); + + ++*pos; + oplen = longest_to_int (exp->elts[*pos].longconst); + + ++*pos; + limit = *pos + BYTES_TO_EXP_ELEM (oplen + 1); + dest_type + = (enum c_string_type) longest_to_int (exp->elts[*pos].longconst); + switch (dest_type & ~C_CHAR) + { + case C_STRING: + type = language_string_char_type (current_language, + current_gdbarch); + break; + case C_WIDE_STRING: + type = lookup_typename ("wchar_t", NULL, 0); + break; + case C_STRING_16: + type = lookup_typename ("char16_t", NULL, 0); + break; + case C_STRING_32: + type = lookup_typename ("char32_t", NULL, 0); + break; + default: + internal_error (__FILE__, __LINE__, "unhandled c_string_type"); + } + dest_charset = charset_for_string_type (dest_type); + + ++*pos; + while (*pos < limit) + { + int len; + + len = longest_to_int (exp->elts[*pos].longconst); + + ++*pos; + if (noside != EVAL_SKIP) + parse_one_string (&output, &exp->elts[*pos].string, len, + dest_charset, type); + *pos += BYTES_TO_EXP_ELEM (len); + } + + /* Skip the trailing length and opcode. */ + *pos += 2; + + if (noside == EVAL_SKIP) + return NULL; + + if ((dest_type & C_CHAR) != 0) + { + LONGEST value; + + if (obstack_object_size (&output) != TYPE_LENGTH (type)) + error (_("Could not convert character constant to target character set")); + value = unpack_long (type, obstack_base (&output)); + result = value_from_longest (type, value); + } + else + { + int i; + /* Write the terminating character. */ + for (i = 0; i < TYPE_LENGTH (type); ++i) + obstack_1grow (&output, 0); + result = value_typed_string (obstack_base (&output), + obstack_object_size (&output), + type); + } + do_cleanups (cleanup); + return result; + } + break; + + default: + break; + } + return evaluate_subexp_standard (expect_type, exp, pos, noside); +} @@ -396,6 +1063,15 @@ c_language_arch_info (struct gdbarch *gdbarch, lai->bool_type_default = builtin->builtin_int; } +static const struct exp_descriptor exp_descriptor_c = +{ + print_subexp_standard, + operator_length_standard, + op_name_standard, + dump_subexp_body_standard, + evaluate_subexp_c +}; + const struct language_defn c_language_defn = { "c", /* Language name */ @@ -405,7 +1081,7 @@ const struct language_defn c_language_defn = case_sensitive_on, array_row_major, macro_expansion_c, - &exp_descriptor_standard, + &exp_descriptor_c, c_parse, c_error, null_post_parser, @@ -524,7 +1200,7 @@ const struct language_defn cplus_language_defn = case_sensitive_on, array_row_major, macro_expansion_c, - &exp_descriptor_standard, + &exp_descriptor_c, c_parse, c_error, null_post_parser, @@ -562,7 +1238,7 @@ const struct language_defn asm_language_defn = case_sensitive_on, array_row_major, macro_expansion_c, - &exp_descriptor_standard, + &exp_descriptor_c, c_parse, c_error, null_post_parser, @@ -605,7 +1281,7 @@ const struct language_defn minimal_language_defn = case_sensitive_on, array_row_major, macro_expansion_c, - &exp_descriptor_standard, + &exp_descriptor_c, c_parse, c_error, null_post_parser, diff --git a/gdb/c-lang.h b/gdb/c-lang.h index 06c5767..ba9d996 100644 --- a/gdb/c-lang.h +++ b/gdb/c-lang.h @@ -29,9 +29,38 @@ struct language_arch_info; #include "macroexp.h" -extern int c_parse (void); /* Defined in c-exp.y */ - -extern void c_error (char *); /* Defined in c-exp.y */ +/* The various kinds of C string and character. Note that these + values are chosen so that they may be or'd together in certain + ways. */ +enum c_string_type + { + /* An ordinary string: "value". */ + C_STRING = 0, + /* A wide string: L"value". */ + C_WIDE_STRING = 1, + /* A 16-bit Unicode string: u"value". */ + C_STRING_16 = 2, + /* A 32-bit Unicode string: U"value". */ + C_STRING_32 = 3, + /* An ordinary char: 'v'. This can also be or'd with one of the + above to form the corresponding CHAR value from a STRING + value. */ + C_CHAR = 4, + /* A wide char: L'v'. */ + C_WIDE_CHAR = 5, + /* A 16-bit Unicode char: u'v'. */ + C_CHAR_16 = 6, + /* A 32-bit Unicode char: U'v'. */ + C_CHAR_32 = 7 + }; + +/* Defined in c-exp.y. */ + +extern int c_parse (void); + +extern void c_error (char *); + +extern int c_parse_escape (char **, struct obstack *); /* Defined in c-typeprint.c */ extern void c_print_type (struct type *, char *, struct ui_file *, int, @@ -48,10 +77,10 @@ extern int c_value_print (struct value *, struct ui_file *, /* These are in c-lang.c: */ -extern void c_printchar (int, struct ui_file *); +extern void c_printchar (int, struct type *, struct ui_file *); -extern void c_printstr (struct ui_file * stream, const gdb_byte *string, - unsigned int length, int width, +extern void c_printstr (struct ui_file * stream, struct type *elttype, + const gdb_byte *string, unsigned int length, int force_ellipses, const struct value_print_options *options); diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c index 0929516..c005fe4 100644 --- a/gdb/c-typeprint.c +++ b/gdb/c-typeprint.c @@ -40,8 +40,6 @@ static void cp_type_print_method_args (struct type *mtype, char *prefix, char *varstring, int staticp, struct ui_file *stream); -static void c_type_print_args (struct type *, struct ui_file *); - static void cp_type_print_derivation_info (struct ui_file *, struct type *); static void c_type_print_varspec_prefix (struct type *, struct ui_file *, int, @@ -199,6 +197,23 @@ cp_type_print_method_args (struct type *mtype, char *prefix, char *varstring, fprintf_filtered (stream, "void"); fprintf_filtered (stream, ")"); + + /* For non-static methods, read qualifiers from the type of + THIS. */ + if (!staticp) + { + struct type *domain; + + gdb_assert (nargs > 0); + gdb_assert (TYPE_CODE (args[0].type) == TYPE_CODE_PTR); + domain = TYPE_TARGET_TYPE (args[0].type); + + if (TYPE_CONST (domain)) + fprintf_filtered (stream, " const"); + + if (TYPE_VOLATILE (domain)) + fprintf_filtered (stream, " volatile"); + } } @@ -354,10 +369,12 @@ c_type_print_modifier (struct type *type, struct ui_file *stream, /* Print out the arguments of TYPE, which should have TYPE_CODE_METHOD or TYPE_CODE_FUNC, to STREAM. Artificial arguments, such as "this" - in non-static methods, are displayed. */ + in non-static methods, are displayed if SHOW_ARTIFICIAL is + non-zero. */ -static void -c_type_print_args (struct type *type, struct ui_file *stream) +void +c_type_print_args (struct type *type, struct ui_file *stream, + int show_artificial) { int i, len; struct field *args; @@ -369,6 +386,9 @@ c_type_print_args (struct type *type, struct ui_file *stream) for (i = 0; i < TYPE_NFIELDS (type); i++) { + if (TYPE_FIELD_ARTIFICIAL (type, i) && !show_artificial) + continue; + if (printed_any) { fprintf_filtered (stream, ", "); @@ -559,7 +579,12 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *stream, fprintf_filtered (stream, ")"); fprintf_filtered (stream, "["); - if (TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0 + if (TYPE_ARRAY_BOUND_IS_DWARF_BLOCK (type, 1)) + { + /* No _() - printed sources should not be locale dependent. */ + fprintf_filtered (stream, "variable"); + } + else if (TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0 && !TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type)) fprintf_filtered (stream, "%d", (TYPE_LENGTH (type) @@ -592,7 +617,7 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *stream, if (passed_a_ptr) fprintf_filtered (stream, ")"); if (!demangled_args) - c_type_print_args (type, stream); + c_type_print_args (type, stream, 1); c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show, passed_a_ptr, 0); break; diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c index 0b616f7..3433da2 100644 --- a/gdb/c-valprint.c +++ b/gdb/c-valprint.c @@ -55,6 +55,18 @@ print_function_pointer_address (CORE_ADDR address, struct ui_file *stream, } +/* A helper for textual_element_type. This checks the name of the + typedef. This is bogus but it isn't apparent that the compiler + provides us the help we may need. */ + +static int +textual_name (const char *name) +{ + return (!strcmp (name, "wchar_t") + || !strcmp (name, "char16_t") + || !strcmp (name, "char32_t")); +} + /* Apply a heuristic to decide whether an array of TYPE or a pointer to TYPE should be printed as a textual string. Return non-zero if it should, or zero if it should be treated as an array of integers @@ -77,6 +89,15 @@ textual_element_type (struct type *type, char format) /* TYPE_CODE_CHAR is always textual. */ if (TYPE_CODE (true_type) == TYPE_CODE_CHAR) return 1; + /* Any other character-like types must be integral. */ + if (TYPE_CODE (true_type) != TYPE_CODE_INT) + return 0; + + /* Check the names of the type and the typedef. */ + if (TYPE_NAME (type) && textual_name (TYPE_NAME (type))) + return 1; + if (TYPE_NAME (true_type) && textual_name (TYPE_NAME (true_type))) + return 1; if (format == 's') { @@ -115,7 +136,8 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, { unsigned int i = 0; /* Number of characters printed */ unsigned len; - struct type *elttype; + struct type *elttype, *unresolved_elttype; + struct type *unresolved_type = type; unsigned eltlen; LONGEST val; CORE_ADDR addr; @@ -124,8 +146,9 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, switch (TYPE_CODE (type)) { case TYPE_CODE_ARRAY: - elttype = check_typedef (TYPE_TARGET_TYPE (type)); - if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0) + unresolved_elttype = TYPE_TARGET_TYPE (type); + elttype = check_typedef (unresolved_elttype); + if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (unresolved_elttype) > 0) { eltlen = TYPE_LENGTH (elttype); len = TYPE_LENGTH (type) / eltlen; @@ -135,7 +158,7 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, } /* Print arrays of textual chars with a string syntax. */ - if (textual_element_type (elttype, options->format)) + if (textual_element_type (unresolved_elttype, options->format)) { /* If requested, look for the first null char and only print elements up to it. */ @@ -143,15 +166,19 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, { unsigned int temp_len; - /* Look for a NULL char. */ for (temp_len = 0; - (valaddr + embedded_offset)[temp_len] - && temp_len < len && temp_len < options->print_max; - temp_len++); + (temp_len < len + && temp_len < options->print_max + && extract_unsigned_integer (valaddr + embedded_offset + + temp_len * eltlen, + eltlen) == 0); + ++temp_len) + ; len = temp_len; } - LA_PRINT_STRING (stream, valaddr + embedded_offset, len, eltlen, 0, options); + LA_PRINT_STRING (stream, unresolved_elttype, + valaddr + embedded_offset, len, 0, options); i = len; } else @@ -209,7 +236,8 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, print_function_pointer_address (addr, stream, options->addressprint); break; } - elttype = check_typedef (TYPE_TARGET_TYPE (type)); + unresolved_elttype = TYPE_TARGET_TYPE (type); + elttype = check_typedef (unresolved_elttype); { addr = unpack_pointer (type, valaddr + embedded_offset); print_unpacked_pointer: @@ -228,12 +256,11 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, /* For a pointer to a textual type, also print the string pointed to, unless pointer is null. */ - /* FIXME: need to handle wchar_t here... */ - if (textual_element_type (elttype, options->format) + if (textual_element_type (unresolved_elttype, options->format) && addr != 0) { - i = val_print_string (addr, -1, TYPE_LENGTH (elttype), stream, + i = val_print_string (unresolved_elttype, addr, -1, stream, options); } else if (cp_is_vtbl_member (type)) @@ -268,7 +295,7 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, } else { - wtype = TYPE_TARGET_TYPE (type); + wtype = unresolved_elttype; } vt_val = value_at (wtype, vt_address); common_val_print (vt_val, stream, recurse + 1, options, @@ -442,11 +469,11 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, Since we don't know whether the value is really intended to be used as an integer or a character, print the character equivalent as well. */ - if (textual_element_type (type, options->format)) + if (textual_element_type (unresolved_type, options->format)) { fputs_filtered (" ", stream); LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr + embedded_offset), - stream); + unresolved_type, stream); } } break; @@ -468,7 +495,7 @@ c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, else fprintf_filtered (stream, "%d", (int) val); fputs_filtered (" ", stream); - LA_PRINT_CHAR ((unsigned char) val, stream); + LA_PRINT_CHAR ((unsigned char) val, unresolved_type, stream); } break; @@ -540,7 +567,7 @@ int c_value_print (struct value *val, struct ui_file *stream, const struct value_print_options *options) { - struct type *type, *real_type; + struct type *type, *real_type, *val_type; int full, top, using_enc; struct value_print_options opts = *options; @@ -553,7 +580,11 @@ c_value_print (struct value *val, struct ui_file *stream, C++: if it is a member pointer, we will take care of that when we print it. */ - type = check_typedef (value_type (val)); + /* Preserve the original type before stripping typedefs. We prefer + to pass down the original type when possible, but for local + checks it is better to look past the typedefs. */ + val_type = value_type (val); + type = check_typedef (val_type); if (TYPE_CODE (type) == TYPE_CODE_PTR || TYPE_CODE (type) == TYPE_CODE_REF) @@ -561,11 +592,12 @@ c_value_print (struct value *val, struct ui_file *stream, /* Hack: remove (char *) for char strings. Their type is indicated by the quoted string anyway. (Don't use textual_element_type here; quoted strings - are always exactly (char *). */ - if (TYPE_CODE (type) == TYPE_CODE_PTR - && TYPE_NAME (type) == NULL - && TYPE_NAME (TYPE_TARGET_TYPE (type)) != NULL - && strcmp (TYPE_NAME (TYPE_TARGET_TYPE (type)), "char") == 0) + are always exactly (char *), (wchar_t *), or the like. */ + if (TYPE_CODE (val_type) == TYPE_CODE_PTR + && TYPE_NAME (val_type) == NULL + && TYPE_NAME (TYPE_TARGET_TYPE (val_type)) != NULL + && (strcmp (TYPE_NAME (TYPE_TARGET_TYPE (val_type)), "char") == 0 + || textual_name (TYPE_NAME (TYPE_TARGET_TYPE (val_type))))) { /* Print nothing */ } @@ -608,6 +640,7 @@ c_value_print (struct value *val, struct ui_file *stream, } type_print (type, "", stream, -1); fprintf_filtered (stream, ") "); + val_type = type; } else { @@ -635,7 +668,7 @@ c_value_print (struct value *val, struct ui_file *stream, /* Print out object: enclosing type is same as real_type if full */ return val_print (value_enclosing_type (val), value_contents_all (val), 0, - VALUE_ADDRESS (val), stream, 0, + value_address (val), stream, 0, &opts, current_language); /* Note: When we look up RTTI entries, we don't get any information on const or volatile attributes */ @@ -647,14 +680,14 @@ c_value_print (struct value *val, struct ui_file *stream, TYPE_NAME (value_enclosing_type (val))); return val_print (value_enclosing_type (val), value_contents_all (val), 0, - VALUE_ADDRESS (val), stream, 0, + value_address (val), stream, 0, &opts, current_language); } /* Otherwise, we end up at the return outside this "if" */ } - return val_print (type, value_contents_all (val), + return val_print (val_type, value_contents_all (val), value_embedded_offset (val), - VALUE_ADDRESS (val) + value_offset (val), + value_address (val), stream, 0, &opts, current_language); } diff --git a/gdb/charset-list.h b/gdb/charset-list.h new file mode 100644 index 0000000..59c64c5 --- /dev/null +++ b/gdb/charset-list.h @@ -0,0 +1,1190 @@ +/* List of character set names for GDB. + + Copyright (C) 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Note that the first entry must always be "auto". + The remaining entries were created by running this script: + + iconv -l | sed -e '/[/]...*$/d' -e 's@^\(.*\)//$@"\1", \\@' + + .. and then removing the final backslash. It would be nice to + separate narrow and wide character sets, but there is no good way + to do that. */ +#define DEFAULT_CHARSET_NAMES \ +"auto", \ +"437", \ +"500", \ +"500V1", \ +"850", \ +"851", \ +"852", \ +"855", \ +"856", \ +"857", \ +"860", \ +"861", \ +"862", \ +"863", \ +"864", \ +"865", \ +"866", \ +"866NAV", \ +"869", \ +"874", \ +"904", \ +"1026", \ +"1046", \ +"1047", \ +"8859_1", \ +"8859_2", \ +"8859_3", \ +"8859_4", \ +"8859_5", \ +"8859_6", \ +"8859_7", \ +"8859_8", \ +"8859_9", \ +"10646-1:1993", \ +"ANSI_X3.4-1968", \ +"ANSI_X3.4-1986", \ +"ANSI_X3.4", \ +"ANSI_X3.110-1983", \ +"ANSI_X3.110", \ +"ARABIC", \ +"ARABIC7", \ +"ARMSCII-8", \ +"ASCII", \ +"ASMO-708", \ +"ASMO_449", \ +"BALTIC", \ +"BIG-5", \ +"BIG-FIVE", \ +"BIG5-HKSCS", \ +"BIG5", \ +"BIG5HKSCS", \ +"BIGFIVE", \ +"BRF", \ +"BS_4730", \ +"CA", \ +"CN-BIG5", \ +"CN-GB", \ +"CN", \ +"CP-AR", \ +"CP-GR", \ +"CP-HU", \ +"CP037", \ +"CP038", \ +"CP273", \ +"CP274", \ +"CP275", \ +"CP278", \ +"CP280", \ +"CP281", \ +"CP282", \ +"CP284", \ +"CP285", \ +"CP290", \ +"CP297", \ +"CP367", \ +"CP420", \ +"CP423", \ +"CP424", \ +"CP437", \ +"CP500", \ +"CP737", \ +"CP775", \ +"CP803", \ +"CP813", \ +"CP819", \ +"CP850", \ +"CP851", \ +"CP852", \ +"CP855", \ +"CP856", \ +"CP857", \ +"CP860", \ +"CP861", \ +"CP862", \ +"CP863", \ +"CP864", \ +"CP865", \ +"CP866", \ +"CP866NAV", \ +"CP868", \ +"CP869", \ +"CP870", \ +"CP871", \ +"CP874", \ +"CP875", \ +"CP880", \ +"CP891", \ +"CP901", \ +"CP902", \ +"CP903", \ +"CP904", \ +"CP905", \ +"CP912", \ +"CP915", \ +"CP916", \ +"CP918", \ +"CP920", \ +"CP921", \ +"CP922", \ +"CP930", \ +"CP932", \ +"CP933", \ +"CP935", \ +"CP936", \ +"CP937", \ +"CP939", \ +"CP949", \ +"CP950", \ +"CP1004", \ +"CP1008", \ +"CP1025", \ +"CP1026", \ +"CP1046", \ +"CP1047", \ +"CP1070", \ +"CP1079", \ +"CP1081", \ +"CP1084", \ +"CP1089", \ +"CP1097", \ +"CP1112", \ +"CP1122", \ +"CP1123", \ +"CP1124", \ +"CP1125", \ +"CP1129", \ +"CP1130", \ +"CP1132", \ +"CP1133", \ +"CP1137", \ +"CP1140", \ +"CP1141", \ +"CP1142", \ +"CP1143", \ +"CP1144", \ +"CP1145", \ +"CP1146", \ +"CP1147", \ +"CP1148", \ +"CP1149", \ +"CP1153", \ +"CP1154", \ +"CP1155", \ +"CP1156", \ +"CP1157", \ +"CP1158", \ +"CP1160", \ +"CP1161", \ +"CP1162", \ +"CP1163", \ +"CP1164", \ +"CP1166", \ +"CP1167", \ +"CP1250", \ +"CP1251", \ +"CP1252", \ +"CP1253", \ +"CP1254", \ +"CP1255", \ +"CP1256", \ +"CP1257", \ +"CP1258", \ +"CP1282", \ +"CP1361", \ +"CP1364", \ +"CP1371", \ +"CP1388", \ +"CP1390", \ +"CP1399", \ +"CP4517", \ +"CP4899", \ +"CP4909", \ +"CP4971", \ +"CP5347", \ +"CP9030", \ +"CP9066", \ +"CP9448", \ +"CP10007", \ +"CP12712", \ +"CP16804", \ +"CPIBM861", \ +"CSA7-1", \ +"CSA7-2", \ +"CSASCII", \ +"CSA_T500-1983", \ +"CSA_T500", \ +"CSA_Z243.4-1985-1", \ +"CSA_Z243.4-1985-2", \ +"CSA_Z243.419851", \ +"CSA_Z243.419852", \ +"CSDECMCS", \ +"CSEBCDICATDE", \ +"CSEBCDICATDEA", \ +"CSEBCDICCAFR", \ +"CSEBCDICDKNO", \ +"CSEBCDICDKNOA", \ +"CSEBCDICES", \ +"CSEBCDICESA", \ +"CSEBCDICESS", \ +"CSEBCDICFISE", \ +"CSEBCDICFISEA", \ +"CSEBCDICFR", \ +"CSEBCDICIT", \ +"CSEBCDICPT", \ +"CSEBCDICUK", \ +"CSEBCDICUS", \ +"CSEUCKR", \ +"CSEUCPKDFMTJAPANESE", \ +"CSGB2312", \ +"CSHPROMAN8", \ +"CSIBM037", \ +"CSIBM038", \ +"CSIBM273", \ +"CSIBM274", \ +"CSIBM275", \ +"CSIBM277", \ +"CSIBM278", \ +"CSIBM280", \ +"CSIBM281", \ +"CSIBM284", \ +"CSIBM285", \ +"CSIBM290", \ +"CSIBM297", \ +"CSIBM420", \ +"CSIBM423", \ +"CSIBM424", \ +"CSIBM500", \ +"CSIBM803", \ +"CSIBM851", \ +"CSIBM855", \ +"CSIBM856", \ +"CSIBM857", \ +"CSIBM860", \ +"CSIBM863", \ +"CSIBM864", \ +"CSIBM865", \ +"CSIBM866", \ +"CSIBM868", \ +"CSIBM869", \ +"CSIBM870", \ +"CSIBM871", \ +"CSIBM880", \ +"CSIBM891", \ +"CSIBM901", \ +"CSIBM902", \ +"CSIBM903", \ +"CSIBM904", \ +"CSIBM905", \ +"CSIBM918", \ +"CSIBM921", \ +"CSIBM922", \ +"CSIBM930", \ +"CSIBM932", \ +"CSIBM933", \ +"CSIBM935", \ +"CSIBM937", \ +"CSIBM939", \ +"CSIBM943", \ +"CSIBM1008", \ +"CSIBM1025", \ +"CSIBM1026", \ +"CSIBM1097", \ +"CSIBM1112", \ +"CSIBM1122", \ +"CSIBM1123", \ +"CSIBM1124", \ +"CSIBM1129", \ +"CSIBM1130", \ +"CSIBM1132", \ +"CSIBM1133", \ +"CSIBM1137", \ +"CSIBM1140", \ +"CSIBM1141", \ +"CSIBM1142", \ +"CSIBM1143", \ +"CSIBM1144", \ +"CSIBM1145", \ +"CSIBM1146", \ +"CSIBM1147", \ +"CSIBM1148", \ +"CSIBM1149", \ +"CSIBM1153", \ +"CSIBM1154", \ +"CSIBM1155", \ +"CSIBM1156", \ +"CSIBM1157", \ +"CSIBM1158", \ +"CSIBM1160", \ +"CSIBM1161", \ +"CSIBM1163", \ +"CSIBM1164", \ +"CSIBM1166", \ +"CSIBM1167", \ +"CSIBM1364", \ +"CSIBM1371", \ +"CSIBM1388", \ +"CSIBM1390", \ +"CSIBM1399", \ +"CSIBM4517", \ +"CSIBM4899", \ +"CSIBM4909", \ +"CSIBM4971", \ +"CSIBM5347", \ +"CSIBM9030", \ +"CSIBM9066", \ +"CSIBM9448", \ +"CSIBM12712", \ +"CSIBM16804", \ +"CSIBM11621162", \ +"CSISO4UNITEDKINGDOM", \ +"CSISO10SWEDISH", \ +"CSISO11SWEDISHFORNAMES", \ +"CSISO14JISC6220RO", \ +"CSISO15ITALIAN", \ +"CSISO16PORTUGESE", \ +"CSISO17SPANISH", \ +"CSISO18GREEK7OLD", \ +"CSISO19LATINGREEK", \ +"CSISO21GERMAN", \ +"CSISO25FRENCH", \ +"CSISO27LATINGREEK1", \ +"CSISO49INIS", \ +"CSISO50INIS8", \ +"CSISO51INISCYRILLIC", \ +"CSISO58GB1988", \ +"CSISO60DANISHNORWEGIAN", \ +"CSISO60NORWEGIAN1", \ +"CSISO61NORWEGIAN2", \ +"CSISO69FRENCH", \ +"CSISO84PORTUGUESE2", \ +"CSISO85SPANISH2", \ +"CSISO86HUNGARIAN", \ +"CSISO88GREEK7", \ +"CSISO89ASMO449", \ +"CSISO90", \ +"CSISO92JISC62991984B", \ +"CSISO99NAPLPS", \ +"CSISO103T618BIT", \ +"CSISO111ECMACYRILLIC", \ +"CSISO121CANADIAN1", \ +"CSISO122CANADIAN2", \ +"CSISO139CSN369103", \ +"CSISO141JUSIB1002", \ +"CSISO143IECP271", \ +"CSISO150", \ +"CSISO150GREEKCCITT", \ +"CSISO151CUBA", \ +"CSISO153GOST1976874", \ +"CSISO646DANISH", \ +"CSISO2022CN", \ +"CSISO2022JP", \ +"CSISO2022JP2", \ +"CSISO2022KR", \ +"CSISO2033", \ +"CSISO5427CYRILLIC", \ +"CSISO5427CYRILLIC1981", \ +"CSISO5428GREEK", \ +"CSISO10367BOX", \ +"CSISOLATIN1", \ +"CSISOLATIN2", \ +"CSISOLATIN3", \ +"CSISOLATIN4", \ +"CSISOLATIN5", \ +"CSISOLATIN6", \ +"CSISOLATINARABIC", \ +"CSISOLATINCYRILLIC", \ +"CSISOLATINGREEK", \ +"CSISOLATINHEBREW", \ +"CSKOI8R", \ +"CSKSC5636", \ +"CSMACINTOSH", \ +"CSNATSDANO", \ +"CSNATSSEFI", \ +"CSN_369103", \ +"CSPC8CODEPAGE437", \ +"CSPC775BALTIC", \ +"CSPC850MULTILINGUAL", \ +"CSPC862LATINHEBREW", \ +"CSPCP852", \ +"CSSHIFTJIS", \ +"CSUCS4", \ +"CSUNICODE", \ +"CSWINDOWS31J", \ +"CUBA", \ +"CWI-2", \ +"CWI", \ +"CYRILLIC", \ +"DE", \ +"DEC-MCS", \ +"DEC", \ +"DECMCS", \ +"DIN_66003", \ +"DK", \ +"DS2089", \ +"DS_2089", \ +"E13B", \ +"EBCDIC-AT-DE-A", \ +"EBCDIC-AT-DE", \ +"EBCDIC-BE", \ +"EBCDIC-BR", \ +"EBCDIC-CA-FR", \ +"EBCDIC-CP-AR1", \ +"EBCDIC-CP-AR2", \ +"EBCDIC-CP-BE", \ +"EBCDIC-CP-CA", \ +"EBCDIC-CP-CH", \ +"EBCDIC-CP-DK", \ +"EBCDIC-CP-ES", \ +"EBCDIC-CP-FI", \ +"EBCDIC-CP-FR", \ +"EBCDIC-CP-GB", \ +"EBCDIC-CP-GR", \ +"EBCDIC-CP-HE", \ +"EBCDIC-CP-IS", \ +"EBCDIC-CP-IT", \ +"EBCDIC-CP-NL", \ +"EBCDIC-CP-NO", \ +"EBCDIC-CP-ROECE", \ +"EBCDIC-CP-SE", \ +"EBCDIC-CP-TR", \ +"EBCDIC-CP-US", \ +"EBCDIC-CP-WT", \ +"EBCDIC-CP-YU", \ +"EBCDIC-CYRILLIC", \ +"EBCDIC-DK-NO-A", \ +"EBCDIC-DK-NO", \ +"EBCDIC-ES-A", \ +"EBCDIC-ES-S", \ +"EBCDIC-ES", \ +"EBCDIC-FI-SE-A", \ +"EBCDIC-FI-SE", \ +"EBCDIC-FR", \ +"EBCDIC-GREEK", \ +"EBCDIC-INT", \ +"EBCDIC-INT1", \ +"EBCDIC-IS-FRISS", \ +"EBCDIC-IT", \ +"EBCDIC-JP-E", \ +"EBCDIC-JP-KANA", \ +"EBCDIC-PT", \ +"EBCDIC-UK", \ +"EBCDIC-US", \ +"EBCDICATDE", \ +"EBCDICATDEA", \ +"EBCDICCAFR", \ +"EBCDICDKNO", \ +"EBCDICDKNOA", \ +"EBCDICES", \ +"EBCDICESA", \ +"EBCDICESS", \ +"EBCDICFISE", \ +"EBCDICFISEA", \ +"EBCDICFR", \ +"EBCDICISFRISS", \ +"EBCDICIT", \ +"EBCDICPT", \ +"EBCDICUK", \ +"EBCDICUS", \ +"ECMA-114", \ +"ECMA-118", \ +"ECMA-128", \ +"ECMA-CYRILLIC", \ +"ECMACYRILLIC", \ +"ELOT_928", \ +"ES", \ +"ES2", \ +"EUC-CN", \ +"EUC-JISX0213", \ +"EUC-JP-MS", \ +"EUC-JP", \ +"EUC-KR", \ +"EUC-TW", \ +"EUCCN", \ +"EUCJP-MS", \ +"EUCJP-OPEN", \ +"EUCJP-WIN", \ +"EUCJP", \ +"EUCKR", \ +"EUCTW", \ +"FI", \ +"FR", \ +"GB", \ +"GB2312", \ +"GB13000", \ +"GB18030", \ +"GBK", \ +"GB_1988-80", \ +"GB_198880", \ +"GEORGIAN-ACADEMY", \ +"GEORGIAN-PS", \ +"GOST_19768-74", \ +"GOST_19768", \ +"GOST_1976874", \ +"GREEK-CCITT", \ +"GREEK", \ +"GREEK7-OLD", \ +"GREEK7", \ +"GREEK7OLD", \ +"GREEK8", \ +"GREEKCCITT", \ +"HEBREW", \ +"HP-GREEK8", \ +"HP-ROMAN8", \ +"HP-ROMAN9", \ +"HP-THAI8", \ +"HP-TURKISH8", \ +"HPGREEK8", \ +"HPROMAN8", \ +"HPROMAN9", \ +"HPTHAI8", \ +"HPTURKISH8", \ +"HU", \ +"IBM-803", \ +"IBM-856", \ +"IBM-901", \ +"IBM-902", \ +"IBM-921", \ +"IBM-922", \ +"IBM-930", \ +"IBM-932", \ +"IBM-933", \ +"IBM-935", \ +"IBM-937", \ +"IBM-939", \ +"IBM-943", \ +"IBM-1008", \ +"IBM-1025", \ +"IBM-1046", \ +"IBM-1047", \ +"IBM-1097", \ +"IBM-1112", \ +"IBM-1122", \ +"IBM-1123", \ +"IBM-1124", \ +"IBM-1129", \ +"IBM-1130", \ +"IBM-1132", \ +"IBM-1133", \ +"IBM-1137", \ +"IBM-1140", \ +"IBM-1141", \ +"IBM-1142", \ +"IBM-1143", \ +"IBM-1144", \ +"IBM-1145", \ +"IBM-1146", \ +"IBM-1147", \ +"IBM-1148", \ +"IBM-1149", \ +"IBM-1153", \ +"IBM-1154", \ +"IBM-1155", \ +"IBM-1156", \ +"IBM-1157", \ +"IBM-1158", \ +"IBM-1160", \ +"IBM-1161", \ +"IBM-1162", \ +"IBM-1163", \ +"IBM-1164", \ +"IBM-1166", \ +"IBM-1167", \ +"IBM-1364", \ +"IBM-1371", \ +"IBM-1388", \ +"IBM-1390", \ +"IBM-1399", \ +"IBM-4517", \ +"IBM-4899", \ +"IBM-4909", \ +"IBM-4971", \ +"IBM-5347", \ +"IBM-9030", \ +"IBM-9066", \ +"IBM-9448", \ +"IBM-12712", \ +"IBM-16804", \ +"IBM037", \ +"IBM038", \ +"IBM256", \ +"IBM273", \ +"IBM274", \ +"IBM275", \ +"IBM277", \ +"IBM278", \ +"IBM280", \ +"IBM281", \ +"IBM284", \ +"IBM285", \ +"IBM290", \ +"IBM297", \ +"IBM367", \ +"IBM420", \ +"IBM423", \ +"IBM424", \ +"IBM437", \ +"IBM500", \ +"IBM775", \ +"IBM803", \ +"IBM813", \ +"IBM819", \ +"IBM848", \ +"IBM850", \ +"IBM851", \ +"IBM852", \ +"IBM855", \ +"IBM856", \ +"IBM857", \ +"IBM860", \ +"IBM861", \ +"IBM862", \ +"IBM863", \ +"IBM864", \ +"IBM865", \ +"IBM866", \ +"IBM866NAV", \ +"IBM868", \ +"IBM869", \ +"IBM870", \ +"IBM871", \ +"IBM874", \ +"IBM875", \ +"IBM880", \ +"IBM891", \ +"IBM901", \ +"IBM902", \ +"IBM903", \ +"IBM904", \ +"IBM905", \ +"IBM912", \ +"IBM915", \ +"IBM916", \ +"IBM918", \ +"IBM920", \ +"IBM921", \ +"IBM922", \ +"IBM930", \ +"IBM932", \ +"IBM933", \ +"IBM935", \ +"IBM937", \ +"IBM939", \ +"IBM943", \ +"IBM1004", \ +"IBM1008", \ +"IBM1025", \ +"IBM1026", \ +"IBM1046", \ +"IBM1047", \ +"IBM1089", \ +"IBM1097", \ +"IBM1112", \ +"IBM1122", \ +"IBM1123", \ +"IBM1124", \ +"IBM1129", \ +"IBM1130", \ +"IBM1132", \ +"IBM1133", \ +"IBM1137", \ +"IBM1140", \ +"IBM1141", \ +"IBM1142", \ +"IBM1143", \ +"IBM1144", \ +"IBM1145", \ +"IBM1146", \ +"IBM1147", \ +"IBM1148", \ +"IBM1149", \ +"IBM1153", \ +"IBM1154", \ +"IBM1155", \ +"IBM1156", \ +"IBM1157", \ +"IBM1158", \ +"IBM1160", \ +"IBM1161", \ +"IBM1162", \ +"IBM1163", \ +"IBM1164", \ +"IBM1166", \ +"IBM1167", \ +"IBM1364", \ +"IBM1371", \ +"IBM1388", \ +"IBM1390", \ +"IBM1399", \ +"IBM4517", \ +"IBM4899", \ +"IBM4909", \ +"IBM4971", \ +"IBM5347", \ +"IBM9030", \ +"IBM9066", \ +"IBM9448", \ +"IBM12712", \ +"IBM16804", \ +"IEC_P27-1", \ +"IEC_P271", \ +"INIS-8", \ +"INIS-CYRILLIC", \ +"INIS", \ +"INIS8", \ +"INISCYRILLIC", \ +"ISIRI-3342", \ +"ISIRI3342", \ +"ISO-2022-CN-EXT", \ +"ISO-2022-CN", \ +"ISO-2022-JP-2", \ +"ISO-2022-JP-3", \ +"ISO-2022-JP", \ +"ISO-2022-KR", \ +"ISO-8859-1", \ +"ISO-8859-2", \ +"ISO-8859-3", \ +"ISO-8859-4", \ +"ISO-8859-5", \ +"ISO-8859-6", \ +"ISO-8859-7", \ +"ISO-8859-8", \ +"ISO-8859-9", \ +"ISO-8859-9E", \ +"ISO-8859-10", \ +"ISO-8859-11", \ +"ISO-8859-13", \ +"ISO-8859-14", \ +"ISO-8859-15", \ +"ISO-8859-16", \ +"ISO-10646", \ +"ISO-CELTIC", \ +"ISO-IR-4", \ +"ISO-IR-6", \ +"ISO-IR-8-1", \ +"ISO-IR-9-1", \ +"ISO-IR-10", \ +"ISO-IR-11", \ +"ISO-IR-14", \ +"ISO-IR-15", \ +"ISO-IR-16", \ +"ISO-IR-17", \ +"ISO-IR-18", \ +"ISO-IR-19", \ +"ISO-IR-21", \ +"ISO-IR-25", \ +"ISO-IR-27", \ +"ISO-IR-37", \ +"ISO-IR-49", \ +"ISO-IR-50", \ +"ISO-IR-51", \ +"ISO-IR-54", \ +"ISO-IR-55", \ +"ISO-IR-57", \ +"ISO-IR-60", \ +"ISO-IR-61", \ +"ISO-IR-69", \ +"ISO-IR-84", \ +"ISO-IR-85", \ +"ISO-IR-86", \ +"ISO-IR-88", \ +"ISO-IR-89", \ +"ISO-IR-90", \ +"ISO-IR-92", \ +"ISO-IR-98", \ +"ISO-IR-99", \ +"ISO-IR-100", \ +"ISO-IR-101", \ +"ISO-IR-103", \ +"ISO-IR-109", \ +"ISO-IR-110", \ +"ISO-IR-111", \ +"ISO-IR-121", \ +"ISO-IR-122", \ +"ISO-IR-126", \ +"ISO-IR-127", \ +"ISO-IR-138", \ +"ISO-IR-139", \ +"ISO-IR-141", \ +"ISO-IR-143", \ +"ISO-IR-144", \ +"ISO-IR-148", \ +"ISO-IR-150", \ +"ISO-IR-151", \ +"ISO-IR-153", \ +"ISO-IR-155", \ +"ISO-IR-156", \ +"ISO-IR-157", \ +"ISO-IR-166", \ +"ISO-IR-179", \ +"ISO-IR-193", \ +"ISO-IR-197", \ +"ISO-IR-199", \ +"ISO-IR-203", \ +"ISO-IR-209", \ +"ISO-IR-226", \ +"ISO646-CA", \ +"ISO646-CA2", \ +"ISO646-CN", \ +"ISO646-CU", \ +"ISO646-DE", \ +"ISO646-DK", \ +"ISO646-ES", \ +"ISO646-ES2", \ +"ISO646-FI", \ +"ISO646-FR", \ +"ISO646-FR1", \ +"ISO646-GB", \ +"ISO646-HU", \ +"ISO646-IT", \ +"ISO646-JP-OCR-B", \ +"ISO646-JP", \ +"ISO646-KR", \ +"ISO646-NO", \ +"ISO646-NO2", \ +"ISO646-PT", \ +"ISO646-PT2", \ +"ISO646-SE", \ +"ISO646-SE2", \ +"ISO646-US", \ +"ISO646-YU", \ +"ISO2022CN", \ +"ISO2022CNEXT", \ +"ISO2022JP", \ +"ISO2022JP2", \ +"ISO2022KR", \ +"ISO6937", \ +"ISO8859-1", \ +"ISO8859-2", \ +"ISO8859-3", \ +"ISO8859-4", \ +"ISO8859-5", \ +"ISO8859-6", \ +"ISO8859-7", \ +"ISO8859-8", \ +"ISO8859-9", \ +"ISO8859-9E", \ +"ISO8859-10", \ +"ISO8859-11", \ +"ISO8859-13", \ +"ISO8859-14", \ +"ISO8859-15", \ +"ISO8859-16", \ +"ISO11548-1", \ +"ISO88591", \ +"ISO88592", \ +"ISO88593", \ +"ISO88594", \ +"ISO88595", \ +"ISO88596", \ +"ISO88597", \ +"ISO88598", \ +"ISO88599", \ +"ISO88599E", \ +"ISO885910", \ +"ISO885911", \ +"ISO885913", \ +"ISO885914", \ +"ISO885915", \ +"ISO885916", \ +"ISO_646.IRV:1991", \ +"ISO_2033-1983", \ +"ISO_2033", \ +"ISO_5427-EXT", \ +"ISO_5427", \ +"ISO_5427:1981", \ +"ISO_5427EXT", \ +"ISO_5428", \ +"ISO_5428:1980", \ +"ISO_6937-2", \ +"ISO_6937-2:1983", \ +"ISO_6937", \ +"ISO_6937:1992", \ +"ISO_8859-1", \ +"ISO_8859-1:1987", \ +"ISO_8859-2", \ +"ISO_8859-2:1987", \ +"ISO_8859-3", \ +"ISO_8859-3:1988", \ +"ISO_8859-4", \ +"ISO_8859-4:1988", \ +"ISO_8859-5", \ +"ISO_8859-5:1988", \ +"ISO_8859-6", \ +"ISO_8859-6:1987", \ +"ISO_8859-7", \ +"ISO_8859-7:1987", \ +"ISO_8859-7:2003", \ +"ISO_8859-8", \ +"ISO_8859-8:1988", \ +"ISO_8859-9", \ +"ISO_8859-9:1989", \ +"ISO_8859-9E", \ +"ISO_8859-10", \ +"ISO_8859-10:1992", \ +"ISO_8859-14", \ +"ISO_8859-14:1998", \ +"ISO_8859-15", \ +"ISO_8859-15:1998", \ +"ISO_8859-16", \ +"ISO_8859-16:2001", \ +"ISO_9036", \ +"ISO_10367-BOX", \ +"ISO_10367BOX", \ +"ISO_11548-1", \ +"ISO_69372", \ +"IT", \ +"JIS_C6220-1969-RO", \ +"JIS_C6229-1984-B", \ +"JIS_C62201969RO", \ +"JIS_C62291984B", \ +"JOHAB", \ +"JP-OCR-B", \ +"JP", \ +"JS", \ +"JUS_I.B1.002", \ +"KOI-7", \ +"KOI-8", \ +"KOI8-R", \ +"KOI8-RU", \ +"KOI8-T", \ +"KOI8-U", \ +"KOI8", \ +"KOI8R", \ +"KOI8U", \ +"KSC5636", \ +"L1", \ +"L2", \ +"L3", \ +"L4", \ +"L5", \ +"L6", \ +"L7", \ +"L8", \ +"L10", \ +"LATIN-9", \ +"LATIN-GREEK-1", \ +"LATIN-GREEK", \ +"LATIN1", \ +"LATIN2", \ +"LATIN3", \ +"LATIN4", \ +"LATIN5", \ +"LATIN6", \ +"LATIN7", \ +"LATIN8", \ +"LATIN10", \ +"LATINGREEK", \ +"LATINGREEK1", \ +"MAC-CENTRALEUROPE", \ +"MAC-CYRILLIC", \ +"MAC-IS", \ +"MAC-SAMI", \ +"MAC-UK", \ +"MAC", \ +"MACCYRILLIC", \ +"MACINTOSH", \ +"MACIS", \ +"MACUK", \ +"MACUKRAINIAN", \ +"MIK", \ +"MS-ANSI", \ +"MS-ARAB", \ +"MS-CYRL", \ +"MS-EE", \ +"MS-GREEK", \ +"MS-HEBR", \ +"MS-MAC-CYRILLIC", \ +"MS-TURK", \ +"MS932", \ +"MS936", \ +"MSCP949", \ +"MSCP1361", \ +"MSMACCYRILLIC", \ +"MSZ_7795.3", \ +"MS_KANJI", \ +"NAPLPS", \ +"NATS-DANO", \ +"NATS-SEFI", \ +"NATSDANO", \ +"NATSSEFI", \ +"NC_NC0010", \ +"NC_NC00-10", \ +"NC_NC00-10:81", \ +"NF_Z_62-010", \ +"NF_Z_62-010_(1973)", \ +"NF_Z_62-010_1973", \ +"NF_Z_62010", \ +"NF_Z_62010_1973", \ +"NO", \ +"NO2", \ +"NS_4551-1", \ +"NS_4551-2", \ +"NS_45511", \ +"NS_45512", \ +"OS2LATIN1", \ +"OSF00010001", \ +"OSF00010002", \ +"OSF00010003", \ +"OSF00010004", \ +"OSF00010005", \ +"OSF00010006", \ +"OSF00010007", \ +"OSF00010008", \ +"OSF00010009", \ +"OSF0001000A", \ +"OSF00010020", \ +"OSF00010100", \ +"OSF00010101", \ +"OSF00010102", \ +"OSF00010104", \ +"OSF00010105", \ +"OSF00010106", \ +"OSF00030010", \ +"OSF0004000A", \ +"OSF0005000A", \ +"OSF05010001", \ +"OSF100201A4", \ +"OSF100201A8", \ +"OSF100201B5", \ +"OSF100201F4", \ +"OSF100203B5", \ +"OSF1002011C", \ +"OSF1002011D", \ +"OSF1002035D", \ +"OSF1002035E", \ +"OSF1002035F", \ +"OSF1002036B", \ +"OSF1002037B", \ +"OSF10010001", \ +"OSF10010004", \ +"OSF10010006", \ +"OSF10020025", \ +"OSF10020111", \ +"OSF10020115", \ +"OSF10020116", \ +"OSF10020118", \ +"OSF10020122", \ +"OSF10020129", \ +"OSF10020352", \ +"OSF10020354", \ +"OSF10020357", \ +"OSF10020359", \ +"OSF10020360", \ +"OSF10020364", \ +"OSF10020365", \ +"OSF10020366", \ +"OSF10020367", \ +"OSF10020370", \ +"OSF10020387", \ +"OSF10020388", \ +"OSF10020396", \ +"OSF10020402", \ +"OSF10020417", \ +"PT", \ +"PT2", \ +"PT154", \ +"R8", \ +"R9", \ +"RK1048", \ +"ROMAN8", \ +"ROMAN9", \ +"RUSCII", \ +"SE", \ +"SE2", \ +"SEN_850200_B", \ +"SEN_850200_C", \ +"SHIFT-JIS", \ +"SHIFT_JIS", \ +"SHIFT_JISX0213", \ +"SJIS-OPEN", \ +"SJIS-WIN", \ +"SJIS", \ +"SS636127", \ +"STRK1048-2002", \ +"ST_SEV_358-88", \ +"T.61-8BIT", \ +"T.61", \ +"T.618BIT", \ +"TCVN-5712", \ +"TCVN", \ +"TCVN5712-1", \ +"TCVN5712-1:1993", \ +"THAI8", \ +"TIS-620", \ +"TIS620-0", \ +"TIS620.2529-1", \ +"TIS620.2533-0", \ +"TIS620", \ +"TS-5881", \ +"TSCII", \ +"TURKISH8", \ +"UCS-2", \ +"UCS-2BE", \ +"UCS-2LE", \ +"UCS-4", \ +"UCS-4BE", \ +"UCS-4LE", \ +"UCS2", \ +"UCS4", \ +"UHC", \ +"UJIS", \ +"UK", \ +"UNICODE", \ +"UNICODEBIG", \ +"UNICODELITTLE", \ +"US-ASCII", \ +"US", \ +"UTF-7", \ +"UTF-8", \ +"UTF-16", \ +"UTF-16BE", \ +"UTF-16LE", \ +"UTF-32", \ +"UTF-32BE", \ +"UTF-32LE", \ +"UTF7", \ +"UTF8", \ +"UTF16", \ +"UTF16BE", \ +"UTF16LE", \ +"UTF32", \ +"UTF32BE", \ +"UTF32LE", \ +"VISCII", \ +"WCHAR_T", \ +"WIN-SAMI-2", \ +"WINBALTRIM", \ +"WINDOWS-31J", \ +"WINDOWS-874", \ +"WINDOWS-936", \ +"WINDOWS-1250", \ +"WINDOWS-1251", \ +"WINDOWS-1252", \ +"WINDOWS-1253", \ +"WINDOWS-1254", \ +"WINDOWS-1255", \ +"WINDOWS-1256", \ +"WINDOWS-1257", \ +"WINDOWS-1258", \ +"WINSAMI2", \ +"WS2", \ +"YU", diff --git a/gdb/charset.c b/gdb/charset.c index 32eb9c3..4850fbf 100644 --- a/gdb/charset.c +++ b/gdb/charset.c @@ -21,6 +21,9 @@ #include "charset.h" #include "gdbcmd.h" #include "gdb_assert.h" +#include "gdb_obstack.h" +#include "charset-list.h" +#include "vec.h" #include #include "gdb_string.h" @@ -33,15 +36,20 @@ /* How GDB's character set support works - GDB has two global settings: + GDB has three global settings: - The `current host character set' is the character set GDB should use in talking to the user, and which (hopefully) the user's - terminal knows how to display properly. + terminal knows how to display properly. Most users should not + change this. - The `current target character set' is the character set the program being debugged uses. + - The `current target wide character set' is the wide character set + the program being debugged uses, that is, the encoding used for + wchar_t. + There are commands to set each of these, and mechanisms for choosing reasonable default values. GDB has a global list of character sets that it can use as its host or target character @@ -57,118 +65,37 @@ characters the user enters in expressions (mostly host->target conversions), - and so on. - - Now, many of these operations are specific to a particular - host/target character set pair. If GDB supports N character sets, - there are N^2 possible pairs. This means that, the larger GDB's - repertoire of character sets gets, the more expensive it gets to add - new character sets. - - To make sure that GDB can do the right thing for every possible - pairing of host and target character set, while still allowing - GDB's repertoire to scale, we use a two-tiered approach: - - - We maintain a global table of "translations" --- groups of - functions specific to a particular pair of character sets. - - - However, a translation can be incomplete: some functions can be - omitted. Where there is not a translation to specify exactly - what function to use, we provide reasonable defaults. The - default behaviors try to use the "iconv" library functions, which - support a wide range of character sets. However, even if iconv - is not available, there are fallbacks to support trivial - translations: when the host and target character sets are the - same. */ - - -/* The character set and translation structures. */ - - -/* A character set GDB knows about. GDB only supports character sets - with stateless encodings, in which every character is one byte - long. */ -struct charset { - - /* A singly-linked list of all known charsets. */ - struct charset *next; - - /* The name of the character set. Comparisons on character set - names are case-sensitive. */ - const char *name; - - /* Non-zero iff this character set can be used as a host character - set. At present, GDB basically assumes that the host character - set is a superset of ASCII. */ - int valid_host_charset; - - /* Pointers to charset-specific functions that depend only on a - single character set, and data pointers to pass to them. */ - int (*host_char_print_literally) (void *baton, - int host_char); - void *host_char_print_literally_baton; - - int (*target_char_to_control_char) (void *baton, - int target_char, - int *target_ctrl_char); - void *target_char_to_control_char_baton; -}; - - -/* A translation from one character set to another. */ -struct translation { - - /* A singly-linked list of all known translations. */ - struct translation *next; - - /* This structure describes functions going from the FROM character - set to the TO character set. Comparisons on character set names - are case-sensitive. */ - const char *from, *to; - - /* Pointers to translation-specific functions, and data pointers to - pass to them. These pointers can be zero, indicating that GDB - should fall back on the default behavior. We hope the default - behavior will be correct for many from/to pairs, reducing the - number of translations that need to be registered explicitly. */ - - /* TARGET_CHAR is in the `from' charset. - Returns a string in the `to' charset. */ - const char *(*c_target_char_has_backslash_escape) (void *baton, - int target_char); - void *c_target_char_has_backslash_escape_baton; - - /* HOST_CHAR is in the `from' charset. - TARGET_CHAR points to a char in the `to' charset. */ - int (*c_parse_backslash) (void *baton, int host_char, int *target_char); - void *c_parse_backslash_baton; - - /* This is used for the host_char_to_target and target_char_to_host - functions. */ - int (*convert_char) (void *baton, int from, int *to); - void *convert_char_baton; -}; - + and so on. + + To avoid excessive code duplication and maintenance efforts, + GDB simply requires a capable iconv function. Users on platforms + without a suitable iconv can use the GNU iconv library. */ /* The global lists of character sets and translations. */ -#ifndef GDB_DEFAULT_HOST_CHARSET -#define GDB_DEFAULT_HOST_CHARSET "ISO-8859-1" -#endif - #ifndef GDB_DEFAULT_TARGET_CHARSET #define GDB_DEFAULT_TARGET_CHARSET "ISO-8859-1" #endif -static const char *host_charset_name = GDB_DEFAULT_HOST_CHARSET; +#ifndef GDB_DEFAULT_TARGET_WIDE_CHARSET +#define GDB_DEFAULT_TARGET_WIDE_CHARSET "UCS-4" +#endif + +static const char *auto_host_charset_name = GDB_DEFAULT_HOST_CHARSET; +static const char *host_charset_name = "auto"; static void show_host_charset_name (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("The host character set is \"%s\".\n"), value); + if (!strcmp (value, "auto")) + fprintf_filtered (file, + _("The host character set is \"auto; currently %s\".\n"), + auto_host_charset_name); + else + fprintf_filtered (file, _("The host character set is \"%s\".\n"), value); } static const char *target_charset_name = GDB_DEFAULT_TARGET_CHARSET; @@ -180,1060 +107,534 @@ show_target_charset_name (struct ui_file *file, int from_tty, value); } - -static const char *host_charset_enum[] = +static const char *target_wide_charset_name = GDB_DEFAULT_TARGET_WIDE_CHARSET; +static void +show_target_wide_charset_name (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) { - "ASCII", - "ISO-8859-1", - 0 -}; + fprintf_filtered (file, _("The target wide character set is \"%s\".\n"), + value); +} -static const char *target_charset_enum[] = +static const char *default_charset_names[] = { - "ASCII", - "ISO-8859-1", - "EBCDIC-US", - "IBM1047", + DEFAULT_CHARSET_NAMES 0 }; -/* The global list of all the charsets GDB knows about. */ -static struct charset *all_charsets; +static const char **charset_enum; + +/* If the target wide character set has big- or little-endian + variants, these are the corresponding names. */ +static const char *target_wide_charset_be_name; +static const char *target_wide_charset_le_name; -static void -register_charset (struct charset *cs) -{ - struct charset **ptr; - - /* Put the new charset on the end, so that the list ends up in the - same order as the registrations in the _initialize function. */ - for (ptr = &all_charsets; *ptr; ptr = &(*ptr)->next) - ; - - cs->next = 0; - *ptr = cs; -} - +/* A helper function for validate which sets the target wide big- and + little-endian character set names, if possible. */ -static struct charset * -lookup_charset (const char *name) +static void +set_be_le_names (void) { - struct charset *cs; + int i, len; - for (cs = all_charsets; cs; cs = cs->next) - if (! strcmp (name, cs->name)) - return cs; + target_wide_charset_le_name = NULL; + target_wide_charset_be_name = NULL; - return NULL; + len = strlen (target_wide_charset_name); + for (i = 0; charset_enum[i]; ++i) + { + if (strncmp (target_wide_charset_name, charset_enum[i], len)) + continue; + if ((charset_enum[i][len] == 'B' + || charset_enum[i][len] == 'L') + && charset_enum[i][len + 1] == 'E' + && charset_enum[i][len + 2] == '\0') + { + if (charset_enum[i][len] == 'B') + target_wide_charset_be_name = charset_enum[i]; + else + target_wide_charset_le_name = charset_enum[i]; + } + } } - -/* The global list of translations. */ -static struct translation *all_translations; - +/* 'Set charset', 'set host-charset', 'set target-charset', 'set + target-wide-charset', 'set charset' sfunc's. */ static void -register_translation (struct translation *t) +validate (void) { - t->next = all_translations; - all_translations = t; -} - - -static struct translation * -lookup_translation (const char *from, const char *to) -{ - struct translation *t; - - for (t = all_translations; t; t = t->next) - if (! strcmp (from, t->from) - && ! strcmp (to, t->to)) - return t; + iconv_t desc; + const char *host_cset = host_charset (); - return 0; -} - - - -/* Constructing charsets. */ - -/* Allocate, initialize and return a straightforward charset. - Use this function, rather than creating the structures yourself, - so that we can add new fields to the structure in the future without - having to tweak all the old charset descriptions. */ -static struct charset * -simple_charset (const char *name, - int valid_host_charset, - int (*host_char_print_literally) (void *baton, int host_char), - void *host_char_print_literally_baton, - int (*target_char_to_control_char) (void *baton, - int target_char, - int *target_ctrl_char), - void *target_char_to_control_char_baton) -{ - struct charset *cs = xmalloc (sizeof (*cs)); + desc = iconv_open (target_wide_charset_name, host_cset); + if (desc == (iconv_t) -1) + error ("Cannot convert between character sets `%s' and `%s'", + target_wide_charset_name, host_cset); + iconv_close (desc); - memset (cs, 0, sizeof (*cs)); - cs->name = name; - cs->valid_host_charset = valid_host_charset; - cs->host_char_print_literally = host_char_print_literally; - cs->host_char_print_literally_baton = host_char_print_literally_baton; - cs->target_char_to_control_char = target_char_to_control_char; - cs->target_char_to_control_char_baton = target_char_to_control_char_baton; + desc = iconv_open (target_charset_name, host_cset); + if (desc == (iconv_t) -1) + error ("Cannot convert between character sets `%s' and `%s'", + target_charset_name, host_cset); + iconv_close (desc); - return cs; + set_be_le_names (); } - - -/* ASCII functions. */ - -static int -ascii_print_literally (void *baton, int c) +/* This is the sfunc for the 'set charset' command. */ +static void +set_charset_sfunc (char *charset, int from_tty, struct cmd_list_element *c) { - c &= 0xff; - - return (0x20 <= c && c <= 0x7e); + /* CAREFUL: set the target charset here as well. */ + target_charset_name = host_charset_name; + validate (); } - -static int -ascii_to_control (void *baton, int c, int *ctrl_char) +/* 'set host-charset' command sfunc. We need a wrapper here because + the function needs to have a specific signature. */ +static void +set_host_charset_sfunc (char *charset, int from_tty, + struct cmd_list_element *c) { - *ctrl_char = (c & 037); - return 1; + validate (); } - -/* ISO-8859 family functions. */ - - -static int -iso_8859_print_literally (void *baton, int c) +/* Wrapper for the 'set target-charset' command. */ +static void +set_target_charset_sfunc (char *charset, int from_tty, + struct cmd_list_element *c) { - c &= 0xff; - - return ((0x20 <= c && c <= 0x7e) /* ascii printables */ - || (! sevenbit_strings && 0xA0 <= c)); /* iso 8859 printables */ + validate (); } - -static int -iso_8859_to_control (void *baton, int c, int *ctrl_char) +/* Wrapper for the 'set target-wide-charset' command. */ +static void +set_target_wide_charset_sfunc (char *charset, int from_tty, + struct cmd_list_element *c) { - *ctrl_char = (c & 0200) | (c & 037); - return 1; + validate (); } - -/* Construct an ISO-8859-like character set. */ -static struct charset * -iso_8859_family_charset (const char *name) +/* sfunc for the 'show charset' command. */ +static void +show_charset (struct ui_file *file, int from_tty, struct cmd_list_element *c, + const char *name) { - return simple_charset (name, 1, - iso_8859_print_literally, 0, - iso_8859_to_control, 0); + show_host_charset_name (file, from_tty, c, host_charset_name); + show_target_charset_name (file, from_tty, c, target_charset_name); + show_target_wide_charset_name (file, from_tty, c, target_wide_charset_name); } - -/* EBCDIC family functions. */ - - -static int -ebcdic_print_literally (void *baton, int c) -{ - c &= 0xff; - - return (64 <= c && c <= 254); -} - +/* Accessor functions. */ -static int -ebcdic_to_control (void *baton, int c, int *ctrl_char) +const char * +host_charset (void) { - /* There are no control character equivalents in EBCDIC. Use - numeric escapes. */ - return 0; + if (!strcmp (host_charset_name, "auto")) + return auto_host_charset_name; + return host_charset_name; } - -/* Construct an EBCDIC-like character set. */ -static struct charset * -ebcdic_family_charset (const char *name) +const char * +target_charset (void) { - return simple_charset (name, 0, - ebcdic_print_literally, 0, - ebcdic_to_control, 0); + return target_charset_name; } - - - - - -/* Fallback functions using iconv. */ - -#if defined(HAVE_ICONV) -struct cached_iconv { - struct charset *from, *to; - iconv_t i; -}; - - -/* Make sure the iconv cache *CI contains an iconv descriptor - translating from FROM to TO. If it already does, fine; otherwise, - close any existing descriptor, and open up a new one. On success, - return zero; on failure, return -1 and set errno. */ -static int -check_iconv_cache (struct cached_iconv *ci, - struct charset *from, - struct charset *to) +const char * +target_wide_charset (void) { - iconv_t i; - - /* Does the cached iconv descriptor match the conversion we're trying - to do now? */ - if (ci->from == from - && ci->to == to - && ci->i != (iconv_t) 0) - return 0; - - /* It doesn't. If we actually had any iconv descriptor open at - all, close it now. */ - if (ci->i != (iconv_t) 0) + if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) { - i = ci->i; - ci->i = (iconv_t) 0; - - if (iconv_close (i) == -1) - error (_("Error closing `iconv' descriptor for " - "`%s'-to-`%s' character conversion: %s"), - ci->from->name, ci->to->name, safe_strerror (errno)); + if (target_wide_charset_be_name) + return target_wide_charset_be_name; } - - /* Open a new iconv descriptor for the required conversion. */ - i = iconv_open (to->name, from->name); - if (i == (iconv_t) -1) - return -1; - - ci->i = i; - ci->from = from; - ci->to = to; - - return 0; -} - - -/* Convert FROM_CHAR using the cached iconv conversion *CI. Return - non-zero if the conversion was successful, zero otherwise. */ -static int -cached_iconv_convert (struct cached_iconv *ci, int from_char, int *to_char) -{ - char from; - ICONV_CONST char *from_ptr = &from; - char to, *to_ptr = &to; - size_t from_left = sizeof (from), to_left = sizeof (to); - - gdb_assert (ci->i != (iconv_t) 0); - - from = from_char; - if (iconv (ci->i, &from_ptr, &from_left, &to_ptr, &to_left) - == (size_t) -1) + else { - /* These all suggest that the input or output character sets - have multi-byte encodings of some characters, which means - it's unsuitable for use as a GDB character set. We should - never have selected it. */ - gdb_assert (errno != E2BIG && errno != EINVAL); - - /* This suggests a bug in the code managing *CI. */ - gdb_assert (errno != EBADF); - - /* This seems to mean that there is no equivalent character in - the `to' character set. */ - if (errno == EILSEQ) - return 0; - - /* Anything else is mysterious. */ - internal_error (__FILE__, __LINE__, - _("Error converting character `%d' from `%s' to `%s' " - "character set: %s"), - from_char, ci->from->name, ci->to->name, - safe_strerror (errno)); + if (target_wide_charset_le_name) + return target_wide_charset_le_name; } - /* If the pointers weren't advanced across the input, that also - suggests something was wrong. */ - gdb_assert (from_left == 0 && to_left == 0); - - *to_char = (unsigned char) to; - return 1; + return target_wide_charset_name; } - -static void -register_iconv_charsets (void) -{ - /* Here we should check whether various character sets were - recognized by the local iconv implementation. - - The first implementation registered a bunch of character sets - recognized by iconv, but then we discovered that iconv on Solaris - and iconv on GNU/Linux had no character sets in common. So we - replaced them with the hard-coded tables that appear later in the - file. */ -} - -#endif /* defined (HAVE_ICONV) */ - -/* Fallback routines for systems without iconv. */ +/* Host character set management. For the time being, we assume that + the host character set is some superset of ASCII. */ -#if ! defined (HAVE_ICONV) -struct cached_iconv { char nothing; }; - -static int -check_iconv_cache (struct cached_iconv *ci, - struct charset *from, - struct charset *to) +char +host_letter_to_control_character (char c) { - errno = EINVAL; - return -1; + if (c == '?') + return 0177; + return c & 0237; } -static int -cached_iconv_convert (struct cached_iconv *ci, int from_char, int *to_char) -{ - /* This function should never be called. */ - gdb_assert (0); -} +/* Convert a host character, C, to its hex value. C must already have + been validated using isxdigit. */ -static void -register_iconv_charsets (void) -{ -} - -#endif /* ! defined(HAVE_ICONV) */ - - -/* Default trivial conversion functions. */ - -static int -identity_either_char_to_other (void *baton, int either_char, int *other_char) +int +host_hex_value (char c) { - *other_char = either_char; - return 1; + if (isdigit (c)) + return c - '0'; + if (c >= 'a' && c <= 'f') + return 10 + c - 'a'; + gdb_assert (c >= 'A' && c <= 'F'); + return 10 + c - 'A'; } - -/* Default non-trivial conversion functions. */ - - -static char backslashable[] = "abfnrtv"; -static char *backslashed[] = {"a", "b", "f", "n", "r", "t", "v", "0"}; -static char represented[] = "\a\b\f\n\r\t\v"; - - -/* Translate TARGET_CHAR into the host character set, and see if it - matches any of our standard escape sequences. */ -static const char * -default_c_target_char_has_backslash_escape (void *baton, int target_char) -{ - int host_char; - const char *ix; - - /* If target_char has no equivalent in the host character set, - assume it doesn't have a backslashed form. */ - if (! target_char_to_host (target_char, &host_char)) - return NULL; - - ix = strchr (represented, host_char); - if (ix) - return backslashed[ix - represented]; - else - return NULL; -} - - -/* Translate the backslash the way we would in the host character set, - and then try to translate that into the target character set. */ -static int -default_c_parse_backslash (void *baton, int host_char, int *target_char) -{ - const char *ix; - - ix = strchr (backslashable, host_char); - - if (! ix) - return 0; - else - return host_char_to_target (represented[ix - backslashable], - target_char); -} +/* Public character management functions. */ +/* A cleanup function which is run to close an iconv descriptor. */ -/* Convert using a cached iconv descriptor. */ -static int -iconv_convert (void *baton, int from_char, int *to_char) +static void +cleanup_iconv (void *p) { - struct cached_iconv *ci = baton; - return cached_iconv_convert (ci, from_char, to_char); + iconv_t *descp = p; + iconv_close (*descp); } +void +convert_between_encodings (const char *from, const char *to, + const gdb_byte *bytes, unsigned int num_bytes, + int width, struct obstack *output, + enum transliterations translit) +{ + iconv_t desc; + struct cleanup *cleanups; + size_t inleft; + char *inp; + unsigned int space_request; + + /* Often, the host and target charsets will be the same. */ + if (!strcmp (from, to)) + { + obstack_grow (output, bytes, num_bytes); + return; + } - -/* Conversion tables. */ - - -/* I'd much rather fall back on iconv whenever possible. But the - character set names you use with iconv aren't standardized at all, - a lot of platforms have really meager character set coverage, etc. - I wanted to have at least something we could use to exercise the - test suite on all platforms. - - In the long run, we should have a configure-time process explore - somehow which character sets the host platform supports, and some - arrangement that allows GDB users to use platform-indepedent names - for character sets. */ - - -/* We generated these tables using iconv on a GNU/Linux machine. */ - - -static int ascii_to_iso_8859_1_table[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */ - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */ - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 80 */ - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 96 */ - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 112 */ - 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 128 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -static int ascii_to_ebcdic_us_table[] = { - 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */ - 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */ - 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */ - 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */ - 215,216,217,226,227,228,229,230,231,232,233, -1,224, -1, -1,109, /* 96 */ - 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */ - 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -static int ascii_to_ibm1047_table[] = { - 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */ - 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */ - 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */ - 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */ - 215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109, /* 96 */ - 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */ - 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -static int iso_8859_1_to_ascii_table[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */ - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */ - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 80 */ - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 96 */ - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 112 */ - 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 128 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 144 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 160 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -static int iso_8859_1_to_ebcdic_us_table[] = { - 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */ - 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */ - 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */ - 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */ - 215,216,217,226,227,228,229,230,231,232,233, -1,224, -1, -1,109, /* 96 */ - 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */ - 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */ - 32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27, /* 144 */ - 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62,255, /* 160 */ - -1, -1, 74, -1, -1, -1,106, -1, -1, -1, -1, -1, 95, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 208 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 224 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 240 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -static int iso_8859_1_to_ibm1047_table[] = { - 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31, /* 32 */ - 64, 90,127,123, 91,108, 80,125, 77, 93, 92, 78,107, 96, 75, 97, /* 48 */ - 240,241,242,243,244,245,246,247,248,249,122, 94, 76,126,110,111, /* 64 */ - 124,193,194,195,196,197,198,199,200,201,209,210,211,212,213,214, /* 80 */ - 215,216,217,226,227,228,229,230,231,232,233,173,224,189, 95,109, /* 96 */ - 121,129,130,131,132,133,134,135,136,137,145,146,147,148,149,150, /* 112 */ - 151,152,153,162,163,164,165,166,167,168,169,192, 79,208,161, 7, /* 128 */ - 32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27, /* 144 */ - 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62,255, /* 160 */ - 65,170, 74,177,159,178,106,181,187,180,154,138,176,202,175,188, /* 176 */ - 144,143,234,250,190,160,182,179,157,218,155,139,183,184,185,171, /* 192 */ - 100,101, 98,102, 99,103,158,104,116,113,114,115,120,117,118,119, /* 208 */ - 172,105,237,238,235,239,236,191,128,253,254,251,252,186,174, 89, /* 224 */ - 68, 69, 66, 70, 67, 71,156, 72, 84, 81, 82, 83, 88, 85, 86, 87, /* 240 */ - 140, 73,205,206,203,207,204,225,112,221,222,219,220,141,142,223 /* 256 */ -}; - - -static int ebcdic_us_to_ascii_table[] = { - 0, 1, 2, 3, -1, 9, -1,127, -1, -1, -1, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, -1, -1, 8, -1, 24, 25, -1, -1, 28, 29, 30, 31, /* 32 */ - -1, -1, -1, -1, -1, 10, 23, 27, -1, -1, -1, -1, -1, 5, 6, 7, /* 48 */ - -1, -1, 22, -1, -1, -1, -1, 4, -1, -1, -1, -1, 20, 21, -1, 26, /* 64 */ - 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, 60, 40, 43,124, /* 80 */ - 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59, -1, /* 96 */ - 45, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 37, 95, 62, 63, /* 112 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */ - -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */ - -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */ - -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */ - 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */ - 92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -static int ebcdic_us_to_iso_8859_1_table[] = { - 0, 1, 2, 3,156, 9,134,127,151,141,142, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19,157,133, 8,135, 24, 25,146,143, 28, 29, 30, 31, /* 32 */ - 128,129,130,131,132, 10, 23, 27,136,137,138,139,140, 5, 6, 7, /* 48 */ - 144,145, 22,147,148,149,150, 4,152,153,154,155, 20, 21,158, 26, /* 64 */ - 32, -1, -1, -1, -1, -1, -1, -1, -1, -1,162, 46, 60, 40, 43,124, /* 80 */ - 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59,172, /* 96 */ - 45, 47, -1, -1, -1, -1, -1, -1, -1, -1,166, 44, 37, 95, 62, 63, /* 112 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */ - -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */ - -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */ - -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */ - 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */ - 92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1,159 /* 256 */ -}; - - -static int ebcdic_us_to_ibm1047_table[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */ - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */ - 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, 75, 76, 77, 78, 79, /* 80 */ - 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, 91, 92, 93, 94,176, /* 96 */ - 96, 97, -1, -1, -1, -1, -1, -1, -1, -1,106,107,108,109,110,111, /* 112 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1,121,122,123,124,125,126,127, /* 128 */ - -1,129,130,131,132,133,134,135,136,137, -1, -1, -1, -1, -1, -1, /* 144 */ - -1,145,146,147,148,149,150,151,152,153, -1, -1, -1, -1, -1, -1, /* 160 */ - -1,161,162,163,164,165,166,167,168,169, -1, -1, -1, -1, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - 192,193,194,195,196,197,198,199,200,201, -1, -1, -1, -1, -1, -1, /* 208 */ - 208,209,210,211,212,213,214,215,216,217, -1, -1, -1, -1, -1, -1, /* 224 */ - 224, -1,226,227,228,229,230,231,232,233, -1, -1, -1, -1, -1, -1, /* 240 */ - 240,241,242,243,244,245,246,247,248,249, -1, -1, -1, -1, -1,255 /* 256 */ -}; - - -static int ibm1047_to_ascii_table[] = { - 0, 1, 2, 3, -1, 9, -1,127, -1, -1, -1, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, -1, -1, 8, -1, 24, 25, -1, -1, 28, 29, 30, 31, /* 32 */ - -1, -1, -1, -1, -1, 10, 23, 27, -1, -1, -1, -1, -1, 5, 6, 7, /* 48 */ - -1, -1, 22, -1, -1, -1, -1, 4, -1, -1, -1, -1, 20, 21, -1, 26, /* 64 */ - 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, 60, 40, 43,124, /* 80 */ - 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 36, 42, 41, 59, 94, /* 96 */ - 45, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, 37, 95, 62, 63, /* 112 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, 58, 35, 64, 39, 61, 34, /* 128 */ - -1, 97, 98, 99,100,101,102,103,104,105, -1, -1, -1, -1, -1, -1, /* 144 */ - -1,106,107,108,109,110,111,112,113,114, -1, -1, -1, -1, -1, -1, /* 160 */ - -1,126,115,116,117,118,119,120,121,122, -1, -1, -1, 91, -1, -1, /* 176 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, /* 192 */ - 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, -1, -1, -1, -1, -1, /* 208 */ - 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, -1, -1, -1, -1, /* 224 */ - 92, -1, 83, 84, 85, 86, 87, 88, 89, 90, -1, -1, -1, -1, -1, -1, /* 240 */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, -1 /* 256 */ -}; - - -static int ibm1047_to_iso_8859_1_table[] = { - 0, 1, 2, 3,156, 9,134,127,151,141,142, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19,157,133, 8,135, 24, 25,146,143, 28, 29, 30, 31, /* 32 */ - 128,129,130,131,132, 10, 23, 27,136,137,138,139,140, 5, 6, 7, /* 48 */ - 144,145, 22,147,148,149,150, 4,152,153,154,155, 20, 21,158, 26, /* 64 */ - 32,160,226,228,224,225,227,229,231,241,162, 46, 60, 40, 43,124, /* 80 */ - 38,233,234,235,232,237,238,239,236,223, 33, 36, 42, 41, 59, 94, /* 96 */ - 45, 47,194,196,192,193,195,197,199,209,166, 44, 37, 95, 62, 63, /* 112 */ - 248,201,202,203,200,205,206,207,204, 96, 58, 35, 64, 39, 61, 34, /* 128 */ - 216, 97, 98, 99,100,101,102,103,104,105,171,187,240,253,254,177, /* 144 */ - 176,106,107,108,109,110,111,112,113,114,170,186,230,184,198,164, /* 160 */ - 181,126,115,116,117,118,119,120,121,122,161,191,208, 91,222,174, /* 176 */ - 172,163,165,183,169,167,182,188,189,190,221,168,175, 93,180,215, /* 192 */ - 123, 65, 66, 67, 68, 69, 70, 71, 72, 73,173,244,246,242,243,245, /* 208 */ - 125, 74, 75, 76, 77, 78, 79, 80, 81, 82,185,251,252,249,250,255, /* 224 */ - 92,247, 83, 84, 85, 86, 87, 88, 89, 90,178,212,214,210,211,213, /* 240 */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,179,219,220,217,218,159 /* 256 */ -}; - - -static int ibm1047_to_ebcdic_us_table[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 16 */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 32 */ - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 48 */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 64 */ - 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, 75, 76, 77, 78, 79, /* 80 */ - 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, 91, 92, 93, 94, -1, /* 96 */ - 96, 97, -1, -1, -1, -1, -1, -1, -1, -1,106,107,108,109,110,111, /* 112 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1,121,122,123,124,125,126,127, /* 128 */ - -1,129,130,131,132,133,134,135,136,137, -1, -1, -1, -1, -1, -1, /* 144 */ - -1,145,146,147,148,149,150,151,152,153, -1, -1, -1, -1, -1, -1, /* 160 */ - -1,161,162,163,164,165,166,167,168,169, -1, -1, -1, -1, -1, -1, /* 176 */ - 95, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 192 */ - 192,193,194,195,196,197,198,199,200,201, -1, -1, -1, -1, -1, -1, /* 208 */ - 208,209,210,211,212,213,214,215,216,217, -1, -1, -1, -1, -1, -1, /* 224 */ - 224, -1,226,227,228,229,230,231,232,233, -1, -1, -1, -1, -1, -1, /* 240 */ - 240,241,242,243,244,245,246,247,248,249, -1, -1, -1, -1, -1,255 /* 256 */ -}; + desc = iconv_open (to, from); + if (desc == (iconv_t) -1) + perror_with_name ("Converting character sets"); + cleanups = make_cleanup (cleanup_iconv, &desc); + inleft = num_bytes; + inp = (char *) bytes; -static int -table_convert_char (void *baton, int from, int *to) -{ - int *table = (int *) baton; + space_request = num_bytes; - if (0 <= from && from <= 255 - && table[from] != -1) + while (inleft > 0) { - *to = table[from]; - return 1; + char *outp; + size_t outleft, r; + int old_size; + + old_size = obstack_object_size (output); + obstack_blank (output, space_request); + + outp = obstack_base (output) + old_size; + outleft = space_request; + + r = iconv (desc, &inp, &inleft, &outp, &outleft); + + /* Now make sure that the object on the obstack only includes + bytes we have converted. */ + obstack_blank (output, - (int) outleft); + + if (r == (size_t) -1) + { + switch (errno) + { + case EILSEQ: + { + int i; + + /* Invalid input sequence. */ + if (translit == translit_none) + error (_("Could not convert character to `%s' character set"), + to); + + /* We emit escape sequence for the bytes, skip them, + and try again. */ + for (i = 0; i < width; ++i) + { + char octal[5]; + + sprintf (octal, "\\%.3o", *inp & 0xff); + obstack_grow_str (output, octal); + + ++inp; + --inleft; + } + } + break; + + case E2BIG: + /* We ran out of space in the output buffer. Make it + bigger next time around. */ + space_request *= 2; + break; + + case EINVAL: + /* Incomplete input sequence. FIXME: ought to report this + to the caller somehow. */ + inleft = 0; + break; + + default: + perror_with_name ("Internal error while converting character sets"); + } + } } - else - return 0; -} - -static struct translation * -table_translation (const char *from, const char *to, int *table, - const char *(*c_target_char_has_backslash_escape) - (void *baton, int target_char), - void *c_target_char_has_backslash_escape_baton, - int (*c_parse_backslash) (void *baton, - int host_char, - int *target_char), - void *c_parse_backslash_baton) -{ - struct translation *t = xmalloc (sizeof (*t)); - - memset (t, 0, sizeof (*t)); - t->from = from; - t->to = to; - t->c_target_char_has_backslash_escape = c_target_char_has_backslash_escape; - t->c_target_char_has_backslash_escape_baton - = c_target_char_has_backslash_escape_baton; - t->c_parse_backslash = c_parse_backslash; - t->c_parse_backslash_baton = c_parse_backslash_baton; - t->convert_char = table_convert_char; - t->convert_char_baton = (void *) table; - - return t; + do_cleanups (cleanups); } - -static struct translation * -simple_table_translation (const char *from, const char *to, int *table) -{ - return table_translation (from, to, table, 0, 0, 0, 0); -} - - -/* Setting and retrieving the host and target charsets. */ - - -/* The current host and target character sets. */ -static struct charset *current_host_charset, *current_target_charset; - -/* The current functions and batons we should use for the functions in - charset.h. */ - -static const char *(*c_target_char_has_backslash_escape_func) - (void *baton, int target_char); -static void *c_target_char_has_backslash_escape_baton; - -static int (*c_parse_backslash_func) (void *baton, - int host_char, - int *target_char); -static void *c_parse_backslash_baton; - -static int (*host_char_to_target_func) (void *baton, - int host_char, - int *target_char); -static void *host_char_to_target_baton; - -static int (*target_char_to_host_func) (void *baton, - int target_char, - int *host_char); -static void *target_char_to_host_baton; - -/* Cached iconv conversions, that might be useful to fallback - routines. */ -static struct cached_iconv cached_iconv_host_to_target; -static struct cached_iconv cached_iconv_target_to_host; - - -/* Charset structures manipulation functions. */ - -static struct charset * -lookup_charset_or_error (const char *name) +/* An iterator that returns host wchar_t's from a target string. */ +struct wchar_iterator { - struct charset *cs = lookup_charset (name); + /* The underlying iconv descriptor. */ + iconv_t desc; - if (! cs) - error (_("GDB doesn't know of any character set named `%s'."), name); + /* The input string. This is updated as convert characters. */ + char *input; + /* The number of bytes remaining in the input. */ + size_t bytes; - return cs; -} + /* The width of an input character. */ + size_t width; -static void -check_valid_host_charset (struct charset *cs) -{ - if (! cs->valid_host_charset) - error (_("GDB can't use `%s' as its host character set."), cs->name); -} + /* The output buffer and its size. */ + wchar_t *out; + size_t out_size; +}; -/* Set the host and target character sets to HOST and TARGET. */ -static void -set_host_and_target_charsets (struct charset *host, struct charset *target) +/* Create a new iterator. */ +struct wchar_iterator * +make_wchar_iterator (const gdb_byte *input, size_t bytes, const char *charset, + size_t width) { - struct translation *h2t, *t2h; - - /* If they're not both initialized yet, then just do nothing for - now. As soon as we're done running our initialize function, - everything will be initialized. */ - if (! host || ! target) - { - current_host_charset = host; - current_target_charset = target; - return; - } - - h2t = lookup_translation (host->name, target->name); - t2h = lookup_translation (target->name, host->name); - - /* If the translations don't provide conversion functions, make sure - iconv can back them up. Do this *before* modifying any state. */ - if (host != target) - { - if (! h2t || ! h2t->convert_char) - { - if (check_iconv_cache (&cached_iconv_host_to_target, host, target) - < 0) - error (_("GDB can't convert from the `%s' character set to `%s'."), - host->name, target->name); - } - if (! t2h || ! t2h->convert_char) - { - if (check_iconv_cache (&cached_iconv_target_to_host, target, host) - < 0) - error (_("GDB can't convert from the `%s' character set to `%s'."), - target->name, host->name); - } - } - - if (t2h && t2h->c_target_char_has_backslash_escape) - { - c_target_char_has_backslash_escape_func - = t2h->c_target_char_has_backslash_escape; - c_target_char_has_backslash_escape_baton - = t2h->c_target_char_has_backslash_escape_baton; - } - else - c_target_char_has_backslash_escape_func - = default_c_target_char_has_backslash_escape; - - if (h2t && h2t->c_parse_backslash) - { - c_parse_backslash_func = h2t->c_parse_backslash; - c_parse_backslash_baton = h2t->c_parse_backslash_baton; - } - else - c_parse_backslash_func = default_c_parse_backslash; - - if (h2t && h2t->convert_char) - { - host_char_to_target_func = h2t->convert_char; - host_char_to_target_baton = h2t->convert_char_baton; - } - else if (host == target) - host_char_to_target_func = identity_either_char_to_other; - else - { - host_char_to_target_func = iconv_convert; - host_char_to_target_baton = &cached_iconv_host_to_target; - } + struct wchar_iterator *result; + iconv_t desc; - if (t2h && t2h->convert_char) - { - target_char_to_host_func = t2h->convert_char; - target_char_to_host_baton = t2h->convert_char_baton; - } - else if (host == target) - target_char_to_host_func = identity_either_char_to_other; - else - { - target_char_to_host_func = iconv_convert; - target_char_to_host_baton = &cached_iconv_target_to_host; - } + desc = iconv_open ("wchar_t", charset); + if (desc == (iconv_t) -1) + perror_with_name ("Converting character sets"); - current_host_charset = host; - current_target_charset = target; -} - -/* Do the real work of setting the host charset. */ -static void -set_host_charset (const char *charset) -{ - struct charset *cs = lookup_charset_or_error (charset); - check_valid_host_charset (cs); - set_host_and_target_charsets (cs, current_target_charset); -} + result = XNEW (struct wchar_iterator); + result->desc = desc; + result->input = (char *) input; + result->bytes = bytes; + result->width = width; -/* Do the real work of setting the target charset. */ -static void -set_target_charset (const char *charset) -{ - struct charset *cs = lookup_charset_or_error (charset); + result->out = XNEW (wchar_t); + result->out_size = 1; - set_host_and_target_charsets (current_host_charset, cs); + return result; } - -/* 'Set charset', 'set host-charset', 'set target-charset', 'show - charset' sfunc's. */ - -/* This is the sfunc for the 'set charset' command. */ static void -set_charset_sfunc (char *charset, int from_tty, struct cmd_list_element *c) +do_cleanup_iterator (void *p) { - struct charset *cs = lookup_charset_or_error (host_charset_name); - check_valid_host_charset (cs); - /* CAREFUL: set the target charset here as well. */ - target_charset_name = host_charset_name; - set_host_and_target_charsets (cs, cs); -} + struct wchar_iterator *iter = p; -/* 'set host-charset' command sfunc. We need a wrapper here because - the function needs to have a specific signature. */ -static void -set_host_charset_sfunc (char *charset, int from_tty, - struct cmd_list_element *c) -{ - set_host_charset (host_charset_name); + iconv_close (iter->desc); + xfree (iter->out); + xfree (iter); } -/* Wrapper for the 'set target-charset' command. */ -static void -set_target_charset_sfunc (char *charset, int from_tty, - struct cmd_list_element *c) +struct cleanup * +make_cleanup_wchar_iterator (struct wchar_iterator *iter) { - set_target_charset (target_charset_name); + return make_cleanup (do_cleanup_iterator, iter); } -/* sfunc for the 'show charset' command. */ -static void -show_charset (struct ui_file *file, int from_tty, struct cmd_list_element *c, - const char *name) -{ - if (current_host_charset == current_target_charset) - fprintf_filtered (file, - _("The current host and target character set is `%s'.\n"), - host_charset ()); - else +int +wchar_iterate (struct wchar_iterator *iter, + enum wchar_iterate_result *out_result, + wchar_t **out_chars, + const gdb_byte **ptr, + size_t *len) +{ + size_t out_request; + + /* Try to convert some characters. At first we try to convert just + a single character. The reason for this is that iconv does not + necessarily update its outgoing arguments when it encounters an + invalid input sequence -- but we want to reliably report this to + our caller so it can emit an escape sequence. */ + out_request = 1; + while (iter->bytes > 0) { - fprintf_filtered (file, _("The current host character set is `%s'.\n"), - host_charset ()); - fprintf_filtered (file, _("The current target character set is `%s'.\n"), - target_charset ()); + char *outptr = (char *) &iter->out[0]; + char *orig_inptr = iter->input; + size_t orig_in = iter->bytes; + size_t out_avail = out_request * sizeof (wchar_t); + size_t num; + wchar_t result; + + size_t r = iconv (iter->desc, (char **) &iter->input, &iter->bytes, + &outptr, &out_avail); + if (r == (size_t) -1) + { + switch (errno) + { + case EILSEQ: + /* Invalid input sequence. Skip it, and let the caller + know about it. */ + *out_result = wchar_iterate_invalid; + *ptr = iter->input; + *len = iter->width; + iter->input += iter->width; + iter->bytes -= iter->width; + return 0; + + case E2BIG: + /* We ran out of space. We still might have converted a + character; if so, return it. Otherwise, grow the + buffer and try again. */ + if (out_avail < out_request * sizeof (wchar_t)) + break; + + ++out_request; + if (out_request > iter->out_size) + { + iter->out_size = out_request; + iter->out = xrealloc (iter->out, + out_request * sizeof (wchar_t)); + } + continue; + + case EINVAL: + /* Incomplete input sequence. Let the caller know, and + arrange for future calls to see EOF. */ + *out_result = wchar_iterate_incomplete; + *ptr = iter->input; + *len = iter->bytes; + iter->bytes = 0; + return 0; + + default: + perror_with_name ("Internal error while converting character sets"); + } + } + + /* We converted something. */ + num = out_request - out_avail / sizeof (wchar_t); + *out_result = wchar_iterate_ok; + *out_chars = iter->out; + *ptr = orig_inptr; + *len = orig_in - iter->bytes; + return num; } + + /* Really done. */ + *out_result = wchar_iterate_eof; + return -1; } -/* Accessor functions. */ +/* The charset.c module initialization function. */ -const char * -host_charset (void) -{ - return current_host_charset->name; -} +extern initialize_file_ftype _initialize_charset; /* -Wmissing-prototype */ -const char * -target_charset (void) -{ - return current_target_charset->name; -} +typedef char *char_ptr; +DEF_VEC_P (char_ptr); +static VEC (char_ptr) *charsets; - -/* Public character management functions. */ +#ifdef HAVE_ICONVLIST +/* A helper function that adds some character sets to the vector of + all character sets. This is a callback function for iconvlist. */ -const char * -c_target_char_has_backslash_escape (int target_char) +static int +add_one (unsigned int count, const char *const *names, void *data) { - return ((*c_target_char_has_backslash_escape_func) - (c_target_char_has_backslash_escape_baton, target_char)); -} + unsigned int i; + for (i = 0; i < count; ++i) + VEC_safe_push (char_ptr, charsets, xstrdup (names[i])); -int -c_parse_backslash (int host_char, int *target_char) -{ - return (*c_parse_backslash_func) (c_parse_backslash_baton, - host_char, target_char); + return 0; } - -int -host_char_print_literally (int host_char) +static void +find_charset_names (void) { - return ((*current_host_charset->host_char_print_literally) - (current_host_charset->host_char_print_literally_baton, - host_char)); + iconvlist (add_one, NULL); + VEC_safe_push (char_ptr, charsets, NULL); } +#else -int -target_char_to_control_char (int target_char, int *target_ctrl_char) +static void +find_charset_names (void) { - return ((*current_target_charset->target_char_to_control_char) - (current_target_charset->target_char_to_control_char_baton, - target_char, target_ctrl_char)); -} + FILE *in; + in = popen ("iconv -l", "r"); + /* It is ok to ignore errors; we'll fall back on a default. */ + if (!in) + return; -int -host_char_to_target (int host_char, int *target_char) -{ - return ((*host_char_to_target_func) - (host_char_to_target_baton, host_char, target_char)); -} + /* POSIX says that iconv -l uses an unspecified format. We parse + the glibc format; feel free to add others as needed. */ + while (!feof (in)) + { + /* The size of buf is chosen arbitrarily. A character set name + longer than this would not be very nice. */ + char buf[80]; + int len; + char *r = fgets (buf, sizeof (buf), in); + if (!r) + break; + len = strlen (r); + if (len <= 3) + continue; + if (buf[len - 2] == '/' && buf[len - 3] == '/') + buf[len - 3] = '\0'; + VEC_safe_push (char_ptr, charsets, xstrdup (buf)); + } + pclose (in); -int -target_char_to_host (int target_char, int *host_char) -{ - return ((*target_char_to_host_func) - (target_char_to_host_baton, target_char, host_char)); + VEC_safe_push (char_ptr, charsets, NULL); } - - -/* The charset.c module initialization function. */ - -extern initialize_file_ftype _initialize_charset; /* -Wmissing-prototype */ +#endif /* HAVE_ICONVLIST */ void _initialize_charset (void) { struct cmd_list_element *new_cmd; - /* Register all the character set GDB knows about. - - You should use the same names that iconv does, where possible, to - take advantage of the iconv-based default behaviors. - - CAUTION: if you register a character set, you must also register - as many translations as are necessary to make that character set - interoperate correctly with all the other character sets. We do - provide default behaviors when no translation is available, or - when a translation's function pointer for a particular operation - is zero. Hopefully, these defaults will be correct often enough - that we won't need to provide too many translations. */ - register_charset (simple_charset ("ASCII", 1, - ascii_print_literally, 0, - ascii_to_control, 0)); - register_charset (iso_8859_family_charset ("ISO-8859-1")); - register_charset (ebcdic_family_charset ("EBCDIC-US")); - register_charset (ebcdic_family_charset ("IBM1047")); - register_iconv_charsets (); - - { - struct { char *from; char *to; int *table; } tlist[] = { - { "ASCII", "ISO-8859-1", ascii_to_iso_8859_1_table }, - { "ASCII", "EBCDIC-US", ascii_to_ebcdic_us_table }, - { "ASCII", "IBM1047", ascii_to_ibm1047_table }, - { "ISO-8859-1", "ASCII", iso_8859_1_to_ascii_table }, - { "ISO-8859-1", "EBCDIC-US", iso_8859_1_to_ebcdic_us_table }, - { "ISO-8859-1", "IBM1047", iso_8859_1_to_ibm1047_table }, - { "EBCDIC-US", "ASCII", ebcdic_us_to_ascii_table }, - { "EBCDIC-US", "ISO-8859-1", ebcdic_us_to_iso_8859_1_table }, - { "EBCDIC-US", "IBM1047", ebcdic_us_to_ibm1047_table }, - { "IBM1047", "ASCII", ibm1047_to_ascii_table }, - { "IBM1047", "ISO-8859-1", ibm1047_to_iso_8859_1_table }, - { "IBM1047", "EBCDIC-US", ibm1047_to_ebcdic_us_table } - }; - - int i; - - for (i = 0; i < (sizeof (tlist) / sizeof (tlist[0])); i++) - register_translation (simple_table_translation (tlist[i].from, - tlist[i].to, - tlist[i].table)); - } - - set_host_charset (host_charset_name); - set_target_charset (target_charset_name); + /* The first element is always "auto"; then we skip it for the + commands where it is not allowed. */ + VEC_safe_push (char_ptr, charsets, "auto"); + find_charset_names (); + + if (VEC_length (char_ptr, charsets) > 1) + charset_enum = default_charset_names; + else + charset_enum = (const char **) VEC_address (char_ptr, charsets); + +#ifdef HAVE_LANGINFO_CODESET + auto_host_charset_name = nl_langinfo (CODESET); + target_charset_name = auto_host_charset_name; + + set_be_le_names (); +#endif add_setshow_enum_cmd ("charset", class_support, - host_charset_enum, &host_charset_name, _("\ + &charset_enum[1], &host_charset_name, _("\ Set the host and target character sets."), _("\ Show the host and target character sets."), _("\ The `host character set' is the one used by the system GDB is running on.\n\ @@ -1249,7 +650,7 @@ To see a list of the character sets GDB supports, type `set charset '."), &setlist, &showlist); add_setshow_enum_cmd ("host-charset", class_support, - host_charset_enum, &host_charset_name, _("\ + charset_enum, &host_charset_name, _("\ Set the host character set."), _("\ Show the host character set."), _("\ The `host character set' is the one used by the system GDB is running on.\n\ @@ -1261,7 +662,7 @@ To see a list of the character sets GDB supports, type `set host-charset '. &setlist, &showlist); add_setshow_enum_cmd ("target-charset", class_support, - target_charset_enum, &target_charset_name, _("\ + &charset_enum[1], &target_charset_name, _("\ Set the target character set."), _("\ Show the target character set."), _("\ The `target character set' is the one used by the program being debugged.\n\ @@ -1271,4 +672,19 @@ To see a list of the character sets GDB supports, type `set target-charset' set_target_charset_sfunc, show_target_charset_name, &setlist, &showlist); + + add_setshow_enum_cmd ("target-wide-charset", class_support, + &charset_enum[1], &target_wide_charset_name, + _("\ +Set the target wide character set."), _("\ +Show the target wide character set."), _("\ +The `target wide character set' is the one used by the program being debugged.\n\ +In particular it is the encoding used by `wchar_t'.\n\ +GDB translates characters and strings between the host and target\n\ +character sets as needed.\n\ +To see a list of the character sets GDB supports, type\n\ +`set target-wide-charset'"), + set_target_wide_charset_sfunc, + show_target_wide_charset_name, + &setlist, &showlist); } diff --git a/gdb/charset.h b/gdb/charset.h index 21780b6..2455355 100644 --- a/gdb/charset.h +++ b/gdb/charset.h @@ -19,6 +19,7 @@ #ifndef CHARSET_H #define CHARSET_H +#include /* If the target program uses a different character set than the host, GDB has some support for translating between the two; GDB converts @@ -26,82 +27,123 @@ them, and converts characters and strings appearing in expressions entered by the user to the target character set. - At the moment, GDB only supports single-byte, stateless character - sets. This includes the ISO-8859 family (ASCII extended with - accented characters, and (I think) Cyrillic, for European - languages), and the EBCDIC family (used on IBM's mainframes). - Unfortunately, it excludes many Asian scripts, the fixed- and - variable-width Unicode encodings, and other desireable things. - Patches are welcome! (For example, it would be nice if the Java - string support could simply get absorbed into some more general - multi-byte encoding support.) - - Furthermore, GDB's code pretty much assumes that the host character - set is some superset of ASCII; there are plenty if ('0' + n) - expressions and the like. - - When the `iconv' library routine supports a character set meeting - the requirements above, it's easy to plug an entry into GDB's table - that uses iconv to handle the details. */ + GDB's code pretty much assumes that the host character set is some + superset of ASCII; there are plenty if ('0' + n) expressions and + the like. */ /* Return the name of the current host/target character set. The result is owned by the charset module; the caller should not free it. */ const char *host_charset (void); const char *target_charset (void); - -/* In general, the set of C backslash escapes (\n, \f) is specific to - the character set. Not all character sets will have form feed - characters, for example. - - The following functions allow GDB to parse and print control - characters in a character-set-independent way. They are both - language-specific (to C and C++) and character-set-specific. - Putting them here is a compromise. */ - - -/* If the target character TARGET_CHAR have a backslash escape in the - C language (i.e., a character like 'n' or 't'), return the host - character string that should follow the backslash. Otherwise, - return zero. - - When this function returns non-zero, the string it returns is - statically allocated; the caller is not responsible for freeing it. */ -const char *c_target_char_has_backslash_escape (int target_char); - - -/* If the host character HOST_CHAR is a valid backslash escape in the - C language for the target character set, return non-zero, and set - *TARGET_CHAR to the target character the backslash escape represents. - Otherwise, return zero. */ -int c_parse_backslash (int host_char, int *target_char); - - -/* Return non-zero if the host character HOST_CHAR can be printed - literally --- that is, if it can be readably printed as itself in a - character or string constant. Return zero if it should be printed - using some kind of numeric escape, like '\031' in C, '^(25)' in - Chill, or #25 in Pascal. */ -int host_char_print_literally (int host_char); - - -/* If the host character HOST_CHAR has an equivalent in the target - character set, set *TARGET_CHAR to that equivalent, and return - non-zero. Otherwise, return zero. */ -int host_char_to_target (int host_char, int *target_char); - - -/* If the target character TARGET_CHAR has an equivalent in the host - character set, set *HOST_CHAR to that equivalent, and return - non-zero. Otherwise, return zero. */ -int target_char_to_host (int target_char, int *host_char); - - -/* If the target character TARGET_CHAR has a corresponding control - character (also in the target character set), set *TARGET_CTRL_CHAR - to the control character, and return non-zero. Otherwise, return - zero. */ -int target_char_to_control_char (int target_char, int *target_ctrl_char); - +const char *target_wide_charset (void); + +/* These values are used to specify the type of transliteration done + by convert_between_encodings. */ +enum transliterations + { + /* Error on failure to convert. */ + translit_none, + /* Transliterate to host char. */ + translit_char + }; + +/* Convert between two encodings. + + FROM is the name of the source encoding. + TO is the name of the target encoding. + BYTES holds the bytes to convert; this is assumed to be characters + in the target encoding. + NUM_BYTES is the number of bytes. + WIDTH is the width of a character from the FROM charset, in bytes. + For a variable width encoding, WIDTH should be the size of a "base + character". + OUTPUT is an obstack where the converted data is written. The + caller is responsible for initializing the obstack, and for + destroying the obstack should an error occur. + TRANSLIT specifies how invalid conversions should be handled. */ +void convert_between_encodings (const char *from, const char *to, + const gdb_byte *bytes, unsigned int num_bytes, + int width, struct obstack *output, + enum transliterations translit); + + +/* These values are used by wchar_iterate to report errors. */ +enum wchar_iterate_result + { + /* Ordinary return. */ + wchar_iterate_ok, + /* Invalid input sequence. */ + wchar_iterate_invalid, + /* Incomplete input sequence at the end of the input. */ + wchar_iterate_incomplete, + /* EOF. */ + wchar_iterate_eof + }; + +/* Declaration of the opaque wchar iterator type. */ +struct wchar_iterator; + +/* Create a new character iterator which returns wchar_t's. INPUT is + the input buffer. BYTES is the number of bytes in the input + buffer. CHARSET is the name of the character set in which INPUT is + encoded. WIDTH is the number of bytes in a base character of + CHARSET. + + This function either returns a new character set iterator, or calls + error. The result can be freed using a cleanup; see + make_cleanup_wchar_iterator. */ +struct wchar_iterator *make_wchar_iterator (const gdb_byte *input, size_t bytes, + const char *charset, + size_t width); + +/* Return a new cleanup suitable for destroying the wchar iterator + ITER. */ +struct cleanup *make_cleanup_wchar_iterator (struct wchar_iterator *iter); + +/* Perform a single iteration of a wchar_t iterator. + + Returns the number of characters converted. A negative result + means that EOF has been reached. A positive result indicates the + number of valid wchar_ts in the result; *OUT_CHARS is updated to + point to the first valid character. + + In all cases aside from EOF, *PTR is set to point to the first + converted target byte. *LEN is set to the number of bytes + converted. + + A zero result means one of several unusual results. *OUT_RESULT is + set to indicate the type of un-ordinary return. + + wchar_iterate_invalid means that an invalid input character was + seen. The iterator is advanced by WIDTH (the argument to + make_wchar_iterator) bytes. + + wchar_iterate_incomplete means that an incomplete character was + seen at the end of the input sequence. + + wchar_iterate_eof means that all bytes were successfully + converted. The other output arguments are not set. */ +int wchar_iterate (struct wchar_iterator *iter, + enum wchar_iterate_result *out_result, + wchar_t **out_chars, + const gdb_byte **ptr, size_t *len); + + + +/* GDB needs to know a few details of its execution character set. + This knowledge is isolated here and in charset.c. */ + +/* The escape character. */ +#define HOST_ESCAPE_CHAR 27 + +/* Convert a letter, like 'c', to its corresponding control + character. */ +char host_letter_to_control_character (char c); + +/* Convert a hex digit character to its numeric value. E.g., 'f' is + converted to 15. This function assumes that C is a valid hex + digit. Both upper- and lower-case letters are recognized. */ +int host_hex_value (char c); #endif /* CHARSET_H */ diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index 4d9c4f3..5fbe398 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -45,6 +45,8 @@ #include "cli/cli-setshow.h" #include "cli/cli-cmds.h" +#include "python/python.h" + #ifdef TUI #include "tui/tui.h" /* For tui_active et.al. */ #endif @@ -178,6 +180,7 @@ struct cmd_list_element *showchecklist; /* Command tracing state. */ +static int source_python = 0; int source_verbose = 0; int trace_commands = 0; @@ -439,6 +442,7 @@ source_script (char *file, int from_tty) struct cleanup *old_cleanups; char *full_pathname = NULL; int fd; + int is_python; if (file == NULL || *file == 0) { @@ -471,8 +475,16 @@ source_script (char *file, int from_tty) } } + is_python = source_python; + if (strlen (file) > 3 && !strcmp (&file[strlen (file) - 3], ".py")) + is_python = 1; + stream = fdopen (fd, FOPEN_RT); - script_from_file (stream, file); + + if (is_python) + source_python_script (stream, file); + else + script_from_file (stream, file); do_cleanups (old_cleanups); } @@ -486,15 +498,30 @@ source_verbose_cleanup (void *old_value) xfree (old_value); } +/* A helper for source_command. Look for an argument in *ARGS. + Update *ARGS by stripping leading whitespace. If an argument is + found, return it (a character). Otherwise, return 0. */ +static int +find_argument (char **args) +{ + int result = 0; + while (isspace ((*args)[0])) + ++*args; + if ((*args)[0] == '-' && isalpha ((*args)[1])) + { + result = (*args)[1]; + *args += 3; + } + return result; +} + static void source_command (char *args, int from_tty) { struct cleanup *old_cleanups; - char *file = args; - int *old_source_verbose = xmalloc (sizeof(int)); - *old_source_verbose = source_verbose; - old_cleanups = make_cleanup (source_verbose_cleanup, old_source_verbose); + old_cleanups = make_cleanup_restore_integer (&source_verbose); + make_cleanup_restore_integer (&source_python); /* -v causes the source command to run in verbose mode. We still have to be able to handle filenames with spaces in a @@ -502,23 +529,28 @@ source_command (char *args, int from_tty) if (args) { - /* Make sure leading white space does not break the comparisons. */ - while (isspace(args[0])) - args++; - - /* Is -v the first thing in the string? */ - if (args[0] == '-' && args[1] == 'v' && isspace (args[2])) + while (1) { - source_verbose = 1; - - /* Trim -v and whitespace from the filename. */ - file = &args[3]; - while (isspace (file[0])) - file++; + int arg = find_argument (&args); + if (!arg) + break; + switch (arg) + { + case 'v': + source_verbose = 1; + break; + case 'p': + source_python = 1; + break; + default: + error (_("unrecognized option -%c"), arg); + } } } - source_script (file, from_tty); + source_script (args, from_tty); + + do_cleanups (old_cleanups); } @@ -1282,7 +1314,9 @@ Read commands from a file named FILE.\n\ Optional -v switch (before the filename) causes each command in\n\ FILE to be echoed as it is executed.\n\ Note that the file \"%s\" is read automatically in this way\n\ -when GDB is started."), gdbinit); +when GDB is started.\n\ +Optional -p switch (before the filename) causes FILE to be evaluated\n\ +as Python code."), gdbinit); c = add_cmd ("source", class_support, source_command, source_help_text, &cmdlist); set_cmd_completer (c, filename_completer); diff --git a/gdb/cli/cli-dump.c b/gdb/cli/cli-dump.c index ee29f2a..96e6111 100644 --- a/gdb/cli/cli-dump.c +++ b/gdb/cli/cli-dump.c @@ -296,7 +296,7 @@ dump_value_to_file (char *cmd, char *mode, char *file_format) if (VALUE_LVAL (val)) { - vaddr = VALUE_ADDRESS (val); + vaddr = value_address (val); } else { diff --git a/gdb/coffread.c b/gdb/coffread.c index 6059d68..47ee601 100644 --- a/gdb/coffread.c +++ b/gdb/coffread.c @@ -346,7 +346,7 @@ coff_alloc_type (int index) We will fill it in later if we find out how. */ if (type == NULL) { - type = alloc_type (current_objfile); + type = alloc_type (current_objfile, NULL); *type_addr = type; } return type; @@ -2101,6 +2101,7 @@ static struct sym_fns coff_sym_fns = coff_new_init, /* sym_new_init: init anything gbl to entire symtab */ coff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ coff_symfile_read, /* sym_read: read a symbol file into symtab */ + NULL, /* sym_read_psymbols */ coff_symfile_finish, /* sym_finish: finished with file, cleanup */ default_symfile_offsets, /* sym_offsets: xlate external to internal form */ default_symfile_segments, /* sym_segments: Get segment information from diff --git a/gdb/config.in b/gdb/config.in index 6aaf77a..0c8ccab 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -42,6 +42,12 @@ language is requested. */ #undef ENABLE_NLS +/* Global directory for GDB data files. */ +#undef GDB_DATADIR + +/* Define if GDB datadir should be relocated when GDB is moved. */ +#undef GDB_DATADIR_RELOCATABLE + /* Define to be a string naming the default host character set. */ #undef GDB_DEFAULT_HOST_CHARSET @@ -169,12 +175,18 @@ /* Define if you have the iconv() function. */ #undef HAVE_ICONV +/* Define to 1 if you have the `iconvlist' function. */ +#undef HAVE_ICONVLIST + /* Define if your compiler supports the #include_next directive. */ #undef HAVE_INCLUDE_NEXT /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define if you have and nl_langinfo(CODESET). */ +#undef HAVE_LANGINFO_CODESET + /* Define if your file defines LC_MESSAGES. */ #undef HAVE_LC_MESSAGES @@ -618,6 +630,9 @@ 'ptrdiff_t'. */ #undef PTRDIFF_T_SUFFIX +/* Define to install path for Python sources */ +#undef PYTHONDIR + /* Bug reporting address */ #undef REPORT_BUGS_TO diff --git a/gdb/configure b/gdb/configure index 7579c84..3a5b582 100755 --- a/gdb/configure +++ b/gdb/configure @@ -314,7 +314,7 @@ ac_subdirs_all="$ac_subdirs_all doc testsuite" ac_subdirs_all="$ac_subdirs_all gdbtk" ac_subdirs_all="$ac_subdirs_all multi-ice" ac_subdirs_all="$ac_subdirs_all gdbserver" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP RANLIB ac_ct_RANLIB build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os am__leading_dot DEPDIR CCDEPMODE MAKE GMAKE_TRUE GMAKE_FALSE SET_MAKE USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT localedir GL_COND_LIBTOOL_TRUE GL_COND_LIBTOOL_FALSE GNULIB_MEMMEM GNULIB_MEMPCPY GNULIB_MEMRCHR GNULIB_STPCPY GNULIB_STPNCPY GNULIB_STRCHRNUL GNULIB_STRDUP GNULIB_STRNDUP GNULIB_STRNLEN GNULIB_STRPBRK GNULIB_STRSEP GNULIB_STRSTR GNULIB_STRCASESTR GNULIB_STRTOK_R GNULIB_MBSLEN GNULIB_MBSNLEN GNULIB_MBSCHR GNULIB_MBSRCHR GNULIB_MBSSTR GNULIB_MBSCASECMP GNULIB_MBSNCASECMP GNULIB_MBSPCASECMP GNULIB_MBSCASESTR GNULIB_MBSCSPN GNULIB_MBSPBRK GNULIB_MBSSPN GNULIB_MBSSEP GNULIB_MBSTOK_R GNULIB_STRERROR GNULIB_STRSIGNAL HAVE_DECL_MEMMEM HAVE_MEMPCPY HAVE_DECL_MEMRCHR HAVE_STPCPY HAVE_STPNCPY HAVE_STRCHRNUL HAVE_DECL_STRDUP HAVE_STRNDUP HAVE_DECL_STRNDUP HAVE_DECL_STRNLEN HAVE_STRPBRK HAVE_STRSEP HAVE_STRCASESTR HAVE_DECL_STRTOK_R HAVE_DECL_STRERROR HAVE_DECL_STRSIGNAL REPLACE_STRERROR REPLACE_STRSIGNAL REPLACE_MEMMEM REPLACE_STRCASESTR REPLACE_STRSTR HAVE_LONG_LONG_INT HAVE_UNSIGNED_LONG_LONG_INT HAVE_INTTYPES_H HAVE_SYS_TYPES_H INCLUDE_NEXT NEXT_STDINT_H HAVE_STDINT_H HAVE_SYS_INTTYPES_H HAVE_SYS_BITYPES_H BITSIZEOF_PTRDIFF_T BITSIZEOF_SIG_ATOMIC_T BITSIZEOF_SIZE_T BITSIZEOF_WCHAR_T BITSIZEOF_WINT_T HAVE_SIGNED_SIG_ATOMIC_T HAVE_SIGNED_WCHAR_T HAVE_SIGNED_WINT_T PTRDIFF_T_SUFFIX SIG_ATOMIC_T_SUFFIX SIZE_T_SUFFIX WCHAR_T_SUFFIX WINT_T_SUFFIX STDINT_H NEXT_STRING_H GNULIB_WCWIDTH HAVE_DECL_WCWIDTH REPLACE_WCWIDTH WCHAR_H HAVE_WCHAR_H NEXT_WCHAR_H LIBGNU_LIBDEPS LIBGNU_LTLIBDEPS GNULIB_STDINT_H PACKAGE INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK AMTAR am__tar am__untar am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH am__fastdepCC_TRUE am__fastdepCC_FALSE subdirs TARGET_OBS PKGVERSION REPORT_BUGS_TO REPORT_BUGS_TEXI LN_S YACC AR ac_ct_AR DLLTOOL ac_ct_DLLTOOL WINDRES ac_ct_WINDRES MIG ac_ct_MIG READLINE READLINE_DEPS READLINE_CFLAGS HAVE_LIBEXPAT LIBEXPAT LTLIBEXPAT PYTHON_CFLAGS ALLOCA CONFIG_LDFLAGS TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE WARN_CFLAGS WERROR_CFLAGS SER_HARDWIRE WIN32LIBS LIBGUI GUI_CFLAGS_X WIN32LDAPP TCL_VERSION TCL_PATCH_LEVEL TCL_BIN_DIR TCL_SRC_DIR TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC TCL_INCLUDE TCL_LIBRARY TCL_DEPS TK_VERSION TK_BIN_DIR TK_SRC_DIR TK_LIB_FILE TK_LIB_FLAG TK_LIB_SPEC TK_STUB_LIB_FILE TK_STUB_LIB_FLAG TK_STUB_LIB_SPEC TK_INCLUDE TK_LIBRARY TK_DEPS TK_XINCLUDES X_CFLAGS X_LDFLAGS X_LIBS GDBTKLIBS GDBTK_CFLAGS GDBTK_SRC_DIR SIM SIM_OBS ENABLE_CFLAGS PROFILE_CFLAGS CONFIG_OBS CONFIG_DEPS CONFIG_SRCS CONFIG_ALL CONFIG_CLEAN CONFIG_INSTALL CONFIG_UNINSTALL target_subdir frags nm_h LIBICONV LIBOBJS LTLIBOBJS gl_LIBOBJS gl_LTLIBOBJS gltests_LIBOBJS gltests_LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP RANLIB ac_ct_RANLIB build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os am__leading_dot DEPDIR CCDEPMODE MAKE GMAKE_TRUE GMAKE_FALSE SET_MAKE USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT localedir GL_COND_LIBTOOL_TRUE GL_COND_LIBTOOL_FALSE GNULIB_MEMMEM GNULIB_MEMPCPY GNULIB_MEMRCHR GNULIB_STPCPY GNULIB_STPNCPY GNULIB_STRCHRNUL GNULIB_STRDUP GNULIB_STRNDUP GNULIB_STRNLEN GNULIB_STRPBRK GNULIB_STRSEP GNULIB_STRSTR GNULIB_STRCASESTR GNULIB_STRTOK_R GNULIB_MBSLEN GNULIB_MBSNLEN GNULIB_MBSCHR GNULIB_MBSRCHR GNULIB_MBSSTR GNULIB_MBSCASECMP GNULIB_MBSNCASECMP GNULIB_MBSPCASECMP GNULIB_MBSCASESTR GNULIB_MBSCSPN GNULIB_MBSPBRK GNULIB_MBSSPN GNULIB_MBSSEP GNULIB_MBSTOK_R GNULIB_STRERROR GNULIB_STRSIGNAL HAVE_DECL_MEMMEM HAVE_MEMPCPY HAVE_DECL_MEMRCHR HAVE_STPCPY HAVE_STPNCPY HAVE_STRCHRNUL HAVE_DECL_STRDUP HAVE_STRNDUP HAVE_DECL_STRNDUP HAVE_DECL_STRNLEN HAVE_STRPBRK HAVE_STRSEP HAVE_STRCASESTR HAVE_DECL_STRTOK_R HAVE_DECL_STRERROR HAVE_DECL_STRSIGNAL REPLACE_STRERROR REPLACE_STRSIGNAL REPLACE_MEMMEM REPLACE_STRCASESTR REPLACE_STRSTR HAVE_LONG_LONG_INT HAVE_UNSIGNED_LONG_LONG_INT HAVE_INTTYPES_H HAVE_SYS_TYPES_H INCLUDE_NEXT NEXT_STDINT_H HAVE_STDINT_H HAVE_SYS_INTTYPES_H HAVE_SYS_BITYPES_H BITSIZEOF_PTRDIFF_T BITSIZEOF_SIG_ATOMIC_T BITSIZEOF_SIZE_T BITSIZEOF_WCHAR_T BITSIZEOF_WINT_T HAVE_SIGNED_SIG_ATOMIC_T HAVE_SIGNED_WCHAR_T HAVE_SIGNED_WINT_T PTRDIFF_T_SUFFIX SIG_ATOMIC_T_SUFFIX SIZE_T_SUFFIX WCHAR_T_SUFFIX WINT_T_SUFFIX STDINT_H NEXT_STRING_H GNULIB_WCWIDTH HAVE_DECL_WCWIDTH REPLACE_WCWIDTH WCHAR_H HAVE_WCHAR_H NEXT_WCHAR_H LIBGNU_LIBDEPS LIBGNU_LTLIBDEPS GNULIB_STDINT_H PACKAGE INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK AMTAR am__tar am__untar am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH am__fastdepCC_TRUE am__fastdepCC_FALSE GDB_DATADIR_PATH pythondir subdirs TARGET_OBS PKGVERSION REPORT_BUGS_TO REPORT_BUGS_TEXI LN_S YACC AR ac_ct_AR DLLTOOL ac_ct_DLLTOOL WINDRES ac_ct_WINDRES MIG ac_ct_MIG LIBICONV LIBICONV_INCLUDE LIBICONV_LIBDIR READLINE READLINE_DEPS READLINE_CFLAGS HAVE_LIBEXPAT LIBEXPAT LTLIBEXPAT PYTHON_CFLAGS ALLOCA CONFIG_LDFLAGS TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE WARN_CFLAGS WERROR_CFLAGS SER_HARDWIRE WIN32LIBS LIBGUI GUI_CFLAGS_X WIN32LDAPP TCL_VERSION TCL_PATCH_LEVEL TCL_BIN_DIR TCL_SRC_DIR TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC TCL_INCLUDE TCL_LIBRARY TCL_DEPS TK_VERSION TK_BIN_DIR TK_SRC_DIR TK_LIB_FILE TK_LIB_FLAG TK_LIB_SPEC TK_STUB_LIB_FILE TK_STUB_LIB_FLAG TK_STUB_LIB_SPEC TK_INCLUDE TK_LIBRARY TK_DEPS TK_XINCLUDES X_CFLAGS X_LDFLAGS X_LIBS GDBTKLIBS GDBTK_CFLAGS GDBTK_SRC_DIR SIM SIM_OBS ENABLE_CFLAGS PROFILE_CFLAGS CONFIG_OBS CONFIG_DEPS CONFIG_SRCS CONFIG_ALL CONFIG_CLEAN CONFIG_INSTALL CONFIG_UNINSTALL target_subdir frags nm_h LIBOBJS LTLIBOBJS gl_LIBOBJS gl_LTLIBOBJS gltests_LIBOBJS gltests_LTLIBOBJS' ac_subst_files='host_makefile_frag' ac_pwd=`pwd` @@ -882,9 +882,14 @@ Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-separate-debug-dir=path Look for global separate debug info in this path LIBDIR/debug + --with-gdb-datadir look for global separate data files in this path + [DATADIR/gdb] + --with-pythondir install Python data files in this path + [DATADIR/gdb/python] --with-libunwind Use libunwind frame unwinding support --with-pkgversion=PKG Use PKG in the version string in place of "GDB" --with-bugurl=URL Direct users to URL to report a bug + --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib --with-system-readline use installed readline library --with-expat include expat support (auto/yes/no) --with-gnu-ld assume the C compiler uses GNU ld default=no @@ -899,7 +904,6 @@ Optional Packages: --with-tcl directory containing tcl configuration (tclConfig.sh) --with-tk directory containing tk configuration (tkConfig.sh) --with-x use the X Window System - --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib Some influential environment variables: CC C compiler command @@ -7130,6 +7134,75 @@ _ACEOF ;; esac +# GDB's datadir relocation + +gdbdatadir=${datadir}/gdb + + +# Check whether --with-gdb-datadir or --without-gdb-datadir was given. +if test "${with_gdb_datadir+set}" = set; then + withval="$with_gdb_datadir" + gdbdatadir="${withval}" +fi; + + + test "x$prefix" = xNONE && prefix="$ac_default_prefix" + test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + ac_define_dir=`eval echo $gdbdatadir` + ac_define_dir=`eval echo $ac_define_dir` + +cat >>confdefs.h <<_ACEOF +#define GDB_DATADIR "$ac_define_dir" +_ACEOF + + + +if test "x$exec_prefix" = xNONE || test "x$exec_prefix" = 'x${prefix}'; then + if test "x$prefix" = xNONE; then + test_prefix=/usr/local + else + test_prefix=$prefix + fi +else + test_prefix=$exec_prefix +fi + +case ${gdbdatadir} in + "${test_prefix}"|"${test_prefix}/"*|\ + '${exec_prefix}'|'${exec_prefix}/'*) + +cat >>confdefs.h <<\_ACEOF +#define GDB_DATADIR_RELOCATABLE 1 +_ACEOF + + ;; +esac +GDB_DATADIR_PATH=${gdbdatadir} + + + +# Check whether --with-pythondir or --without-pythondir was given. +if test "${with_pythondir+set}" = set; then + withval="$with_pythondir" + pythondir="${withval}" +else + pythondir=no +fi; + +# If the user passed in a path, define it. Otherwise, compute it at +# runtime based on the possibly-relocatable datadir. +if test "$pythondir" = "no"; then + pythondir='$(GDB_DATADIR_PATH)/python' +else + +cat >>confdefs.h <<_ACEOF +#define PYTHONDIR "$pythondir" +_ACEOF + +fi + + + subdirs="$subdirs doc testsuite" @@ -9989,6 +10062,226 @@ if test "$ac_cv_search_dlgetmodinfo" != no; then fi + + + +# Check whether --with-libiconv-prefix or --without-libiconv-prefix was given. +if test "${with_libiconv_prefix+set}" = set; then + withval="$with_libiconv_prefix" + + for dir in `echo "$withval" | tr : ' '`; do + if test -d $dir/include; then LIBICONV_INCLUDE="-I$dir/include"; CPPFLAGS="$CPPFLAGS -I$dir/include"; fi + if test -d $dir/lib; then LIBICONV_LIBDIR="-L$dir/lib"; LDFLAGS="$LDFLAGS -L$dir/lib"; fi + done + +fi; + + echo "$as_me:$LINENO: checking for iconv" >&5 +echo $ECHO_N "checking for iconv... $ECHO_C" >&6 +if test "${am_cv_func_iconv+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + am_cv_func_iconv=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS -liconv" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$am_save_LIBS" + fi + +fi +echo "$as_me:$LINENO: result: $am_cv_func_iconv" >&5 +echo "${ECHO_T}$am_cv_func_iconv" >&6 + if test "$am_cv_func_iconv" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_ICONV 1 +_ACEOF + + echo "$as_me:$LINENO: checking for iconv declaration" >&5 +echo $ECHO_N "checking for iconv declaration... $ECHO_C" >&6 + if test "${am_cv_proto_iconv+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + am_cv_proto_iconv_arg1="" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +am_cv_proto_iconv_arg1="const" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" +fi + + am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + echo "$as_me:$LINENO: result: ${ac_t:- + }$am_cv_proto_iconv" >&5 +echo "${ECHO_T}${ac_t:- + }$am_cv_proto_iconv" >&6 + +cat >>confdefs.h <<_ACEOF +#define ICONV_CONST $am_cv_proto_iconv_arg1 +_ACEOF + + fi + LIBICONV= + if test "$am_cv_lib_iconv" = yes; then + LIBICONV="-liconv" + fi + + + + + # On alpha-osf, it appears that libtermcap and libcurses are not compatible. # There is a very specific comment in /usr/include/curses.h explaining that # termcap routines built into libcurses must not be used. @@ -11418,6 +11711,8 @@ _ACEOF CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_PYTHON_OBS)" CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_PYTHON_DEPS)" CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_PYTHON_SRCS)" + CONFIG_INSTALL="$CONFIG_INSTALL install-python" + CONFIG_UNINSTALL="$CONFIG_UNINSTALL uninstall-python" ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_PYTHON_CFLAGS)" # Flags needed to compile Python code (taken from python-config --cflags). @@ -15445,10 +15740,11 @@ fi + for ac_func in canonicalize_file_name realpath getrusage getuid \ getgid poll pread64 sbrk setpgid setpgrp setsid \ sigaction sigprocmask sigsetmask socketpair syscall \ - ttrace wborder setlocale + ttrace wborder setlocale iconvlist do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -15550,6 +15846,70 @@ fi done + echo "$as_me:$LINENO: checking for nl_langinfo and CODESET" >&5 +echo $ECHO_N "checking for nl_langinfo and CODESET... $ECHO_C" >&6 +if test "${am_cv_langinfo_codeset+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +char* cs = nl_langinfo(CODESET); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + am_cv_langinfo_codeset=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +am_cv_langinfo_codeset=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +echo "$as_me:$LINENO: result: $am_cv_langinfo_codeset" >&5 +echo "${ECHO_T}$am_cv_langinfo_codeset" >&6 + if test $am_cv_langinfo_codeset = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LANGINFO_CODESET 1 +_ACEOF + + fi + + # Check the return and argument types of ptrace. No canned test for # this, so roll our own. gdb_ptrace_headers=' @@ -20776,230 +21136,11 @@ done - cat >>confdefs.h <<\_ACEOF -#define GDB_DEFAULT_HOST_CHARSET "ISO-8859-1" +#define GDB_DEFAULT_HOST_CHARSET "UTF-8" _ACEOF - - - -# Check whether --with-libiconv-prefix or --without-libiconv-prefix was given. -if test "${with_libiconv_prefix+set}" = set; then - withval="$with_libiconv_prefix" - - for dir in `echo "$withval" | tr : ' '`; do - if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi - if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi - done - -fi; - - echo "$as_me:$LINENO: checking for iconv" >&5 -echo $ECHO_N "checking for iconv... $ECHO_C" >&6 -if test "${am_cv_func_iconv+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - - am_cv_func_iconv="no, consider installing GNU libiconv" - am_cv_lib_iconv=no - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -#include -int -main () -{ -iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - am_cv_func_iconv=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if test "$am_cv_func_iconv" != yes; then - am_save_LIBS="$LIBS" - LIBS="$LIBS -liconv" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -#include -int -main () -{ -iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - am_cv_lib_iconv=yes - am_cv_func_iconv=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -fi -rm -f conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$am_save_LIBS" - fi - -fi -echo "$as_me:$LINENO: result: $am_cv_func_iconv" >&5 -echo "${ECHO_T}$am_cv_func_iconv" >&6 - if test "$am_cv_func_iconv" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_ICONV 1 -_ACEOF - - echo "$as_me:$LINENO: checking for iconv declaration" >&5 -echo $ECHO_N "checking for iconv declaration... $ECHO_C" >&6 - if test "${am_cv_proto_iconv+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -#include -#include -extern -#ifdef __cplusplus -"C" -#endif -#if defined(__STDC__) || defined(__cplusplus) -size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); -#else -size_t iconv(); -#endif - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" - || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - am_cv_proto_iconv_arg1="" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -am_cv_proto_iconv_arg1="const" -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext - am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" -fi - - am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` - echo "$as_me:$LINENO: result: ${ac_t:- - }$am_cv_proto_iconv" >&5 -echo "${ECHO_T}${ac_t:- - }$am_cv_proto_iconv" >&6 - -cat >>confdefs.h <<_ACEOF -#define ICONV_CONST $am_cv_proto_iconv_arg1 -_ACEOF - - fi - LIBICONV= - if test "$am_cv_lib_iconv" = yes; then - LIBICONV="-liconv" - fi - - - ac_config_files="$ac_config_files Makefile .gdbinit:gdbinit.in gnulib/Makefile" ac_config_commands="$ac_config_commands default" cat >confcache <<\_ACEOF @@ -21865,6 +22006,8 @@ s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t +s,@GDB_DATADIR_PATH@,$GDB_DATADIR_PATH,;t t +s,@pythondir@,$pythondir,;t t s,@subdirs@,$subdirs,;t t s,@TARGET_OBS@,$TARGET_OBS,;t t s,@PKGVERSION@,$PKGVERSION,;t t @@ -21880,6 +22023,9 @@ s,@WINDRES@,$WINDRES,;t t s,@ac_ct_WINDRES@,$ac_ct_WINDRES,;t t s,@MIG@,$MIG,;t t s,@ac_ct_MIG@,$ac_ct_MIG,;t t +s,@LIBICONV@,$LIBICONV,;t t +s,@LIBICONV_INCLUDE@,$LIBICONV_INCLUDE,;t t +s,@LIBICONV_LIBDIR@,$LIBICONV_LIBDIR,;t t s,@READLINE@,$READLINE,;t t s,@READLINE_DEPS@,$READLINE_DEPS,;t t s,@READLINE_CFLAGS@,$READLINE_CFLAGS,;t t @@ -21944,7 +22090,6 @@ s,@CONFIG_UNINSTALL@,$CONFIG_UNINSTALL,;t t s,@target_subdir@,$target_subdir,;t t s,@frags@,$frags,;t t s,@nm_h@,$nm_h,;t t -s,@LIBICONV@,$LIBICONV,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t s,@gl_LIBOBJS@,$gl_LIBOBJS,;t t diff --git a/gdb/configure.ac b/gdb/configure.ac index 3f81ff2..ff76053 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1,6 +1,6 @@ dnl Autoconf configure script for GDB, the GNU debugger. dnl Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -dnl 2005, 2006, 2007, 2008 +dnl 2005, 2006, 2007, 2008, 2009 dnl Free Software Foundation, Inc. dnl dnl This file is part of GDB. @@ -118,6 +118,51 @@ case ${debugdir} in ;; esac +# GDB's datadir relocation + +gdbdatadir=${datadir}/gdb + +AC_ARG_WITH([gdb-datadir], + [AS_HELP_STRING([--with-gdb-datadir], + [look for global separate data files in this path [DATADIR/gdb]])], [gdbdatadir="${withval}"]) + +AC_DEFINE_DIR(GDB_DATADIR, gdbdatadir, + [Global directory for GDB data files. ]) + +if test "x$exec_prefix" = xNONE || test "x$exec_prefix" = 'x${prefix}'; then + if test "x$prefix" = xNONE; then + test_prefix=/usr/local + else + test_prefix=$prefix + fi +else + test_prefix=$exec_prefix +fi + +case ${gdbdatadir} in + "${test_prefix}"|"${test_prefix}/"*|\ + '${exec_prefix}'|'${exec_prefix}/'*) + AC_DEFINE(GDB_DATADIR_RELOCATABLE, 1, [Define if GDB datadir should be relocated when GDB is moved.]) + ;; +esac +GDB_DATADIR_PATH=${gdbdatadir} +AC_SUBST(GDB_DATADIR_PATH) + +AC_ARG_WITH([pythondir], + [AS_HELP_STRING([--with-pythondir], + [install Python data files in this path [DATADIR/gdb/python]])], [pythondir="${withval}"], [pythondir=no]) + +# If the user passed in a path, define it. Otherwise, compute it at +# runtime based on the possibly-relocatable datadir. +if test "$pythondir" = "no"; then + pythondir='$(GDB_DATADIR_PATH)/python' +else + AC_DEFINE_UNQUOTED(PYTHONDIR, "$pythondir", + [Define to install path for Python sources]) +fi +AC_SUBST(pythondir) + + AC_CONFIG_SUBDIRS(doc testsuite) # Check whether to support alternative target configurations @@ -430,6 +475,8 @@ AC_SEARCH_LIBS(zlibVersion, z, [AC_CHECK_HEADERS(zlib.h)]) # On HP/UX we may need libxpdl for dlgetmodinfo (used by solib-pa64.c). AC_SEARCH_LIBS(dlgetmodinfo, [dl xpdl]) +AM_ICONV + # On alpha-osf, it appears that libtermcap and libcurses are not compatible. # There is a very specific comment in /usr/include/curses.h explaining that # termcap routines built into libcurses must not be used. @@ -649,6 +696,8 @@ if test "${have_libpython}" = yes; then CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_PYTHON_OBS)" CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_PYTHON_DEPS)" CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_PYTHON_SRCS)" + CONFIG_INSTALL="$CONFIG_INSTALL install-python" + CONFIG_UNINSTALL="$CONFIG_UNINSTALL uninstall-python" ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_PYTHON_CFLAGS)" # Flags needed to compile Python code (taken from python-config --cflags). @@ -776,7 +825,8 @@ AC_FUNC_VFORK AC_CHECK_FUNCS([canonicalize_file_name realpath getrusage getuid \ getgid poll pread64 sbrk setpgid setpgrp setsid \ sigaction sigprocmask sigsetmask socketpair syscall \ - ttrace wborder setlocale]) + ttrace wborder setlocale iconvlist]) +AM_LANGINFO_CODESET # Check the return and argument types of ptrace. No canned test for # this, so roll our own. @@ -1930,17 +1980,10 @@ dnl Check for exe extension set on certain hosts (e.g. Win32) AC_EXEEXT dnl Detect the character set used by this host. - -dnl At the moment, we just assume it's ISO-8859-1 (which is a -dnl superset of ASCII containing the characters needed for French, -dnl German, Spanish, Italian, and possibly others), but if were -dnl *were* to support any host character sets other than ISO-8859-1, -dnl here's where we'd detect it. -AC_DEFINE(GDB_DEFAULT_HOST_CHARSET, "ISO-8859-1", +dnl At the moment, we just assume it's UTF-8. +AC_DEFINE(GDB_DEFAULT_HOST_CHARSET, "UTF-8", [Define to be a string naming the default host character set.]) -AM_ICONV - AC_OUTPUT(Makefile .gdbinit:gdbinit.in gnulib/Makefile, [ dnl Autoconf doesn't provide a mechanism for modifying definitions diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 65c3e25..f0cca7d 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -36,7 +36,7 @@ alpha*-*-osf*) alpha*-*-linux*) # Target: Little-endian Alpha running Linux gdb_target_obs="alpha-tdep.o alpha-mdebug-tdep.o alpha-linux-tdep.o \ - solib.o solib-svr4.o" + solib.o solib-svr4.o linux-tdep.o" ;; alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu) # Target: FreeBSD/alpha @@ -63,7 +63,7 @@ alpha*-*-*) am33_2.0*-*-linux*) # Target: Matsushita mn10300 (AM33) running Linux gdb_target_obs="mn10300-tdep.o mn10300-linux-tdep.o corelow.o \ - solib.o solib-svr4.o" + solib.o solib-svr4.o linux-tdep.o" ;; arm*-wince-pe | arm*-*-mingw32ce*) @@ -128,7 +128,7 @@ hppa*-*-hpux*) hppa*-*-linux*) # Target: HP PA-RISC running Linux gdb_target_obs="hppa-tdep.o hppa-linux-tdep.o glibc-tdep.o \ - solib.o solib-svr4.o symfile-mem.o" + solib.o solib-svr4.o symfile-mem.o linux-tdep.o" ;; hppa*-*-netbsd*) # Target: NetBSD/hppa @@ -218,7 +218,7 @@ i[34567]86-*-*) ia64-*-linux*) # Target: Intel IA-64 running GNU/Linux gdb_target_obs="ia64-tdep.o ia64-linux-tdep.o \ - solib.o solib-svr4.o symfile-mem.o" + solib.o solib-svr4.o symfile-mem.o linux-tdep.o" build_gdbserver=yes ;; ia64*-*-*) @@ -242,7 +242,8 @@ m32c-*-*) m32r*-*-linux*) # Target: Renesas M32R running GNU/Linux gdb_target_obs="m32r-tdep.o m32r-linux-tdep.o remote-m32r-sdi.o \ - glibc-tdep.o solib.o solib-svr4.o symfile-mem.o" + glibc-tdep.o solib.o solib-svr4.o symfile-mem.o \ + linux-tdep.o" gdb_sim=../sim/m32r/libsim.a build_gdbserver=yes ;; @@ -267,7 +268,7 @@ fido-*-elf*) m68*-*-linux*) # Target: Motorola m68k with a.out and ELF gdb_target_obs="m68k-tdep.o m68klinux-tdep.o solib.o solib-svr4.o \ - glibc-tdep.o symfile-mem.o" + glibc-tdep.o symfile-mem.o linux-tdep.o" build_gdbserver=yes ;; m68*-*-netbsd* | m68*-*-knetbsd*-gnu) @@ -303,7 +304,8 @@ mips*-sgi-irix6*) mips*-*-linux*) # Target: Linux/MIPS gdb_target_obs="mips-tdep.o mips-linux-tdep.o glibc-tdep.o \ - corelow.o solib.o solib-svr4.o symfile-mem.o" + corelow.o solib.o solib-svr4.o symfile-mem.o \ + linux-tdep.o" gdb_sim=../sim/mips/libsim.a build_gdbserver=yes ;; @@ -354,7 +356,8 @@ powerpc-*-aix* | rs6000-*-*) powerpc-*-linux* | powerpc64-*-linux*) # Target: PowerPC running Linux gdb_target_obs="rs6000-tdep.o ppc-linux-tdep.o ppc-sysv-tdep.o \ - solib.o solib-svr4.o corelow.o symfile-mem.o" + solib.o solib-svr4.o corelow.o symfile-mem.o \ + linux-tdep.o" gdb_sim=../sim/ppc/libsim.a build_gdbserver=yes ;; @@ -381,7 +384,8 @@ score-*-*) sh*-*-linux*) # Target: GNU/Linux Super-H gdb_target_obs="sh-tdep.o sh64-tdep.o sh-linux-tdep.o monitor.o \ - dsrec.o solib.o solib-svr4.o symfile-mem.o glibc-tdep.o" + dsrec.o solib.o solib-svr4.o symfile-mem.o glibc-tdep.o \ + linux-tdep.o" gdb_sim=../sim/sh/libsim.a build_gdbserver=yes ;; @@ -409,13 +413,14 @@ sh*) sparc-*-linux*) # Target: GNU/Linux SPARC gdb_target_obs="sparc-tdep.o sparc-sol2-tdep.o sol2-tdep.o \ - sparc-linux-tdep.o solib.o solib-svr4.o symfile-mem.o" + sparc-linux-tdep.o solib.o solib-svr4.o symfile-mem.o \ + linux-tdep.o" ;; sparc64-*-linux*) # Target: GNU/Linux UltraSPARC gdb_target_obs="sparc64-tdep.o sparc64-sol2-tdep.o sol2-tdep.o \ sparc64-linux-tdep.o sparc-tdep.o sparc-sol2-tdep.o \ - sparc-linux-tdep.o solib.o solib-svr4.o" + sparc-linux-tdep.o solib.o solib-svr4.o linux-tdep.o" build_gdbserver=yes ;; sparc*-*-freebsd* | sparc*-*-kfreebsd*-gnu) @@ -542,7 +547,8 @@ x86_64-*-openbsd*) xtensa*-*-linux*) gdb_target=linux # Target: GNU/Linux Xtensa gdb_target_obs="xtensa-tdep.o xtensa-config.o xtensa-linux-tdep.o \ - solib.o solib-svr4.o corelow.o symfile-mem.o" + solib.o solib-svr4.o corelow.o symfile-mem.o \ + linux-tdep.o" build_gdbserver=yes ;; xtensa*) diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y index 5f5ee3a..a8f8f30 100644 --- a/gdb/cp-name-parser.y +++ b/gdb/cp-name-parser.y @@ -1,7 +1,6 @@ /* YACC parser for C++ names, for GDB. - Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 - Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. Parts of the lexer are based on c-exp.y from GDB. @@ -501,7 +500,7 @@ operator : OPERATOR NEW | OPERATOR ARROW { $$ = make_operator ("->", 2); } | OPERATOR '(' ')' - { $$ = make_operator ("()", 0); } + { $$ = make_operator ("()", 2); } | OPERATOR '[' ']' { $$ = make_operator ("[]", 2); } ; diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c index c6c5617..4b84348 100644 --- a/gdb/cp-namespace.c +++ b/gdb/cp-namespace.c @@ -30,26 +30,13 @@ #include "dictionary.h" #include "command.h" #include "frame.h" +#include "buildsym.h" /* List of using directives that are active in the current file. */ -static struct using_direct *using_list; - -static struct using_direct *cp_add_using (const char *name, - unsigned int inner_len, - unsigned int outer_len, - struct using_direct *next); - static struct using_direct *cp_copy_usings (struct using_direct *using, struct obstack *obstack); -static struct symbol *lookup_namespace_scope (const char *name, - const char *linkage_name, - const struct block *block, - const domain_enum domain, - const char *scope, - int scope_len); - static struct symbol *lookup_symbol_file (const char *name, const char *linkage_name, const struct block *block, @@ -78,31 +65,6 @@ static struct symbol *lookup_possible_namespace_symbol (const char *name); static void maintenance_cplus_namespace (char *args, int from_tty); -/* Set up support for dealing with C++ namespace info in the current - symtab. */ - -void cp_initialize_namespace () -{ - using_list = NULL; -} - -/* Add all the using directives we've gathered to the current symtab. - STATIC_BLOCK should be the symtab's static block; OBSTACK is used - for allocation. */ - -void -cp_finalize_namespace (struct block *static_block, - struct obstack *obstack) -{ - if (using_list != NULL) - { - block_set_using (static_block, - cp_copy_usings (using_list, obstack), - obstack); - using_list = NULL; - } -} - /* Check to see if SYMBOL refers to an object contained within an anonymous namespace; if so, add an appropriate using directive. */ @@ -136,14 +98,17 @@ cp_scan_for_anonymous_namespaces (const struct symbol *symbol) "(anonymous namespace)", ANONYMOUS_NAMESPACE_LEN) == 0) { + int outer_len = (previous_component == 0 ? 0 : previous_component - 2); + char outer[outer_len+1]; + + strncpy(outer, name, outer_len); + + outer[outer_len] = '\0'; /* We've found a component of the name that's an anonymous namespace. So add symbols in it to the namespace given by the previous component if there is one, or to the global namespace if there isn't. */ - cp_add_using_directive (name, - previous_component == 0 - ? 0 : previous_component - 2, - next_component); + cp_add_using_directive (outer, name, "", "", 0); } /* The "+ 2" is for the "::". */ previous_component = next_component + 2; @@ -154,32 +119,27 @@ cp_scan_for_anonymous_namespaces (const struct symbol *symbol) } } -/* Add a using directive to using_list. NAME is the start of a string - that should contain the namespaces we want to add as initial - substrings, OUTER_LENGTH is the end of the outer namespace, and - INNER_LENGTH is the end of the inner namespace. If the using - directive in question has already been added, don't add it - twice. */ +/* Add a using directive to using_list. If the using directive in question + has already been added, don't add it twice. */ void -cp_add_using_directive (const char *name, unsigned int outer_length, - unsigned int inner_length) +cp_add_using_directive (const char *outer, const char *inner, const char* alias, + const char *declaration, const int line_number) { struct using_direct *current; struct using_direct *new; /* Has it already been added? */ - for (current = using_list; current != NULL; current = current->next) + for (current = using_directives; current != NULL; current = current->next) { - if ((strncmp (current->inner, name, inner_length) == 0) - && (strlen (current->inner) == inner_length) - && (strlen (current->outer) == outer_length)) + if (strcmp (current->inner, inner) == 0 + && strcmp (current->outer, outer) == 0) return; } - using_list = cp_add_using (name, inner_length, outer_length, - using_list); + using_directives = cp_add_using (outer, inner, alias, declaration, + line_number,using_directives); } /* Record the namespace that the function defined by SYMBOL was @@ -230,26 +190,31 @@ cp_is_anonymous (const char *namespace) != NULL); } -/* Create a new struct using direct whose inner namespace is the - initial substring of NAME of leng INNER_LEN and whose outer - namespace is the initial substring of NAME of length OUTER_LENGTH. +/* Create a new struct using direct whose inner namespace is INNER + and whose outer namespace is OUTER. ALIAS is the name of the imported + namespace in the current scope. If ALIAS is an empty string then the + namespace is known by its original name. Set its next member in the linked list to NEXT; allocate all memory using xmalloc. It copies the strings, so NAME can be a temporary string. */ -static struct using_direct * -cp_add_using (const char *name, - unsigned int inner_len, - unsigned int outer_len, +struct using_direct * +cp_add_using (const char *outer, + const char *inner, + const char *alias, + const char *declaration, + const int line_number, struct using_direct *next) { struct using_direct *retval; - gdb_assert (outer_len < inner_len); - retval = xmalloc (sizeof (struct using_direct)); - retval->inner = savestring (name, inner_len); - retval->outer = savestring (name, outer_len); + retval->inner = savestring (inner, strlen(inner)); + retval->outer = savestring (outer, strlen(outer)); + retval->alias = savestring (alias, strlen(alias)); + retval->declaration = savestring (declaration, strlen(declaration)); + retval->line_number = line_number; + retval->next = next; return retval; @@ -274,7 +239,11 @@ cp_copy_usings (struct using_direct *using, retval->inner = obsavestring (using->inner, strlen (using->inner), obstack); retval->outer = obsavestring (using->outer, strlen (using->outer), - obstack); + obstack); + retval->alias = obsavestring (using->alias, strlen (using->alias), + obstack); + retval->declaration = obsavestring (using->declaration, strlen (using->declaration), + obstack); retval->next = cp_copy_usings (using->next, obstack); xfree (using->inner); @@ -299,8 +268,14 @@ cp_lookup_symbol_nonlocal (const char *name, const struct block *block, const domain_enum domain) { - return lookup_namespace_scope (name, linkage_name, block, domain, - block_scope (block), 0); + + struct symbol* sym = lookup_namespace_scope(name, linkage_name, block, + domain, block_scope(block), 0); + + if (sym != NULL) + return sym; + + return lookup_symbol_file(name, linkage_name, block, domain, 0); } /* Lookup NAME at namespace scope (or, in C terms, in static and @@ -318,7 +293,7 @@ cp_lookup_symbol_nonlocal (const char *name, "A::x", and if that call fails, then the first call looks for "x". */ -static struct symbol * +struct symbol * lookup_namespace_scope (const char *name, const char *linkage_name, const struct block *block, @@ -354,10 +329,43 @@ lookup_namespace_scope (const char *name, namespace = alloca (scope_len + 1); strncpy (namespace, scope, scope_len); namespace[scope_len] = '\0'; - return cp_lookup_symbol_namespace (namespace, name, linkage_name, + return cp_lookup_symbol_namespace_incremental (namespace, name, linkage_name, block, domain); } +/* Searches the for the given NAME in the given NAMESPACE, using import + statements implied by the given BLOCK, *and its' parents*. */ +struct symbol * +cp_lookup_symbol_namespace_incremental (const char *namespace, + const char *name, + const char *linkage_name, + const struct block *block, + const domain_enum domain) +{ + struct symbol *sym; + const struct block *global_block = block_global_block (block); + + /* Check if either no block is specified or it's a global block. */ + + if (global_block == NULL) + return NULL; + + while (block != global_block) + { + sym = cp_lookup_symbol_namespace (namespace, name, linkage_name, block, domain); + + if (sym != NULL) + return sym; + + block = BLOCK_SUPERBLOCK (block); + } + + /* We've reached the global block without finding a result. */ + + return NULL; +} + + /* Look up NAME in the C++ namespace NAMESPACE, applying the using directives that are active in BLOCK. Other arguments are as in cp_lookup_symbol_nonlocal. */ @@ -370,7 +378,7 @@ cp_lookup_symbol_namespace (const char *namespace, const domain_enum domain) { const struct using_direct *current; - struct symbol *sym; + struct symbol *sym = NULL; /* First, go through the using directives. If any of them add new names to the namespace we're searching in, see if we can find a @@ -380,15 +388,42 @@ cp_lookup_symbol_namespace (const char *namespace, current != NULL; current = current->next) { - if (strcmp (namespace, current->outer) == 0) + + int current_line = find_pc_line (get_frame_pc (get_current_frame ()), 0).line; + + if (strcmp (namespace, current->outer) == 0 && current->line_number < current_line) { - sym = cp_lookup_symbol_namespace (current->inner, - name, - linkage_name, - block, - domain); - if (sym != NULL) + + if(strcmp ("", current->declaration) != 0){ + if(strcmp (name, current->declaration) == 0){ + sym = cp_lookup_symbol_namespace (current->inner, + name, + linkage_name, + block, + domain); + } + + }else{ + /* Check for aliases */ + if(strcmp (name, current->alias) == 0){ + sym = cp_lookup_symbol_namespace (namespace, + current->inner, + linkage_name, + block, + domain); + }else{ + if(strcmp ("", current->alias) == 0){ + sym = cp_lookup_symbol_namespace (current->inner, + name, + linkage_name, + block, + domain); + } + } + } + if (sym != NULL){ return sym; + } } } @@ -398,8 +433,10 @@ cp_lookup_symbol_namespace (const char *namespace, if (namespace[0] == '\0') { - return lookup_symbol_file (name, linkage_name, block, - domain, 0); + sym = lookup_symbol_file (name, linkage_name, + block, domain, + cp_is_anonymous (namespace)); + return sym; } else { diff --git a/gdb/cp-support.c b/gdb/cp-support.c index bf42636..9f04c86 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -175,7 +175,8 @@ mangled_name_to_comp (const char *mangled_name, int options, return ret; } -/* Return the name of the class containing method PHYSNAME. */ +/* Return the name of the class or namespace containing + function, method, or variable PHYSNAME. */ char * cp_class_name_from_physname (const char *physname) diff --git a/gdb/cp-support.h b/gdb/cp-support.h index 837ca6c..23f8d5b 100644 --- a/gdb/cp-support.h +++ b/gdb/cp-support.h @@ -38,14 +38,28 @@ struct demangle_component; /* This struct is designed to store data from using directives. It says that names from namespace INNER should be visible within - namespace OUTER. OUTER should always be a strict initial substring - of INNER. These form a linked list; NEXT is the next element of - the list. */ + namespace OUTER These form a linked list; NEXT is the next element of + the list. ALIAS is set to a non empty string if the imported namespace + has been aliased.Eg: + namespace C=A::B; + ALIAS = "C" + DECLARATION is the name of the imported declaration, if this import + statement represents one. Eg: + using A::x; + Where x is variable in namespace A. declaration is set to x. +*/ struct using_direct { char *inner; char *outer; + + char *alias; + + char *declaration; + + int line_number; + struct using_direct *next; }; @@ -54,6 +68,7 @@ struct using_direct extern char *cp_canonicalize_string (const char *string); + extern char *cp_class_name_from_physname (const char *physname); extern char *method_name_from_physname (const char *physname); @@ -76,9 +91,18 @@ extern struct type *cp_lookup_rtti_type (const char *name, extern int cp_is_anonymous (const char *namespace); -extern void cp_add_using_directive (const char *name, - unsigned int outer_length, - unsigned int inner_length); +extern void cp_add_using_directive (const char *outer, + const char *inner, + const char *alias, + const char *declaration, + const int line_number); + +extern struct using_direct *cp_add_using (const char *outer, + const char *inner, + const char *alias, + const char *declaration, + const int line_number, + struct using_direct *next); extern void cp_initialize_namespace (void); @@ -98,6 +122,19 @@ extern struct symbol *cp_lookup_symbol_nonlocal (const char *name, const struct block *block, const domain_enum domain); +extern struct symbol *lookup_namespace_scope (const char *name, + const char *linkage_name, + const struct block *block, + const domain_enum domain, + const char *scope, + int scope_len); + +extern struct symbol *cp_lookup_symbol_namespace_incremental (const char *namespace, + const char *name, + const char *linkage_name, + const struct block *block, + const domain_enum domain); + extern struct symbol *cp_lookup_symbol_namespace (const char *namespace, const char *name, const char *linkage_name, diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c index 8b7d868..dcd32cb 100644 --- a/gdb/cp-valprint.c +++ b/gdb/cp-valprint.c @@ -461,6 +461,7 @@ cp_print_static_field (struct type *type, if (TYPE_CODE (type) == TYPE_CODE_STRUCT) { CORE_ADDR *first_dont_print; + CORE_ADDR addr; int i; first_dont_print @@ -470,7 +471,7 @@ cp_print_static_field (struct type *type, while (--i >= 0) { - if (VALUE_ADDRESS (val) == first_dont_print[i]) + if (value_address (val) == first_dont_print[i]) { fputs_filtered ("", @@ -479,12 +480,13 @@ cp_print_static_field (struct type *type, } } - obstack_grow (&dont_print_statmem_obstack, (char *) &VALUE_ADDRESS (val), + addr = value_address (val); + obstack_grow (&dont_print_statmem_obstack, (char *) &addr, sizeof (CORE_ADDR)); CHECK_TYPEDEF (type); cp_print_value_fields (type, type, value_contents_all (val), - value_embedded_offset (val), VALUE_ADDRESS (val), + value_embedded_offset (val), value_address (val), stream, recurse, options, NULL, 1); return; } @@ -492,7 +494,7 @@ cp_print_static_field (struct type *type, opts = *options; opts.deref_ref = 0; val_print (type, value_contents_all (val), - value_embedded_offset (val), VALUE_ADDRESS (val), + value_embedded_offset (val), value_address (val), stream, recurse, &opts, current_language); } diff --git a/gdb/dbxread.c b/gdb/dbxread.c index 115bdef..7f756af 100644 --- a/gdb/dbxread.c +++ b/gdb/dbxread.c @@ -1,6 +1,6 @@ /* Read dbx symbol tables and convert to internal format, for GDB. Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, - 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2008. + 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2008, 2009. Free Software Foundation, Inc. This file is part of GDB. @@ -1188,6 +1188,8 @@ read_dbx_symtab (struct objfile *objfile) struct internal_nlist nlist; CORE_ADDR text_addr; int text_size; + char *sym_name; + int sym_len; char *namestring; int nsl; @@ -1681,6 +1683,28 @@ pos %d"), if (!p) continue; /* Not a debugging symbol. */ + sym_len = 0; + if (psymtab_language == language_cplus) + { + char *new_name, *name = alloca (p - namestring + 1); + memcpy (name, namestring, p - namestring); + name[p - namestring] = '\0'; + new_name = cp_canonicalize_string (name); + if (new_name != NULL) + { + sym_len = strlen (new_name); + sym_name = obsavestring (new_name, sym_len, + &objfile->objfile_obstack); + xfree (new_name); + } + } + + if (sym_len == 0) + { + sym_name = namestring; + sym_len = p - namestring; + } + /* Main processing section for debugging symbols which the initial read through the symbol tables needs to worry about. If we reach this point, the symbol which we are @@ -1698,7 +1722,7 @@ pos %d"), namestring = gdbarch_static_transform_name (gdbarch, namestring); - add_psymbol_to_list (namestring, p - namestring, + add_psymbol_to_list (sym_name, sym_len, VAR_DOMAIN, LOC_STATIC, &objfile->static_psymbols, 0, nlist.n_value, @@ -1710,7 +1734,7 @@ pos %d"), data_sect_index); /* The addresses in these entries are reported to be wrong. See the code that reads 'G's for symtabs. */ - add_psymbol_to_list (namestring, p - namestring, + add_psymbol_to_list (sym_name, sym_len, VAR_DOMAIN, LOC_STATIC, &objfile->global_psymbols, 0, nlist.n_value, @@ -1728,7 +1752,7 @@ pos %d"), || (p == namestring + 1 && namestring[0] != ' ')) { - add_psymbol_to_list (namestring, p - namestring, + add_psymbol_to_list (sym_name, sym_len, STRUCT_DOMAIN, LOC_TYPEDEF, &objfile->static_psymbols, nlist.n_value, 0, @@ -1736,7 +1760,7 @@ pos %d"), if (p[2] == 't') { /* Also a typedef with the same name. */ - add_psymbol_to_list (namestring, p - namestring, + add_psymbol_to_list (sym_name, sym_len, VAR_DOMAIN, LOC_TYPEDEF, &objfile->static_psymbols, nlist.n_value, 0, @@ -1749,7 +1773,7 @@ pos %d"), case 't': if (p != namestring) /* a name is there, not just :T... */ { - add_psymbol_to_list (namestring, p - namestring, + add_psymbol_to_list (sym_name, sym_len, VAR_DOMAIN, LOC_TYPEDEF, &objfile->static_psymbols, nlist.n_value, 0, @@ -1829,7 +1853,7 @@ pos %d"), case 'c': /* Constant, e.g. from "const" in Pascal. */ - add_psymbol_to_list (namestring, p - namestring, + add_psymbol_to_list (sym_name, sym_len, VAR_DOMAIN, LOC_CONST, &objfile->static_psymbols, nlist.n_value, 0, psymtab_language, objfile); @@ -1893,7 +1917,7 @@ pos %d"), pst->textlow = nlist.n_value; textlow_not_set = 0; } - add_psymbol_to_list (namestring, p - namestring, + add_psymbol_to_list (sym_name, sym_len, VAR_DOMAIN, LOC_BLOCK, &objfile->static_psymbols, 0, nlist.n_value, @@ -1961,7 +1985,7 @@ pos %d"), pst->textlow = nlist.n_value; textlow_not_set = 0; } - add_psymbol_to_list (namestring, p - namestring, + add_psymbol_to_list (sym_name, sym_len, VAR_DOMAIN, LOC_BLOCK, &objfile->global_psymbols, 0, nlist.n_value, @@ -3547,6 +3571,7 @@ static struct sym_fns aout_sym_fns = dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */ dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */ dbx_symfile_read, /* sym_read: read a symbol file into symtab */ + NULL, /* sym_read_psymbols */ dbx_symfile_finish, /* sym_finish: finished with file, cleanup */ default_symfile_offsets, /* sym_offsets: parse user's offsets to internal form */ diff --git a/gdb/defs.h b/gdb/defs.h index 845b320..ad6e7d7 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -151,6 +151,9 @@ extern int dbx_commands; /* System root path, used to find libraries etc. */ extern char *gdb_sysroot; +/* GDB datadir, used to store data files. */ +extern char *gdb_datadir; + /* Search path for separate debug files. */ extern char *debug_file_directory; @@ -366,6 +369,9 @@ extern struct cleanup *make_cleanup_fclose (FILE *file); extern struct cleanup *make_cleanup_bfd_close (bfd *abfd); +struct obstack; +extern struct cleanup *make_cleanup_obstack_free (struct obstack *obstack); + extern struct cleanup *make_cleanup_restore_integer (int *variable); extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *); diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 10e7388..d2c0f1e 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -955,8 +955,10 @@ Connect to process ID @var{number}, as with the @code{attach} command. @itemx -x @var{file} @cindex @code{--command} @cindex @code{-x} -Execute @value{GDBN} commands from file @var{file}. @xref{Command -Files,, Command files}. +Execute commands from file @var{file}. If @var{file} ends in +@samp{.py}, then the file is evaluated as Python code. If Python +support is not enabled in this @value{GDBN}, then an error occurs. +@xref{Command Files,, Command files}. @item -eval-command @var{command} @itemx -ex @var{command} @@ -1148,6 +1150,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} @@ -3636,6 +3648,98 @@ A failed Ada assertion. A call to @code{exec}. This is currently only available for HP-UX and @sc{gnu}/Linux. +@item syscall +@itemx syscall @r{[}@var{name} @r{|} @var{number}@r{]} @r{...} +@cindex break on a system call. +A call to or return from a @code{syscall}. If no argument is specified, +then it catches a call to or return from any system call. + +@var{name} can be any valid system call name in the system. You can +use the @value{GDBN} command-line completion facilities to list the +available choices. @xref{Completion,, Command Completion}, for +details on how to do this. + +You may also specify the system call numerically. This may be useful +if @value{GDBN} does not fully support your system's list of system +calls. + +The example below illustrates how this command works if you don't provide +arguments to it: + +@smallexample +(@value{GDBP}) catch syscall +Catchpoint 1 (syscall) +(@value{GDBP}) r +Starting program: /tmp/catch-syscall + +Catchpoint 1 (call to syscall 'close'), 0xffffe424 in __kernel_vsyscall () +(@value{GDBP}) c +Continuing. + +Catchpoint 1 (returned from syscall 'close'), 0xffffe424 in __kernel_vsyscall () +(@value{GDBP}) +@end smallexample + +Here is an example of catching a system call by name: + +@smallexample +(@value{GDBP}) catch syscall chroot +Catchpoint 1 (syscall(s) 'chroot') +(@value{GDBP}) r +Starting program: /tmp/catch-syscall + +Catchpoint 1 (call to syscall 'chroot'), 0xffffe424 in __kernel_vsyscall () +(@value{GDBP}) c +Continuing. + +Catchpoint 1 (returned from syscall 'chroot'), 0xffffe424 in __kernel_vsyscall () +(@value{GDBP}) +@end smallexample + +And last but not least, an example of specifying a system call +numerically: + +@smallexample +(@value{GDBP}) catch syscall 252 +Catchpoint 1 (syscall(s) 'exit_group') +(@value{GDBP}) r +Starting program: /tmp/catch-syscall + +Catchpoint 1 (call to syscall 'exit_group'), 0xffffe424 in __kernel_vsyscall () +(@value{GDBP}) c +Continuing. + +Program exited normally. +(@value{GDBP}) +@end smallexample + +If you configure @value{GDBN} using the @samp{--without-expat} option, +it will not be able to display syscall names. Also, if your +architecture does not have an XML file describing its system calls, +you will not be able to see the syscall names. In either case, you +will see a warning like this: + +@smallexample +(@value{GDBP}) catch syscall +warning: Could not open "syscalls/i386-linux.xml" +warning: Could not load the syscall XML file 'syscalls/i386-linux.xml'. +GDB will not be able to display syscall names. +Catchpoint 1 (syscall) +(@value{GDBP}) +@end smallexample + +Of course, the file name will change depending on your architecture and system. + +Still using the example above, you can also try to catch a syscall by its +number. In this case, you would see something like: + +@smallexample +(@value{GDBP}) catch syscall 252 +Catchpoint 1 (syscall(s) 252) +@end smallexample + +Again, in this case @value{GDBN} would not be able to display syscall's names. + @item fork A call to @code{fork}. This is currently only available for HP-UX and @sc{gnu}/Linux. @@ -4711,6 +4815,24 @@ the program to report that some thread has stopped before prompting for another command. In background execution, @value{GDBN} immediately gives a command prompt so that you can issue other commands while your program runs. +You need to explicitly enable asynchronous mode before you can use +background execution commands. You can use these commands to +manipulate the asynchronous mode setting: + +@table @code +@kindex set target-async +@item set target-async on +Enable asynchronous mode. +@item set target-async off +Disable asynchronous mode. +@kindex show target-async +@item show target-async +Show the current target-async setting. +@end table + +If the target doesn't support async mode, @value{GDBN} issues an error +message if you attempt to use the background execution commands. + To specify background execution, add a @code{&} to the command. For example, the background form of the @code{continue} command is @code{continue&}, or just @code{c&}. The execution commands that accept background execution @@ -4776,11 +4898,6 @@ only the current thread. To stop the whole program in non-stop mode, use @code{interrupt -a}. @end table -You may need to explicitly enable async mode before you can use background -execution commands, with the @code{set target-async 1} command. If the -target doesn't support async mode, @value{GDBN} issues an error message -if you attempt to use the background execution commands. - @node Thread-Specific Breakpoints @subsection Thread-Specific Breakpoints @@ -6536,6 +6653,12 @@ Without this format, @value{GDBN} displays pointers to and arrays of @code{char}, @w{@code{unsigned char}}, and @w{@code{signed char}} as strings. Single-byte members of a vector are displayed as an integer array. + +@item r +@cindex raw printing +Print using the @samp{raw} formatting. By default, @value{GDBN} will +use a type-specific pretty-printer. The @samp{r} format bypasses any +pretty-printer which might exist for the value's type. @end table For example, to print the program counter in hex (@pxref{Registers}), type @@ -7408,6 +7531,20 @@ On HP-UX systems, if you refer to a function or variable name that begins with a dollar sign, @value{GDBN} searches for a user or system name first, before it searches for a convenience variable. +@cindex convenience functions +@value{GDBN} also supplies some @dfn{convenience functions}. These +have a syntax similar to convenience variables. A convenience +function can be used in an expression just like an ordinary function; +however, a convenience function is implemented internally to +@value{GDBN}. + +@table @code +@item help function +@kindex help function +@cindex show all convenience functions +Print a list of all convenience functions. +@end table + @node Registers @section Registers @@ -7931,13 +8068,17 @@ support: @table @code @item set target-charset @var{charset} @kindex set target-charset -Set the current target character set to @var{charset}. We list the -character set names @value{GDBN} recognizes below, but if you type -@code{set target-charset} followed by @key{TAB}@key{TAB}, @value{GDBN} will -list the target character sets it supports. -@end table +Set the current target character set to @var{charset}. If you type +@code{set target-charset} followed by @key{TAB}@key{TAB}, @value{GDBN} +will list the target character sets it supports. + +@item set target-wide-charset @var{charset} +@kindex set target-wide-charset +Set the current target wide character set to @var{charset}. The +target wide character set is the character set used by @code{wchar_t}. +If you type @code{set target-charset} followed by @key{TAB}@key{TAB}, +@value{GDBN} will list the target character sets it supports. -@table @code @item set host-charset @var{charset} @kindex set host-charset Set the current host character set to @var{charset}. @@ -7947,10 +8088,9 @@ system it is running on; you can override that default using the @code{set host-charset} command. @value{GDBN} can only use certain character sets as its host character -set. We list the character set names @value{GDBN} recognizes below, and -indicate which can be host character sets, but if you type -@code{set target-charset} followed by @key{TAB}@key{TAB}, @value{GDBN} will -list the host character sets it supports. +set. If you type @code{set target-charset} followed by +@key{TAB}@key{TAB}, @value{GDBN} will list the host character sets it +supports. @item set charset @var{charset} @kindex set charset @@ -7974,37 +8114,6 @@ Show the name of the current target charset. @end table -@value{GDBN} currently includes support for the following character -sets: - -@table @code - -@item ASCII -@cindex ASCII character set -Seven-bit U.S. @sc{ascii}. @value{GDBN} can use this as its host -character set. - -@item ISO-8859-1 -@cindex ISO 8859-1 character set -@cindex ISO Latin 1 character set -The ISO Latin 1 character set. This extends @sc{ascii} with accented -characters needed for French, German, and Spanish. @value{GDBN} can use -this as its host character set. - -@item EBCDIC-US -@itemx IBM1047 -@cindex EBCDIC character set -@cindex IBM1047 character set -Variants of the @sc{ebcdic} character set, used on some of IBM's -mainframe operating systems. (@sc{gnu}/Linux on the S/390 uses U.S. @sc{ascii}.) -@value{GDBN} cannot use these as its host character set. - -@end table - -Note that these are all single-byte character sets. More work inside -@value{GDBN} is needed to support multi-byte or variable-width character -encodings, like the UTF-8 and UCS-2 encodings of Unicode. - Here is an example of @value{GDBN}'s character set support in action. Assume that the following source code has been placed in the file @file{charset-test.c}: @@ -12510,6 +12619,12 @@ It is possible for the function you call via the @code{print} or the function, or if you passed it incorrect arguments). What happens in that case is controlled by the @code{set unwindonsignal} command. +Similarly, with a C++ program it is possible for the function you +call via the @code{print} or @code{call} command to generate an +exception that is not handled due to the constraints of the dummy +frame. What happens in that case is controlled by the +@code{set unwind-on-terminating-exception} command. + @table @code @item set unwindonsignal @kindex set unwindonsignal @@ -12526,6 +12641,23 @@ received. @kindex show unwindonsignal Show the current setting of stack unwinding in the functions called by @value{GDBN}. + +@item set unwind-on-terminating-exception +@kindex set unwind-on-terminating-exception +@cindex unwind stack in called functions +@cindex call dummy stack unwinding on unhandled exception. +Set unwinding of the stack if a C++ exception is raised but unhandled +while in a function that @value{GDBN} called in the program being +debugged. If set to on (the default), @value{GDBN} unwinds the stack +it created for the call and restores the context to what it was before +the call. If set to off, @value{GDBN} the exception is delivered to +the default C++ exception handler. + +@item show unwind-on-terminating-exception +@kindex show unwind-on-terminating-exception +Show the current setting of stack unwinding in the functions called by +@value{GDBN}. + @end table @cindex weak alias functions @@ -17815,7 +17947,7 @@ command: @table @code @kindex source @cindex execute commands from a file -@item source [@code{-v}] @var{filename} +@item source [@code{-v}] [@code{-p}] @var{filename} Execute the command file @var{filename}. @end table @@ -17832,6 +17964,11 @@ If @code{-v}, for verbose mode, is given then @value{GDBN} displays each command as it is executed. The option must be given before @var{filename}, and is interpreted as part of the filename anywhere else. +If @var{filename} ends in @samp{.py}, or if @code{-p}, for Python, is +given then @value{GDBN} evaluates the contents of the file as Python +code. If Python support is not compiled in to @value{GDBN}, then an +error occurs. + Commands that would ask for confirmation if used interactively proceed without asking when used in a command file. Many @value{GDBN} commands that normally print messages to say what they are doing omit the messages @@ -18093,8 +18230,6 @@ containing @code{end}. For example: @smallexample (@value{GDBP}) python -Type python script -End with a line saying just "end". >print 23 >end 23 @@ -18107,6 +18242,14 @@ in a Python script. This can be controlled using @code{maint set python print-stack}: if @code{on}, the default, then Python stack printing is enabled; if @code{off}, then Python stack printing is disabled. + +@kindex maint set python auto-load +@item maint set python auto-load +By default, @value{GDBN} will attempt to automatically load Python +code when an object file is opened. This can be controlled using +@code{maint set python auto-load}: if @code{on}, the default, then +Python auto-loading is enabled; if @code{off}, then Python +auto-loading is disabled. @end table @node Python API @@ -18114,6 +18257,14 @@ disabled. @cindex python api @cindex programming in python +You can get quick online help for @value{GDBN}'s Python API by issuing +the command @w{@kbd{python help (gdb)}}. + +Functions and methods which have two or more optional arguments allow +them to be specified using keyword syntax. This allows passing some +optional arguments while skipping others. Example: +@w{@code{gdb.some_function ('foo', bar = 1, baz = 2)}}. + @cindex python stdout @cindex python pagination At startup, @value{GDBN} overrides Python's @code{sys.stdout} and @@ -18125,8 +18276,17 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. @menu * Basic Python:: Basic Python Functions. * Exception Handling:: -* Values From Inferior:: +* Auto-loading:: Automatically loading Python code. +* Values From Inferior:: Python representation of values. +* Types From Inferior:: Python representation of types. +* Pretty Printing:: Pretty-printing values. +* Threads In Python:: Accessing inferior threads from Python. * Commands In Python:: Implementing new commands in Python. +* Parameters In Python:: Adding new @value{GDBN} parameters. +* Functions In Python:: Writing new convenience functions. +* Objfiles In Python:: Object files. +* Breakpoints In Python:: Manipulating breakpoints using Python. +* Frames In Python:: Acessing inferior stack frames from Python. @end menu @node Basic Python @@ -18152,10 +18312,30 @@ command as having originated from the user invoking it interactively. It must be a boolean value. If omitted, it defaults to @code{False}. @end defun -@findex gdb.get_parameter -@defun get_parameter parameter -Return the value of a @value{GDBN} parameter. @var{parameter} is a -string naming the parameter to look up; @var{parameter} may contain +@findex gdb.current_objfile +@defun current_objfile +When auto-loading a Python script (@pxref{Auto-loading}), @value{GDBN} +sets the ``current objfile'' to the corresponding objfile. This +function returns the current objfile. If there is no current objfile, +this function returns @code{None}. +@end defun + +@findex gdb.breakpoints +@defun breakpoints +Return a sequence holding all of @value{GDBN}'s breakpoints. +@xref{Breakpoints In Python}, for more information. +@end defun + +@findex gdb.objfiles +@defun objfiles +Return a sequence of all the objfiles current known to @value{GDBN}. +@xref{Objfiles In Python}. +@end defun + +@findex gdb.parameter +@defun parameter name +Return the value of the named @value{GDBN} parameter. @var{name} is a +string naming the parameter to look up; @var{name} may contain spaces if the parameter has a multi-part name. For example, @samp{print object} is a valid parameter name. @@ -18179,6 +18359,28 @@ If no exception is raised, the return value is always an instance of @code{gdb.Value} (@pxref{Values From Inferior}). @end defun +@findex gdb.parse_and_eval +@defun parse_and_eval expression +Parse @var{expression} as an expression in the current language, +evaluate it, and return the result as a @code{gdb.Value}. +@var{expression} must be a string. +@end defun + +@findex gdb.post_event +@defun post_event event +Put @var{event}, a callable object taking no arguments, into +@value{GDBN}'s internal event queue. This callable will be invoked at +some later point, during @value{GDBN}'s event processing. Events +posted using @code{post_event} will be run in the order in which they +were posted; however, there is no way to know when they will be +processed relative to other events inside @value{GDBN}. + +@value{GDBN} is not thread-safe. If your Python program uses multiple +threads, you must be careful to only call @value{GDBN}-specific +functions in the main @value{GDBN} thread. @code{post_event} ensures +this. +@end defun + @findex gdb.write @defun write string Print a string to @value{GDBN}'s paginated standard output stream. @@ -18193,6 +18395,66 @@ Flush @value{GDBN}'s paginated standard output stream. Flushing function. @end defun +@findex gdb.frames +@defun frames +Return a tuple of all frame objects. +@end defun + +@findex gdb.newest_frame +@defun newest_frame +Return the newest frame object. +@end defun + +@findex gdb.selected_frame +@defun selected_frame +Return the selected frame object. +@end defun + +@findex gdb.frame_stop_reason_string +@defun frame_stop_reason_string @var{reason} +Return a string explaining the reason why @value{GDBN} stopped unwinding +frames, as expressed by the given @var{reason} code (an integer, see the +@code{unwind_stop_reason} method in +@xref{Frames In Python,,Accessing inferior stack frames from Python}.) +@end defun + +@findex gdb.read_memory +@defun read_memory @var{address} @var{length} +Read @var{length} bytes of memory from the inferior, starting at @var{address}. +Returns a buffer object, which behaves much like an array or a string. It +can be modified and given to the @code{gdb.write_memory} function. +@end defun + +@findex gdb.write_memory +@defun write_memory @var{address} @var{buffer} @r{[}@var{length}@r{]} +Write the contents of @var{buffer} (a Python object which supports the buffer +protocol, i.e., a string, an array or the object returned from +@code{gdb.read_memory}) to the inferior, starting at @var{address}. If given, +@var{length} determines the number of bytes from @var{buffer} to be written. +@end defun + +@findex gdb.search_memory +@defun search_memory @var{address} @var{length} @var{pattern} @r{[}@var{size}@r{]} @r{[}@var{max_count}@r{]} +Search a region of the inferior memory starting at @var{address} with the given +@var{length}. @var{pattern} can be a string, a byte array, a buffer object, +a number, a @code{gdb.Value} object (@pxref{Values From Inferior}) or a list +or tuple with elements in any combination of those types. If @var{size} is +given and is non-zero, it specifies the size in bytes of a Python scalar or +@code{gdb.Value} in the search pattern. If @var{size} is zero or not specified, + it is taken from the value's type in the current language. +This is useful when one wants to specify the search +pattern as a mixture of types. +Note that this means, for example, that in the case of C-like languages +a search for an untyped 0x42 will search for @samp{(int) 0x42} +which is typically four bytes. @var{max_count} is the highest number of matches +to search for. +@end defun + +@findex gdb.solib_address +@defun solib_address @var{address} +Return the name of the shared library holding the given address, or None. +@end defun + @node Exception Handling @subsubsection Exception Handling @cindex python exceptions @@ -18224,6 +18486,44 @@ message as its value, and the Python call stack backtrace at the Python statement closest to where the @value{GDBN} error occured as the traceback. +@node Auto-loading +@subsubsection Auto-loading + +When a new object file (@pxref{Objfiles In Python}) is read (for +example, due to the @code{file} command, or because the inferior has +loaded a shared library), @value{GDBN} will look for a file named by +adding @samp{-gdb.py} to the object file's real name (the name formed +after following all symlinks and resolving @code{.} and @code{..} +components). If this file exists and is readable, @value{GDBN} will +evaluate it as a Python script. + +If this file does not exist, and if the parameter +@code{debug-file-directory} is set, then @value{GDBN} will append the +object file's real name to the value of this parameter, and try again. + +Finally, if this file does not exist, then @value{GDBN} will look in +subdirectory of @code{gdb_datadir} (whose value is available from +@code{maint show gdb_datadir}). Specifically, @value{GDBN} will take +the value of @code{gdb_datadir}, append @samp{python/auto-load}, and +then append the object file's real name. + +Also, if a separate debug file is used, @value{GDBN} will look for the +@samp{-gdb.py} file both in the directory associated with the +application and the directory associated with the separate debug file. + +When reading a @samp{-gdb.py} file, @value{GDBN} sets the ``current +objfile''. This is available via the @code{gdb.current_objfile} +function. This can be useful for registering objfile-specific +pretty-printers. + +This feature is useful for supplying application-specific debugging +commands and scripts. It can be disabled using @code{maint set python +auto-load}. + +@value{GDBN} does not track which files it has already auto-loaded. +So, your @samp{-gdb.py} file should take care to ensure that it may be +evaluated multiple times without error. + @node Values From Inferior @subsubsection Values From Inferior @cindex values from inferior, with Python @@ -18258,8 +18558,21 @@ bar = some_val['foo'] Again, @code{bar} will also be a @code{gdb.Value} object. -For pointer data types, @code{gdb.Value} provides a method for -dereferencing the pointer to obtain the object it points to. +The following methods are provided: + +@table @code +@defmethod Value address +If the @code{gdb.Value} object is addressable, this will return a new +@code{gdb.Value} object representing the address. Otherwise, this +will throw an exception. +@end defmethod + +@defmethod Value cast type +Cast the @code{gdb.Value} to the type represented by @var{type}, and +return a new @code{gdb.Value}. @var{type} must be a @code{gdb.Type} +object. If the cast cannot be performed for some reason, an exception +is thrown. +@end defmethod @defmethod Value dereference This method returns a new @code{gdb.Value} object whose contents is @@ -18282,7 +18595,7 @@ The result @code{bar} will be a @code{gdb.Value} object holding the value pointed to by @code{foo}. @end defmethod -@defmethod Value string @r{[}encoding @r{[}errors@r{]}@r{]} +@defmethod Value string @r{[}encoding@r{]} @r{[}errors@r{]} If this @code{gdb.Value} represents a string, then this method converts the contents to a Python string. Otherwise, this method will throw an exception. @@ -18309,6 +18622,468 @@ The optional @var{errors} argument is the same as the corresponding argument to Python's @code{string.decode} method. @end defmethod +@defmethod Value type +Return the type of this @code{gdb.Value}. The result is a +@code{gdb.Type} object. +@end defmethod +@end table + +@node Types From Inferior +@subsubsection Types From Inferior + +@cindex gdb.Type +@value{GDBN} represents types from the inferior using the class +@code{gdb.Type}. + +The following methods are provided: + +@table @code +@defmethod Type Type [name [block]] +Construct a new instance of @code{gdb.Type}. + +If @var{name} is given, it specifies the name of a type to look up in +the inferior. + +If @var{block} is given, then @var{name} is looked up in that scope. +Otherwise, it is searched for globally. +@end defmethod + +@defmethod Type code +Return the type code for this type. The type code will be one of the +@code{TYPE_CODE_} constants defined below. +@end defmethod + +@defmethod Type fields +For structure and union types, this method returns the fields. Range +types have two fields, the minimum and maximum values. Enum types +have one field per enum constant. Function and method types have one +field per parameter. The base types of C++ classes are also +represented as fields. If the type has no fields, or does not fit +into one of these categories, an empty sequence will be returned. + +Each field is an object, with some pre-defined attributes: +@table @code +@item bitpos +This attribute is not available for @code{static} fields. For +non-@code{static} fields, the value is the bit position of the field. + +@item name +The name of the field, or @code{None} for anonymous fields. + +@item artificial +This is @code{True} if the field is artificial, usually meaning that +it was provided by the compiler and not the user. This attribute is +always provided, and is @code{False} if the field is not artificial. + +@item bitsize +If the field is packed, or is a bitfield, then this will have a +non-zero value, which is the size of the field in bits. Otherwise, +this will be zero; in this case the field's size is given by its type. + +@item type +The type of the field. +@end table +@end defmethod + +@defmethod Type const +Return a new @code{gdb.Type} object which represents a +@code{const}-qualified variant of this type. +@end defmethod + +@defmethod Type volatile +Return a new @code{gdb.Type} object which represents a +@code{volatile}-qualified variant of this type. +@end defmethod + +@defmethod Type unqualified +Return a new @code{gdb.Type} object which represents an unqualified +variant of this type. That is, the result is neither @code{const} nor +@code{volatile}. +@end defmethod + +@defmethod Type reference +Return a new @code{gdb.Type} object which represents a reference to this +type. +@end defmethod + +@defmethod Type sizeof +Return the size of this type, in target @code{char} units. Usually, a +target's @code{char} type will be an 8-bit byte. However, on some +unusual platforms, this type may have a different size. +@end defmethod + +@defmethod Type strip_typedefs +Return a new @code{gdb.Type} that represents the real type, +after removing all layers of typedefs. +@end defmethod + +@defmethod Type tag +Return the tag name for this type. The tag name is the name after +@code{struct}, @code{union}, or @code{enum} in C; not all languages +have this concept. If this type has no tag name, then @code{None} is +returned. +@end defmethod + +@defmethod Type target +Return a new @code{gdb.Type} object which represents the target type +of this type. + +For a pointer type, the target type is the type of the pointed-to +object. For an array type, the target type is the type of the +elements of the array. For a function type, the target type is the +type of the return value. For a complex type, the target type is the +type of the elements. For a typedef, the target type is the aliased +type. +@end defmethod + +@defmethod Type template_argument n [block] +If this @code{gdb.Type} is a template type, this will return a new +@code{gdb.Type} which represents the type of the @var{n}th template +argument. + +If this @code{gdb.Type} is not a template type, this will throw an +exception. + +If @var{block} is given, then @var{name} is looked up in that scope. +Otherwise, it is searched for globally. +@end defmethod +@end table + + +Each type has a code, which indicates what category this type falls +into. The available type categories are represented by constants +defined in the @code{gdb} module: + +@table @code +@findex TYPE_CODE_PTR +@findex gdb.TYPE_CODE_PTR +@item TYPE_CODE_PTR +The type is a pointer. + +@findex TYPE_CODE_ARRAY +@findex gdb.TYPE_CODE_ARRAY +@item TYPE_CODE_ARRAY +The type is an array. + +@findex TYPE_CODE_STRUCT +@findex gdb.TYPE_CODE_STRUCT +@item TYPE_CODE_STRUCT +The type is a structure. + +@findex TYPE_CODE_UNION +@findex gdb.TYPE_CODE_UNION +@item TYPE_CODE_UNION +The type is a union. + +@findex TYPE_CODE_ENUM +@findex gdb.TYPE_CODE_ENUM +@item TYPE_CODE_ENUM +The type is an enum. + +@findex TYPE_CODE_FLAGS +@findex gdb.TYPE_CODE_FLAGS +@item TYPE_CODE_FLAGS +A bit flags type. +@c FIXME: what is this? + +@findex TYPE_CODE_FUNC +@findex gdb.TYPE_CODE_FUNC +@item TYPE_CODE_FUNC +The type is a function. + +@findex TYPE_CODE_INT +@findex gdb.TYPE_CODE_INT +@item TYPE_CODE_INT +The type is an integer type. + +@findex TYPE_CODE_FLT +@findex gdb.TYPE_CODE_FLT +@item TYPE_CODE_FLT +A floating point type. + +@findex TYPE_CODE_VOID +@findex gdb.TYPE_CODE_VOID +@item TYPE_CODE_VOID +The special type @code{void}. + +@findex TYPE_CODE_SET +@findex gdb.TYPE_CODE_SET +@item TYPE_CODE_SET +A Pascal set type. + +@findex TYPE_CODE_RANGE +@findex gdb.TYPE_CODE_RANGE +@item TYPE_CODE_RANGE +A range type, that is, an integer type with bounds. + +@findex TYPE_CODE_STRING +@findex gdb.TYPE_CODE_STRING +@item TYPE_CODE_STRING +A string type. Note that this is only used for certain languages with +language-defined string types; C strings are not represented this way. + +@findex TYPE_CODE_BITSTRING +@findex gdb.TYPE_CODE_BITSTRING +@item TYPE_CODE_BITSTRING +A string of bits. + +@findex TYPE_CODE_ERROR +@findex gdb.TYPE_CODE_ERROR +@item TYPE_CODE_ERROR +An unknown or erroneous type. + +@findex TYPE_CODE_METHOD +@findex gdb.TYPE_CODE_METHOD +@item TYPE_CODE_METHOD +A C++ method type. + +@findex TYPE_CODE_METHODPTR +@findex gdb.TYPE_CODE_METHODPTR +@item TYPE_CODE_METHODPTR +A pointer-to-member-function. + +@findex TYPE_CODE_MEMBERPTR +@findex gdb.TYPE_CODE_MEMBERPTR +@item TYPE_CODE_MEMBERPTR +A pointer-to-member. + +@findex TYPE_CODE_REF +@findex gdb.TYPE_CODE_REF +@item TYPE_CODE_REF +A reference type. + +@findex TYPE_CODE_CHAR +@findex gdb.TYPE_CODE_CHAR +@item TYPE_CODE_CHAR +A character type. + +@findex TYPE_CODE_BOOL +@findex gdb.TYPE_CODE_BOOL +@item TYPE_CODE_BOOL +A boolean type. + +@findex TYPE_CODE_COMPLEX +@findex gdb.TYPE_CODE_COMPLEX +@item TYPE_CODE_COMPLEX +A complex float type. + +@findex TYPE_CODE_TYPEDEF +@findex gdb.TYPE_CODE_TYPEDEF +@item TYPE_CODE_TYPEDEF +A typedef to some other type. + +@findex TYPE_CODE_TEMPLATE +@findex gdb.TYPE_CODE_TEMPLATE +@item TYPE_CODE_TEMPLATE +A C++ template type. Note that this is not used for a template +instantiation; those appear as ordinary struct types. +@c FIXME I hope that is true + +@findex TYPE_CODE_TEMPLATE_ARG +@findex gdb.TYPE_CODE_TEMPLATE_ARG +@item TYPE_CODE_TEMPLATE_ARG +A C++ template argument. +@c FIXME: is this ever used? + +@findex TYPE_CODE_NAMESPACE +@findex gdb.TYPE_CODE_NAMESPACE +@item TYPE_CODE_NAMESPACE +A C++ namespace. + +@findex TYPE_CODE_DECFLOAT +@findex gdb.TYPE_CODE_DECFLOAT +@item TYPE_CODE_DECFLOAT +A decimal floating point type. + +@findex TYPE_CODE_INTERNAL_FUNCTION +@findex gdb.TYPE_CODE_INTERNAL_FUNCTION +@item TYPE_CODE_INTERNAL_FUNCTION +A function internal to @value{GDBN}. This is the type used to represent +convenience functions. +@end table + +@node Pretty Printing +@subsubsection Pretty Printing + +@value{GDBN} provides a mechanism to allow pretty-printing of values +using Python code. This mechanism works for both MI and the CLI. + +A pretty-printer is an object that implements a specific interface. +There is no predefined base class for pretty-printers. + +@defop Operation {pretty printer} __init__ (self, val) +When printing a value, @value{GDBN} constructs an instance of the +pretty-printer. @var{val} is the value to be printed, an instance of +@code{gdb.Value}. +@end defop + +@defop Operation {pretty printer} children (self) +When printing a value, @value{GDBN} will call this method to compute +the children of the value passed to the object's constructor. + +This method must return an object conforming to the Python iterator +protocol. Each element returned by the iterator must be a tuple +holding two elements. The first element is the ``name'' of the child; +the second element is the child's value. The value can be any Python +object which is convertible to a @value{GDBN} value. + +This method is optional. If it does not exist, @value{GDBN} will act +as though the value has no children. +@end defop + +@defop Operation {pretty printer} display_hint (self) +This method must return a string. The CLI may use this to change the +formatting of children of a value. The result will also be supplied +to an MI consumer as a @samp{displayhint} attribute of the variable +being printed. + +Some display hints are predefined by @value{GDBN}: + +@table @samp +@item array +Indicate that the object being printed is ``array-like''. The CLI +uses this to respect parameters such as @code{set print elements} and +@code{set print array}. + +@item map +Indicate that the object being printed is ``map-like'', and that the +children of this value can be assumed to alternate between keys and +values. + +@item string +Indicate that the object being printed is ``string-like''. If the +printer's @code{to_string} method returns a Python string of some +kind, then @value{GDBN} will call its internal language-specific +string-printing function to format the string. For the CLI this means +adding quotation marks, possibly escaping some characters, respecting +@code{set print elements}, and the like. +@end table +@end defop + +@defop Operation {pretty printer} to_string (self) +@value{GDBN} will call this method to display the string +representation of the value passed to the object's constructor. + +When printing from the CLI, if the @code{to_string} method exists, +then @value{GDBN} will prepend its result to the values returned by +@code{children}. + +If this method returns a string, it is printed verbatim. Otherwise, +the result is converted to a @code{gdb.Value}, following the usual +algorithm. Then @value{GDBN} prints this value; this may possibly +result in a call to another pretty-printer. If the result is not +convertible to @code{gdb.Value}, an exception is raised. +@end defop + +@subsubsection Selecting Pretty-Printers + +The Python list @code{gdb.pretty_printers} contains an array of +functions that have been registered via addition as a pretty-printer. +Each function will be called with a @code{gdb.Value} to be +pretty-printed. Each @code{gdb.Objfile} also contains a +@code{pretty_printers} attribute. A function on one of these lists +takes a single @code{gdb.Value} argument and returns a pretty-printer +object conforming to the interface definition above. If this function +cannot create a pretty-printer for the value, it should return +@code{None}. + +@value{GDBN} first checks the @code{pretty_printers} attribute of each +@code{gdb.Objfile} and iteratively calls each function in the list for +that @code{gdb.Objfile} until it receives a pretty-printer object. +After these @code{gdb.Objfile} have been exhausted, it tries the +global @code{gdb.pretty-printers} list, again calling each function +until an object is returned. + +The order in which the objfiles are searched is not specified. +Functions are always invoked from the head of the +@code{gdb.pretty-printers} list, and iterated over sequentially until +the end of the list, or a printer object is returned. + +Here is an example showing how a @code{std::string} printer might be +written: + +@smallexample +class StdStringPrinter: + "Print a std::string" + + def __init__ (self, val): + self.val = val + + def to_string (self): + return self.val['_M_dataplus']['_M_p'] +@end smallexample + +And here is an example showing how a lookup function for +the printer example above might be written. + +@smallexample +def str_lookup_function (val): + + lookup_tag = val.type ().tag () + regex = re.compile ("^std::basic_string$") + if lookup_tag == None: + return None + if regex.match (lookup_tag): + return StdStringPrinter (val) + + return None +@end smallexample + +The example lookup function extracts the value's type, and attempts to +match it to a type that it can pretty-print. If it is a type the +printer can pretty-print, it will return a printer object. If not, it +returns: @code{None}. + +We recommend that you put your core pretty-printers into a versioned +python package, and then restrict your auto-loaded code to idempotent +behavior -- for example, just @code{import}s of your printer modules, +followed by a call to a register pretty-printers with the current +objfile. This approach will scale more nicely to multiple inferiors, +potentially using different library versions. + +For example, in addition to the above, this code might appear in +@code{gdb.libstdcxx.v6}: + +@smallexample +def register_printers (objfile): + objfile.pretty_printers.add (str_lookup_function) +@end smallexample + +And then the corresponding contents of the auto-load file would be: + +@smallexample +import gdb.libstdcxx.v6 +gdb.libstdcxx.v6.register_printers (gdb.current_objfile ()) +@end smallexample + +@node Threads In Python +@subsubsection Threads In Python + +Python scripts can access information about the inferior's threads +using some functions provided by @value{GDBN}. Like all of +@value{GDBN}'s Python additions, these are in the @code{gdb} module: + +@findex gdb.threads +@defun threads +This function returns a tuple holding all the thread IDs which are +valid when the function is called. If there are no valid threads, +this will return @code{None}. +@end defun + +@findex gdb.current_thread +@defun current_thread +This function returns the thread ID of the selected thread. If there +is no selected thread, this will return @code{None}. +@end defun + +@findex gdb.switch_to_thread +@defun switch_to_thread id +This changes @value{GDBN}'s currently selected thread to the thread +given by @var{id}. @var{id} must be a valid thread ID as returned by +@code{threads}. If @var{id} is invalid, this function throws an +exception. +@end defun + @node Commands In Python @subsubsection Commands In Python @@ -18320,7 +19095,7 @@ You can implement new @value{GDBN} CLI commands in Python. A CLI command is implemented using an instance of the @code{gdb.Command} class, most commonly using a subclass. -@defmethod Command __init__ name @var{command-class} @r{[}@var{completer-class} @var{prefix}@r{]} +@defmethod Command __init__ name @var{command_class} @r{[}@var{completer_class}@r{]} @r{[}@var{prefix}@r{]} The object initializer for @code{Command} registers the new command with @value{GDBN}. This initializer is normally invoked from the subclass' own @code{__init__} method. @@ -18332,11 +19107,11 @@ an exception is raised. There is no support for multi-line commands. -@var{command-class} should be one of the @samp{COMMAND_} constants +@var{command_class} should be one of the @samp{COMMAND_} constants defined below. This argument tells @value{GDBN} how to categorize the new command in the help system. -@var{completer-class} is an optional argument. If given, it should be +@var{completer_class} is an optional argument. If given, it should be one of the @samp{COMPLETE_} constants defined below. This argument tells @value{GDBN} how to perform completion for this command. If not given, @value{GDBN} will attempt to complete using the object's @@ -18563,6 +19338,374 @@ registration of the command with @value{GDBN}. Depending on how the Python code is read into @value{GDBN}, you may need to import the @code{gdb} module explicitly. + +@node Parameters In Python +@subsubsection Parameters In Python + +@cindex parameters in python +@cindex python parameters +@tindex gdb.Parameter +@tindex Parameter +You can implement new @value{GDBN} parameters using Python. A new +parameter is implemented as an instance of the @code{gdb.Parameter} +class. Parameters are exposed to the user via the @code{set} and +@code{show} commands. + +@defmethod Parameter __init__ name @var{command-class} @var{parameter-class} @r{[}@var{enum-sequence}@r{]} +The object initializer for @code{Parameter} registers the new +parameter with @value{GDBN}. This initializer is normally invoked +from the subclass' own @code{__init__} method. + +@var{name} is the name of the new parameter. If @var{name} consists +of multiple words, then the initial words are looked for as prefix +commands. In this case, if one of the prefix commands does not exist, +an exception is raised. + +@var{command-class} should be one of the @samp{COMMAND_} constants +(@pxref{Commands In Python}). This argument tells @value{GDBN} how to +categorize the new parameter in the help system. + +@var{parameter-class} should be one of the @samp{PARAM_} constants +defined below. This argument tells @value{GDBN} the type of the new +parameter; this information is used for input validation and +completion. + +If @var{parameter-class} is @code{PARAM_ENUM}, then +@var{enum-sequence} must be a sequence of strings. These strings +represent the possible values for the parameter. + +If @var{parameter-class} is not @code{PARAM_ENUM}, then the presence +of a fourth argument will cause an exception to be thrown. + +The help text for the new parameter is taken from the Python +documentation string for the parameter's class, if there is one. If +there is no documentation string, a default value is used. +@end defmethod + +@defivar Parameter set_doc +If this attribute exists, and is a string, then its value is used as +the help text for this parameter's @code{set} command. The value is +examined when @code{Parameter.__init__} is invoked; subsequent changes +have no effect. +@end defivar + +@defivar Parameter show_doc +If this attribute exists, and is a string, then its value is used as +the help text for this parameter's @code{show} command. The value is +examined when @code{Parameter.__init__} is invoked; subsequent changes +have no effect. +@end defivar + +@defivar Parameter value +The @code{value} attribute holds the underlying value of the +parameter. It can be read and assigned to just as any other +attribute. @value{GDBN} does validation when assignments are made. +@end defivar + + +When a new parameter is defined, its type must be specified. The +available types are represented by constants defined in the @code{gdb} +module: + +@table @code +@findex PARAM_BOOLEAN +@findex gdb.PARAM_BOOLEAN +@item PARAM_BOOLEAN +The value is a plain boolean. The Python boolean values, @code{True} +and @code{False} are the only valid values. + +@findex PARAM_AUTO_BOOLEAN +@findex gdb.PARAM_AUTO_BOOLEAN +@item PARAM_AUTO_BOOLEAN +The value has three possible states: true, false, and @samp{auto}. In +Python, true and false are represented using boolean constants, and +@samp{auto} is represented using @code{None}. + +@findex PARAM_UINTEGER +@findex gdb.PARAM_UINTEGER +@item PARAM_UINTEGER +The value is an unsigned integer. The value of 0 should be +interpreted to mean ``unlimited''. + +@findex PARAM_INTEGER +@findex gdb.PARAM_INTEGER +@item PARAM_INTEGER +The value is a signed integer. The value of 0 should be interpreted +to mean ``unlimited''. + +@findex PARAM_STRING +@findex gdb.PARAM_STRING +@item PARAM_STRING +The value is a string. When the user modifies the string, escapes are +translated. + +@findex PARAM_STRING_NOESCAPE +@findex gdb.PARAM_STRING_NOESCAPE +@item PARAM_STRING_NOESCAPE +The value is a string. When the user modifies the string, escapes are +passed through untranslated. + +@findex PARAM_OPTIONAL_FILENAME +@findex gdb.PARAM_OPTIONAL_FILENAME +@item PARAM_OPTIONAL_FILENAME +The value is a either a filename (a string), or @code{None}. + +@findex PARAM_FILENAME +@findex gdb.PARAM_FILENAME +@item PARAM_FILENAME +The value is a filename (a string). + +@findex PARAM_ZINTEGER +@findex gdb.PARAM_ZINTEGER +@item PARAM_ZINTEGER +The value is an integer. This is like @code{PARAM_INTEGER}, except 0 +is interpreted as itself. + +@findex PARAM_ENUM +@findex gdb.PARAM_ENUM +@item PARAM_ENUM +The value is a string, which must be one of a collection string +constants provided when the parameter is created. +@end table + +@node Functions In Python +@subsubsection Writing new convenience functions + +@cindex writing convenience functions +@cindex convenience functions in python +@cindex python convenience functions +@tindex gdb.Function +@tindex Function +You can implement new convenience functions (@pxref{Convenience Vars}) +in Python. A convenience function is an instance of a subclass of the +class @code{gdb.Function}. + +@defmethod Function __init__ name +The initializer for @code{Function} registers the new function with +@value{GDBN}. The argument @var{name} is the name of the function, +a string. The function will be visible to the user as a convenience +variable of type @code{internal function}, whose name is the same as +the given @var{name}. + +The documentation for the new function is taken from the documentation +string for the new class. +@end defmethod + +@defmethod Function invoke @var{*args} +When a convenience function is evaluated, its arguments are converted +to instances of @code{gdb.Value}, and then the function's +@code{invoke} method is called. Note that @value{GDBN} does not +predetermine the arity of convenience functions. Instead, all +available arguments are passed to @code{invoke}, following the +standard Python calling convention. In particular, a convenience +function can have default values for parameters without ill effect. + +The return value of this method is used as its value in the enclosing +expression. If an ordinary Python value is returned, it is converted +to a @code{gdb.Value} following the usual rules. +@end defmethod + +The following code snippet shows how a trivial convenience function can +be implemented in Python: + +@smallexample +class Greet (gdb.Function): + """Return string to greet someone. +Takes a name as argument.""" + + def __init__ (self): + super (Greet, self).__init__ ("greet") + + def invoke (self, name): + return "Hello, %s!" % name.string () + +Greet () +@end smallexample + +The last line instantiates the class, and is necessary to trigger the +registration of the function with @value{GDBN}. Depending on how the +Python code is read into @value{GDBN}, you may need to import the +@code{gdb} module explicitly. + +@node Objfiles In Python +@subsubsection Objfiles In Python + +@cindex objfiles in python +@cindex python objfiles +@tindex gdb.Objfile +@tindex Objfile +@value{GDBN} loads symbols for an inferior from various +symbol-containing files. These include the primary executable file, +any shared libraries used by the inferior, and any separate debug info +files. @value{GDBN} calls these symbol-containing files +@dfn{objfiles}. + +Each objfile is represented by an instance of the @code{gdb.Objfile} +class. + +@defivar Objfile filename +The file name of the objfile as a string. +@end defivar + +@defivar Objfile pretty_printers +The @code{pretty_printers} attribute is used to look up +pretty-printers by type. This is a dictionary which maps regular +expressions (strings) to pretty-printing objects. @xref{Pretty +Printing}, for more information. +@end defivar + +@node Breakpoints In Python +@subsubsection Manipulating breakpoints using Python + +@cindex breakpoints in python +@cindex python breakpoints +@tindex gdb.Breakpoint +@tindex Breakpoint +Python code can manipulate breakpoints via the @code{gdb.Breakpoint} +class. + +@defmethod Breakpoint __init__ location +Create a new breakpoint. @var{location} is a string naming the +location of the breakpoint. The contents can be any location +recognized by the @code{break} command. +@end defmethod + +@defmethod Breakpoint is_valid +Return @code{True} if this @code{Breakpoint} object is valid, +@code{False} otherwise. A @code{Breakpoint} object can become invalid +if the user deletes the breakpoint. In this case, the object still +exists, but the underlying breakpoint does not. +@end defmethod + +@defivar Breakpoint enabled +This attribute is @code{True} if the breakpoint is enabled, and +@code{False} otherwise. This attribute is writable. +@end defivar + +@defivar Breakpoint silent +This attribute is @code{True} if the breakpoint is silent, and +@code{False} otherwise. This attribute is writable. + +Note that a breakpoint can also be silent if it has commands and the +first command is @code{silent}. This is not reported by the +@code{silent} attribute. +@end defivar + +@defivar Breakpoint thread +If the breakpoint is thread-specific, this attribute holds the thread +id. If the breakpoint is not thread-specific, this attribute is +@code{None}. This attribute is writable. +@end defivar + +@defivar Breakpoint ignore_count +This attribute holds the ignore count for the breakpoint, an integer. +This attribute is writable. +@end defivar + +@defivar Breakpoint number +This attribute holds the breakpoint's number -- the identifier used by +the user to manipulate the breakpoint. This attribute is not writable. +@end defivar + +@defivar Breakpoint hit_count +This attribute holds the hit count for the breakpoint, an integer. +This attribute is writable, but currently it can only be set to zero. +@end defivar + +@defivar Breakpoint location +This attribute holds the location of the breakpoint, as specified by +the user. It is a string. This attribute is not writable. +@end defivar + +@defivar Breakpoint condition +This attribute holds the condition of the breakpoint, as specified by +the user. It is a string. If there is no condition, this attribute's +value is @code{None}. This attribute is writable. +@end defivar + +@defivar Breakpoint commands +This attribute holds the commands attached to the breakpoint. If +there are commands, this returns a string holding all the commands, +separated by newlines. If there are no commands, this attribute is +@code{None}. This attribute is not writable. +@end defivar + +@node Frames In Python +@subsubsection Accessing inferior stack frames from Python. + +@cindex frames in python +@tindex gdb.Frame +@tindex Frame +When the debugged program stops, @value{GDBN} is able to analyse its call +stack (@pxref{Frames,,Stack frames}). The @code{gdb.Frame} class +represents a frame in the stack. You can get a tuple containing all the +frames in the stack with the @code{gdb.frames} function, the newest +frame with the @code{gdb.newest_frame} function, and the selected frame +with the @code{gdb.selected_frame} function +(see @xref{Selection,,Selecting a Frame}.) See +@xref{Basic Python,,Basic Python}. + +A @code{gdb.Frame} object has the following methods: + +@table @code +@defmethod Frame equals @code{frame} +Compare frames. +@end defmethod + +@defmethod Frame is_valid +Returns true if the @code{gdb.Frame} object is valid, false if not. +A frame object can become invalid if the frame it refers to doesn't +exist anymore in the inferior. All @code{gdb.Frame} methods will throw +an exception if it is invalid at the time the method call is made. +@end defmethod + +@defmethod Frame name +Returns the function name of the frame, or @code{None} if it can't be +obtained. +@end defmethod + +@defmethod Frame type +Returns the type of the frame. The value can be one of +@code{gdb.NORMAL_FRAME}, @code{gdb.DUMMY_FRAME}, @code{gdb.SIGTRAMP_FRAME} +or @code{gdb.SENTINEL_FRAME}. +@end defmethod + +@defmethod Frame unwind_stop_reason +Return an integer representing the reason why it's not possible to find +frames older than this. Use @code{gdb.frame_stop_reason_string} to convert +the value returned by this function to a string. +@end defmethod + +@defmethod Frame pc +Returns the frame's resume address. +@end defmethod + +@defmethod Frame block +Returns the frame's code block. @c (see @xref{Block,,Code Blocks and Scopes}). +@end defmethod + +@defmethod Frame address_in_block +Returns an address which falls within the frame's code block. +@end defmethod + +@defmethod Frame older +Return the frame immediately older (outer) to this frame. +@end defmethod + +@defmethod Frame newer +Return the frame immediately newer (inner) to this frame. +@end defmethod + +@defmethod Frame find_sal +Return the frame's symtab and line object. @c (see @xref{Symtab_and_line,, Symtab and line}). +@end defmethod + +@defmethod Frame read_var @var{variable} +Return the value of the given variable in this frame. @code{variable} can be +either a string or a @code{gdb.Symbol} object. @c (@pxref{Symbols In Python}). +@end defmethod +@end table + @node Interpreters @chapter Command Interpreters @cindex command interpreters @@ -22273,6 +23416,103 @@ Unfreezing a variable does not update it, only subsequent (gdb) @end smallexample +@subheading The @code{-var-set-visualizer} command +@findex -var-set-visualizer +@anchor{-var-set-visualizer} + +@subsubheading Synopsis + +@smallexample + -var-set-visualizer @var{name} @var{visualizer} +@end smallexample + +@subheading The @code{-var-set-child-range} command +@findex -var-set-child-range +@anchor{-var-set-child-range} + +Set a visualizer for the variable object @var{name}. + +@var{visualizer} is the visualizer to use. The special value +@samp{None} means to disable any visualizer in use. + +If not @samp{None}, @var{visualizer} must be a Python expression. +This expression must evaluate to a callable object which accepts a +single argument. @value{GDBN} will call this object with the value of +the varobj @var{name} as an argument. This function must return an +object which conforms to the pretty-printing interface (@pxref{Pretty +Printing}). + +The pre-defined function @code{gdb.default_visualizer} may be used +to select a visualizer according to the type of the varobj. This is +called when a varobj is created, and so ordinarily is not needed. + +@code{gdb.default_visualizer} looks in the global dictionary named +@code{gdb.pretty_printers}. + +This feature is only available if Python support is enabled. + +@subsubheading Example + +Resetting the visualizer: + +@smallexample +(gdb) +-var-set-visualizer V None +^done +@end smallexample + +Reselecting the default (type-based) visualizer: + +@smallexample +(gdb) +-var-set-visualizer V gdb.default_visualizer +^done +@end smallexample + +Suppose @code{SomeClass} is a visualizer class. A lambda expression +can be used to instantiate this class for a varobj: + +@smallexample +(gdb) +-var-set-visualizer V "lambda val: SomeClass()" +^done +@end smallexample + +@subsubheading Synopsis + +@smallexample + -var-set-child-range @var{name} @var{from} @var{to} +@end smallexample + +Select a sub-range of the children of the variable object @var{name}; +future calls to @code{-var-list-children} will only report the +selected range of children. This allows an MI consumer to avoid +inefficiencies if the varobj has very many children. + +If either @var{from} or @var{to} is less than zero, then sub-range +selection is disabled, and @code{-var-list-children} will report all +children. + +Otherwise, @var{from} and @var{to} are indexes into the array of +children. Children starting at @var{from} and stopping jsut before +@var{to} will be reported. + +@subsubheading Example + +@smallexample +(gdb) + -var-list-children n + ^done,numchild=3,children=[@{name="a",numchild=0,type="int"@}, + @{name="b",numchild=0,type="int"@}, + @{name="c",numchild=0,type="int"@}] +(gdb) + -var-set-child-range n 1 2 +(gdb) + -var-list-children n + ^done,numchild=3,children=[@{name="b",numchild=0,type="int"@}, + @{name="c",numchild=0,type="int"@}] +@end smallexample + @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @node GDB/MI Data Manipulation @@ -23832,6 +25072,10 @@ as possible presense of the @code{frozen} field in the output of @code{-varobj-create}. @item pending-breakpoints Indicates presence of the @option{-f} option to the @code{-break-insert} command. +@item python +Indicates presence of Python scripting support, Python-based +pretty-printing commands, and possible presence of the +@samp{display_hint} field in the output of @code{-var-list-children} @item thread-info Indicates presence of the @code{-thread-info} command. @@ -25402,28 +26646,6 @@ data in a @file{gmon.out} file, be sure to move it to a safe location. Configuring with @samp{--enable-profiling} arranges for @value{GDBN} to be compiled with the @samp{-pg} compiler option. -@kindex maint set linux-async -@kindex maint show linux-async -@cindex asynchronous support -@item maint set linux-async -@itemx maint show linux-async -Control the GNU/Linux native asynchronous support -(@pxref{Background Execution}) of @value{GDBN}. - -GNU/Linux native asynchronous support will be disabled until you use -the @samp{maint set linux-async} command to enable it. - -@kindex maint set remote-async -@kindex maint show remote-async -@cindex asynchronous support -@item maint set remote-async -@itemx maint show remote-async -Control the remote asynchronous support -(@pxref{Background Execution}) of @value{GDBN}. - -Remote asynchronous support will be disabled until you use -the @samp{maint set remote-async} command to enable it. - @kindex maint show-debug-regs @cindex x86 hardware debug registers @item maint show-debug-regs diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index ce11d89..eaa6a13 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -38,6 +38,7 @@ #include "complaints.h" #include "dwarf2-frame.h" +#include "addrmap.h" struct comp_unit; @@ -1499,6 +1500,14 @@ dwarf2_frame_find_fde (CORE_ADDR *pc) struct dwarf2_fde *fde; CORE_ADDR offset; + if (objfile->quick_addrmap) + { + if (!addrmap_find (objfile->quick_addrmap, *pc)) + continue; + } + /* FIXME: Read-in only .debug_frame/.eh_frame without .debug_info? */ + require_partial_symbols (objfile); + fde = objfile_data (objfile, dwarf2_frame_objfile_data); if (fde == NULL) continue; diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c index 75a4ec7..aa8ab33 100644 --- a/gdb/dwarf2expr.c +++ b/gdb/dwarf2expr.c @@ -752,6 +752,13 @@ execute_stack_op (struct dwarf_expr_context *ctx, ctx->initialized = 0; goto no_push; + case DW_OP_push_object_address: + if (ctx->get_object_address == NULL) + error (_("DWARF-2 expression error: DW_OP_push_object_address must " + "have a value to push.")); + result = (ctx->get_object_address) (ctx->baton); + break; + default: error (_("Unhandled dwarf expression opcode 0x%x"), op); } diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h index 7047922..a287b6f 100644 --- a/gdb/dwarf2expr.h +++ b/gdb/dwarf2expr.h @@ -67,10 +67,10 @@ struct dwarf_expr_context The result must be live until the current expression evaluation is complete. */ unsigned char *(*get_subr) (void *baton, off_t offset, size_t *length); +#endif /* Return the `object address' for DW_OP_push_object_address. */ CORE_ADDR (*get_object_address) (void *baton); -#endif /* The current depth of dwarf expression recursion, via DW_OP_call*, DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index cad3db8..2251e48 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -107,6 +107,9 @@ struct dwarf_expr_baton { struct frame_info *frame; struct objfile *objfile; + /* From DW_TAG_variable's DW_AT_location (not DW_TAG_type's + DW_AT_data_location) for DW_OP_push_object_address. */ + CORE_ADDR object_address; }; /* Helper functions for dwarf2_evaluate_loc_desc. */ @@ -163,22 +166,32 @@ dwarf_expr_frame_base (void *baton, gdb_byte **start, size_t * length) *start = find_location_expression (symbaton, length, get_frame_address_in_block (frame)); } - else + else if (SYMBOL_OPS (framefunc) == &dwarf2_locexpr_funcs) { struct dwarf2_locexpr_baton *symbaton; + symbaton = SYMBOL_LOCATION_BATON (framefunc); - if (symbaton != NULL) - { - *length = symbaton->size; - *start = symbaton->data; - } - else - *start = NULL; + gdb_assert (symbaton != NULL); + *start = symbaton->data; + *length = symbaton->size; + } + else if (SYMBOL_OPS (framefunc) == &dwarf2_missing_funcs) + { + struct dwarf2_locexpr_baton *symbaton; + + symbaton = SYMBOL_LOCATION_BATON (framefunc); + gdb_assert (symbaton == NULL); + *start = NULL; + *length = 0; /* unused */ } + else + internal_error (__FILE__, __LINE__, + _("Unsupported SYMBOL_OPS %p for \"%s\""), + SYMBOL_OPS (framefunc), SYMBOL_PRINT_NAME (framefunc)); if (*start == NULL) error (_("Could not find the frame base for \"%s\"."), - SYMBOL_NATURAL_NAME (framefunc)); + SYMBOL_PRINT_NAME (framefunc)); } /* Using the objfile specified in BATON, find the address for the @@ -191,6 +204,119 @@ dwarf_expr_tls_address (void *baton, CORE_ADDR offset) return target_translate_tls_address (debaton->objfile, offset); } +static CORE_ADDR +dwarf_expr_object_address (void *baton) +{ + struct dwarf_expr_baton *debaton = baton; + + /* The message is suppressed in DWARF_BLOCK_EXEC. */ + if (debaton->object_address == 0) + error (_("Cannot resolve DW_OP_push_object_address for a missing object")); + + return debaton->object_address; +} + +/* Address of the variable we are currently referring to. It is set from + DW_TAG_variable's DW_AT_location (not DW_TAG_type's DW_AT_data_location) for + DW_OP_push_object_address. */ + +static CORE_ADDR object_address; + +/* Callers use object_address_set while their callers use the result set so we + cannot run the cleanup at the local block of our direct caller. Still we + should reset OBJECT_ADDRESS at least for the next GDB command. */ + +static void +object_address_cleanup (void *prev_save_voidp) +{ + CORE_ADDR *prev_save = prev_save_voidp; + + object_address = *prev_save; + xfree (prev_save); +} + +/* Set the base address - DW_AT_location - of a variable. It is being later + used to derive other object addresses by DW_OP_push_object_address. + + It would be useful to sanity check ADDRESS - such as for some objects with + unset VALUE_ADDRESS - but some valid addresses may be zero (such as first + objects in relocatable .o files). */ + +void +object_address_set (CORE_ADDR address) +{ + CORE_ADDR *prev_save; + + prev_save = xmalloc (sizeof *prev_save); + *prev_save = object_address; + make_cleanup (object_address_cleanup, prev_save); + + object_address = address; +} + +/* Evaluate DWARF expression at DATA ... DATA + SIZE with its result readable + by dwarf_expr_fetch (RETVAL, 0). FRAME parameter can be NULL to call + get_selected_frame to find it. Returned dwarf_expr_context freeing is + pushed on the cleanup chain. */ + +static struct dwarf_expr_context * +dwarf_expr_prep_ctx (struct frame_info *frame, gdb_byte *data, + unsigned short size, struct dwarf2_per_cu_data *per_cu) +{ + struct dwarf_expr_context *ctx; + struct dwarf_expr_baton baton; + + if (!frame) + frame = get_selected_frame (NULL); + + baton.frame = frame; + baton.objfile = dwarf2_per_cu_objfile (per_cu); + baton.object_address = object_address; + + ctx = new_dwarf_expr_context (); + ctx->gdbarch = get_objfile_arch (baton.objfile); + ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); + ctx->baton = &baton; + ctx->read_reg = dwarf_expr_read_reg; + ctx->read_mem = dwarf_expr_read_mem; + ctx->get_frame_base = dwarf_expr_frame_base; + ctx->get_tls_address = dwarf_expr_tls_address; + ctx->get_object_address = dwarf_expr_object_address; + + make_cleanup ((make_cleanup_ftype *) free_dwarf_expr_context, ctx); + + dwarf_expr_eval (ctx, data, size); + + /* It was used only during dwarf_expr_eval. */ + ctx->baton = NULL; + + return ctx; +} + +/* Evaluate DWARF expression at DLBATON expecting it produces exactly one + CORE_ADDR result on the DWARF stack stack. */ + +CORE_ADDR +dwarf_locexpr_baton_eval (struct dwarf2_locexpr_baton *dlbaton) +{ + struct dwarf_expr_context *ctx; + CORE_ADDR retval; + struct cleanup *back_to = make_cleanup (null_cleanup, 0); + + ctx = dwarf_expr_prep_ctx (NULL, dlbaton->data, dlbaton->size, + dlbaton->per_cu); + if (ctx->num_pieces > 0) + error (_("DW_OP_*piece is unsupported for DW_FORM_block")); + else if (ctx->in_reg) + error (_("Register result is unsupported for DW_FORM_block")); + + retval = dwarf_expr_fetch (ctx, 0); + + do_cleanups (back_to); + + return retval; +} + /* Evaluate a location description, starting at DATA and with length SIZE, to find the current location of variable VAR in the context of FRAME. */ @@ -200,8 +326,8 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, struct dwarf2_per_cu_data *per_cu) { struct value *retval; - struct dwarf_expr_baton baton; struct dwarf_expr_context *ctx; + struct cleanup *back_to = make_cleanup (null_cleanup, 0); if (size == 0) { @@ -211,19 +337,8 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, return retval; } - baton.frame = frame; - baton.objfile = dwarf2_per_cu_objfile (per_cu); + ctx = dwarf_expr_prep_ctx (frame, data, size, per_cu); - ctx = new_dwarf_expr_context (); - ctx->gdbarch = get_objfile_arch (baton.objfile); - ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); - ctx->baton = &baton; - ctx->read_reg = dwarf_expr_read_reg; - ctx->read_mem = dwarf_expr_read_mem; - ctx->get_frame_base = dwarf_expr_frame_base; - ctx->get_tls_address = dwarf_expr_tls_address; - - dwarf_expr_eval (ctx, data, size); if (ctx->num_pieces > 0) { int i; @@ -261,15 +376,19 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, { CORE_ADDR address = dwarf_expr_fetch (ctx, 0); + /* object_address_set called here is required in ALLOCATE_VALUE's + CHECK_TYPEDEF for the object's possible DW_OP_push_object_address. */ + object_address_set (address); + retval = allocate_value (SYMBOL_TYPE (var)); VALUE_LVAL (retval) = lval_memory; set_value_lazy (retval, 1); - VALUE_ADDRESS (retval) = address; + set_value_address (retval, address); } set_value_initialized (retval, ctx->initialized); - free_dwarf_expr_context (ctx); + do_cleanups (back_to); return retval; } @@ -587,7 +706,7 @@ static int loclist_describe_location (struct symbol *symbol, struct ui_file *stream) { /* FIXME: Could print the entire list of locations. */ - fprintf_filtered (stream, "a variable with multiple locations"); + fprintf_filtered (stream, _("a variable with multiple locations")); return 1; } @@ -603,16 +722,56 @@ loclist_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax, data = find_location_expression (dlbaton, &size, ax->scope); if (data == NULL) - error (_("Variable \"%s\" is not available."), SYMBOL_NATURAL_NAME (symbol)); + error (_("Variable \"%s\" is not available."), SYMBOL_PRINT_NAME (symbol)); dwarf2_tracepoint_var_ref (symbol, ax, value, data, size); } -/* The set of location functions used with the DWARF-2 expression - evaluator and location lists. */ +/* The set of location functions used with the DWARF-2 location lists. */ const struct symbol_ops dwarf2_loclist_funcs = { loclist_read_variable, loclist_read_needs_frame, loclist_describe_location, loclist_tracepoint_var_ref }; + +static struct value * +missing_read_variable (struct symbol *symbol, struct frame_info *frame) +{ + struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); + + gdb_assert (dlbaton == NULL); + error (_("Unable to resolve variable \"%s\""), SYMBOL_PRINT_NAME (symbol)); +} + +static int +missing_read_needs_frame (struct symbol *symbol) +{ + return 0; +} + +static int +missing_describe_location (struct symbol *symbol, struct ui_file *stream) +{ + fprintf_filtered (stream, _("a variable we are unable to resolve")); + return 1; +} + +static void +missing_tracepoint_var_ref (struct symbol *symbol, struct 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_ops dwarf2_missing_funcs = { + missing_read_variable, + missing_read_needs_frame, + missing_describe_location, + missing_tracepoint_var_ref +}; diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h index 76577f1..bf46761 100644 --- a/gdb/dwarf2loc.h +++ b/gdb/dwarf2loc.h @@ -71,5 +71,11 @@ struct dwarf2_loclist_baton extern const struct symbol_ops dwarf2_locexpr_funcs; extern const struct symbol_ops dwarf2_loclist_funcs; +extern const struct symbol_ops dwarf2_missing_funcs; + +extern void object_address_set (CORE_ADDR address); + +extern CORE_ADDR dwarf_locexpr_baton_eval + (struct dwarf2_locexpr_baton *dlbaton); #endif /* dwarf2loc.h */ diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 55868da..de93d08 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -1,8 +1,7 @@ /* DWARF 2 debugging format support for GDB. Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009 - Free Software Foundation, Inc. + 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology, Inc. with support from Florida State University (under contract @@ -47,6 +46,9 @@ #include "command.h" #include "gdbcmd.h" #include "addrmap.h" +#include "f-lang.h" +#include "c-lang.h" +#include "typeprint.h" #include #include "gdb_string.h" @@ -103,7 +105,7 @@ typedef struct pubnames_header _PUBNAMES_HEADER; #define _ACTUAL_PUBNAMES_HEADER_SIZE 13 -/* .debug_pubnames header +/* .debug_aranges header Because of alignment constraints, this structure has padding and cannot be mapped directly onto the beginning of the .debug_info section. */ typedef struct aranges_header @@ -299,9 +301,6 @@ struct dwarf2_cu /* Hash table holding all the loaded partial DIEs. */ htab_t partial_dies; - /* `.debug_ranges' offset for this `DW_TAG_compile_unit' DIE. */ - unsigned int ranges_offset; - /* Storage for things with the same lifetime as this read-in compilation unit, including partial DIEs. */ struct obstack comp_unit_obstack; @@ -349,9 +348,6 @@ struct dwarf2_cu DIEs for namespaces, we don't need to try to infer them from mangled names. */ unsigned int has_namespace_info : 1; - - /* Field `ranges_offset' is filled in; flag as the value may be zero. */ - unsigned int has_ranges_offset : 1; }; /* Persistent data held for a compilation unit, even when not @@ -451,17 +447,12 @@ struct partial_die_info /* DWARF-2 tag for this DIE. */ ENUM_BITFIELD(dwarf_tag) tag : 16; - /* Language code associated with this DIE. This is only used - for the compilation unit DIE. */ - unsigned int language : 8; - /* Assorted flags describing the data found in this DIE. */ unsigned int has_children : 1; unsigned int is_external : 1; unsigned int is_declaration : 1; unsigned int has_type : 1; unsigned int has_specification : 1; - unsigned int has_stmt_list : 1; unsigned int has_pc_info : 1; /* Flag set if the SCOPE field of this structure has been @@ -472,10 +463,12 @@ struct partial_die_info unsigned int has_byte_size : 1; /* The name of this DIE. Normally the value of DW_AT_name, but - sometimes DW_TAG_MIPS_linkage_name or a string computed in some - other fashion. */ + sometimes a default name for unnamed DIEs. */ char *name; - char *dirname; + + /* The linkage name of this DIE, from DW_AT_MIPS_linkage_name, or + NULL if no linkage name was present. */ + char *linkage_name; /* The scope to prepend to our children. This is generally allocated on the comp_unit_obstack, so will disappear @@ -498,9 +491,6 @@ struct partial_die_info DW_AT_extension). */ unsigned int spec_offset; - /* If HAS_STMT_LIST, the offset of the Line Number Information data. */ - unsigned int line_offset; - /* Pointers to this DIE's parent, first child, and next sibling, if any. */ struct partial_die_info *die_parent, *die_child, *die_sibling; @@ -523,6 +513,15 @@ struct attr_abbrev ENUM_BITFIELD(dwarf_form) form : 16; }; +/* Additional GDB-specific attribute forms. */ +enum + { + /* A string which has been updated to GDB's internal + representation (e.g. converted to canonical form) and does not + need to be updated again. */ + GDB_FORM_cached_string = 0xff + }; + /* Attributes have a name and a value */ struct attribute { @@ -756,7 +755,7 @@ static void dwarf2_create_include_psymtab (char *, struct partial_symtab *, struct objfile *); static void dwarf2_build_include_psymtabs (struct dwarf2_cu *, - struct partial_die_info *, + struct die_info *, struct partial_symtab *); static void dwarf2_build_psymtabs_hard (struct objfile *, int); @@ -768,6 +767,9 @@ static void scan_partial_symbols (struct partial_die_info *, static void add_partial_symbol (struct partial_die_info *, struct dwarf2_cu *); +static gdb_byte *read_comp_unit_head (struct comp_unit_head *, gdb_byte *, + bfd *); + static int pdi_needs_namespace (enum dwarf_tag tag); static void add_partial_namespace (struct partial_die_info *pdi, @@ -794,6 +796,10 @@ static void dwarf2_psymtab_to_symtab (struct partial_symtab *); static void psymtab_to_symtab_1 (struct partial_symtab *); +static gdb_byte *dwarf2_read_section_1 (struct objfile *objfile, + struct obstack *obstack, + asection *sectp); + gdb_byte *dwarf2_read_section (struct objfile *, asection *); static void dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu); @@ -929,7 +935,8 @@ static int dwarf2_ranges_read (unsigned, CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *, struct partial_symtab *); static int dwarf2_get_pc_bounds (struct die_info *, - CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *); + CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *, + struct partial_symtab *pst); static void get_scope_pc_bounds (struct die_info *, CORE_ADDR *, CORE_ADDR *, @@ -962,6 +969,8 @@ static void read_namespace (struct die_info *die, struct dwarf2_cu *); static void read_module (struct die_info *die, struct dwarf2_cu *cu); +static void read_import_statement (struct die_info *die, struct dwarf2_cu *); + static const char *namespace_name (struct die_info *die, int *is_anonymous, struct dwarf2_cu *); @@ -993,6 +1002,9 @@ static void process_die (struct die_info *, struct dwarf2_cu *); static char *dwarf2_linkage_name (struct die_info *, struct dwarf2_cu *); +static char *dwarf2_canonicalize_name (char *, struct dwarf2_cu *, + struct obstack *); + static char *dwarf2_name (struct die_info *die, struct dwarf2_cu *); static struct die_info *dwarf2_extension (struct die_info *die, @@ -1030,7 +1042,14 @@ static void store_in_ref_table (struct die_info *, static unsigned int dwarf2_get_ref_die_offset (struct attribute *); -static int dwarf2_get_attr_constant_value (struct attribute *, int); +enum dwarf2_get_attr_constant_value + { + dwarf2_attr_unknown, + dwarf2_attr_const, + dwarf2_attr_block + }; +static enum dwarf2_get_attr_constant_value dwarf2_get_attr_constant_value + (struct attribute *attr, int *val_return); static struct die_info *follow_die_ref (struct die_info *, struct attribute *, @@ -1085,6 +1104,9 @@ static void age_cached_comp_units (void); static void free_one_cached_comp_unit (void *); +static void fetch_die_type_attrs (struct die_info *die, struct type *type, + struct dwarf2_cu *cu); + static struct type *set_die_type (struct die_info *, struct type *, struct dwarf2_cu *); @@ -1104,19 +1126,28 @@ static void dwarf2_clear_marks (struct dwarf2_per_cu_data *); static struct type *get_die_type (struct die_info *die, struct dwarf2_cu *cu); +static struct dwarf2_locexpr_baton *dwarf2_attr_to_locexpr_baton + (struct attribute *attr, struct dwarf2_cu *cu); + /* Try to locate the sections we need for DWARF 2 debugging information and return true if we have enough to do something. */ int dwarf2_has_info (struct objfile *objfile) { - struct dwarf2_per_objfile *data; + int update_sizes = 0; /* Initialize per-objfile state. */ - data = obstack_alloc (&objfile->objfile_obstack, sizeof (*data)); - memset (data, 0, sizeof (*data)); - set_objfile_data (objfile, dwarf2_objfile_data_key, data); - dwarf2_per_objfile = data; + dwarf2_per_objfile = objfile_data (objfile, dwarf2_objfile_data_key); + if (!dwarf2_per_objfile) + { + struct dwarf2_per_objfile *data + = obstack_alloc (&objfile->objfile_obstack, sizeof (*data)); + memset (data, 0, sizeof (*data)); + set_objfile_data (objfile, dwarf2_objfile_data_key, data); + dwarf2_per_objfile = data; + update_sizes = 1; + } dwarf_info_section = 0; dwarf_abbrev_section = 0; @@ -1127,8 +1158,9 @@ dwarf2_has_info (struct objfile *objfile) dwarf_eh_frame_section = 0; dwarf_ranges_section = 0; dwarf_loc_section = 0; + dwarf_aranges_section = 0; - bfd_map_over_sections (objfile->obfd, dwarf2_locate_sections, NULL); + bfd_map_over_sections (objfile->obfd, dwarf2_locate_sections, &update_sizes); return (dwarf_info_section != NULL && dwarf_abbrev_section != NULL); } @@ -1149,51 +1181,61 @@ section_is_p (asection *sectp, const char *name) in. */ static void -dwarf2_locate_sections (bfd *abfd, asection *sectp, void *ignore_ptr) +dwarf2_locate_sections (bfd *abfd, asection *sectp, void *user_data) { + int update_sizes = * (int *) user_data; if (section_is_p (sectp, INFO_SECTION)) { - dwarf2_per_objfile->info_size = bfd_get_section_size (sectp); + if (update_sizes) + dwarf2_per_objfile->info_size = bfd_get_section_size (sectp); dwarf_info_section = sectp; } else if (section_is_p (sectp, ABBREV_SECTION)) { - dwarf2_per_objfile->abbrev_size = bfd_get_section_size (sectp); + if (update_sizes) + dwarf2_per_objfile->abbrev_size = bfd_get_section_size (sectp); dwarf_abbrev_section = sectp; } else if (section_is_p (sectp, LINE_SECTION)) { - dwarf2_per_objfile->line_size = bfd_get_section_size (sectp); + if (update_sizes) + dwarf2_per_objfile->line_size = bfd_get_section_size (sectp); dwarf_line_section = sectp; } else if (section_is_p (sectp, PUBNAMES_SECTION)) { - dwarf2_per_objfile->pubnames_size = bfd_get_section_size (sectp); + if (update_sizes) + dwarf2_per_objfile->pubnames_size = bfd_get_section_size (sectp); dwarf_pubnames_section = sectp; } else if (section_is_p (sectp, ARANGES_SECTION)) { - dwarf2_per_objfile->aranges_size = bfd_get_section_size (sectp); + if (update_sizes) + dwarf2_per_objfile->aranges_size = bfd_get_section_size (sectp); dwarf_aranges_section = sectp; } else if (section_is_p (sectp, LOC_SECTION)) { - dwarf2_per_objfile->loc_size = bfd_get_section_size (sectp); + if (update_sizes) + dwarf2_per_objfile->loc_size = bfd_get_section_size (sectp); dwarf_loc_section = sectp; } else if (section_is_p (sectp, MACINFO_SECTION)) { - dwarf2_per_objfile->macinfo_size = bfd_get_section_size (sectp); + if (update_sizes) + dwarf2_per_objfile->macinfo_size = bfd_get_section_size (sectp); dwarf_macinfo_section = sectp; } else if (section_is_p (sectp, STR_SECTION)) { - dwarf2_per_objfile->str_size = bfd_get_section_size (sectp); + if (update_sizes) + dwarf2_per_objfile->str_size = bfd_get_section_size (sectp); dwarf_str_section = sectp; } else if (section_is_p (sectp, FRAME_SECTION)) { - dwarf2_per_objfile->frame_size = bfd_get_section_size (sectp); + if (update_sizes) + dwarf2_per_objfile->frame_size = bfd_get_section_size (sectp); dwarf_frame_section = sectp; } else if (section_is_p (sectp, EH_FRAME_SECTION)) @@ -1201,13 +1243,15 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *ignore_ptr) flagword aflag = bfd_get_section_flags (ignore_abfd, sectp); if (aflag & SEC_HAS_CONTENTS) { - dwarf2_per_objfile->eh_frame_size = bfd_get_section_size (sectp); + if (update_sizes) + dwarf2_per_objfile->eh_frame_size = bfd_get_section_size (sectp); dwarf_eh_frame_section = sectp; } } else if (section_is_p (sectp, RANGES_SECTION)) { - dwarf2_per_objfile->ranges_size = bfd_get_section_size (sectp); + if (update_sizes) + dwarf2_per_objfile->ranges_size = bfd_get_section_size (sectp); dwarf_ranges_section = sectp; } @@ -1250,6 +1294,86 @@ dwarf2_resize_section (asection *sectp, bfd_size_type new_size) sectp->name); } +/* A cleanup that frees an obstack. */ +static void +finalize_obstack (void *o) +{ + struct obstack *ob = o; + obstack_free (o, 0); +} + +/* Read the .debug_aranges section and construct an address map. */ + +void +dwarf2_create_quick_addrmap (struct objfile *objfile) +{ + char *aranges_buffer, *aranges_ptr; + bfd *abfd = objfile->obfd; + CORE_ADDR baseaddr; + struct cleanup *old; + struct obstack temp_obstack; + struct addrmap *mutable_map; + + if (!dwarf_aranges_section) + return; + + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + + aranges_buffer = dwarf2_read_section_1 (objfile, NULL, dwarf_aranges_section); + aranges_ptr = aranges_buffer; + old = make_cleanup (xfree, aranges_buffer); + + obstack_init (&temp_obstack); + make_cleanup (finalize_obstack, &temp_obstack); + mutable_map = addrmap_create_mutable (&temp_obstack); + + while ((aranges_ptr - aranges_buffer) < dwarf2_per_objfile->aranges_size) + { + struct comp_unit_head cu_header; + unsigned int bytes_read, segment_size, delta; + LONGEST info_offset; + struct dwarf2_cu cu; + + cu_header.initial_length_size = 0; + aranges_ptr = read_comp_unit_head (&cu_header, aranges_ptr, abfd); + + segment_size = read_1_byte (abfd, aranges_ptr); + aranges_ptr += 1; + + /* Align the pointer to twice the pointer size. I didn't see + this in the spec but it appears to be required. */ + delta = (aranges_ptr - aranges_buffer) % (2 * cu_header.addr_size); + delta = (2 * cu_header.addr_size - delta) % (2 * cu_header.addr_size); + aranges_ptr += delta; + + memset (&cu, 0, sizeof (cu)); + cu.header.addr_size = cu_header.addr_size; + + while (1) + { + CORE_ADDR address, length; + + address = read_address (abfd, aranges_ptr, &cu, &bytes_read); + aranges_ptr += bytes_read; + + length = read_address (abfd, aranges_ptr, &cu, &bytes_read); + aranges_ptr += bytes_read; + + if (address == 0 && length == 0) + break; + + address += baseaddr; + + addrmap_set_empty (mutable_map, address, address + length, objfile); + } + } + + objfile->quick_addrmap = addrmap_create_fixed (mutable_map, + &objfile->objfile_obstack); + do_cleanups (old); +} + + /* Build a partial symbol table. */ void @@ -1453,22 +1577,24 @@ dwarf2_create_include_psymtab (char *name, struct partial_symtab *pst, /* Read the Line Number Program data and extract the list of files included by the source file represented by PST. Build an include - partial symtab for each of these included files. - - This procedure assumes that there *is* a Line Number Program in - the given CU. Callers should check that PDI->HAS_STMT_LIST is set - before calling this procedure. */ + partial symtab for each of these included files. */ static void dwarf2_build_include_psymtabs (struct dwarf2_cu *cu, - struct partial_die_info *pdi, + struct die_info *die, struct partial_symtab *pst) { struct objfile *objfile = cu->objfile; bfd *abfd = objfile->obfd; - struct line_header *lh; + struct line_header *lh = NULL; + struct attribute *attr; - lh = dwarf_decode_line_header (pdi->line_offset, abfd, cu); + attr = dwarf2_attr (die, DW_AT_stmt_list, cu); + if (attr) + { + unsigned int line_offset = DW_UNSND (attr); + lh = dwarf_decode_line_header (line_offset, abfd, cu); + } if (lh == NULL) return; /* No linetable, so no includes. */ @@ -1477,6 +1603,36 @@ dwarf2_build_include_psymtabs (struct dwarf2_cu *cu, free_line_header (lh); } +/* Find the base address of the compilation unit for range lists and + location lists. It will normally be specified by DW_AT_low_pc. + In DWARF-3 draft 4, the base address could be overridden by + DW_AT_entry_pc. It's been removed, but GCC still uses this for + compilation units with discontinuous ranges. */ + +static void +dwarf2_find_base_address (struct die_info *die, struct dwarf2_cu *cu) +{ + struct attribute *attr; + + cu->base_known = 0; + cu->base_address = 0; + + attr = dwarf2_attr (die, DW_AT_entry_pc, cu); + if (attr) + { + cu->base_address = DW_ADDR (attr); + cu->base_known = 1; + } + else + { + attr = dwarf2_attr (die, DW_AT_low_pc, cu); + if (attr) + { + cu->base_address = DW_ADDR (attr); + cu->base_known = 1; + } + } +} /* Build the partial symbol table by doing a quick pass through the .debug_info and .debug_abbrev sections. */ @@ -1489,7 +1645,7 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) bfd *abfd = objfile->obfd; gdb_byte *info_ptr; gdb_byte *beg_of_comp_unit; - struct partial_die_info comp_unit_die; + struct die_info *comp_unit_die; struct partial_symtab *pst; struct cleanup *back_to; CORE_ADDR baseaddr; @@ -1523,9 +1679,12 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) { struct cleanup *back_to_inner; struct dwarf2_cu cu; - struct abbrev_info *abbrev; unsigned int bytes_read; struct dwarf2_per_cu_data *this_cu; + int has_children, has_pc_info; + struct attribute *attr; + const char *name; + CORE_ADDR best_lowpc, best_highpc; beg_of_comp_unit = info_ptr; @@ -1551,11 +1710,10 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) this_cu = dwarf2_find_comp_unit (cu.header.offset, objfile); /* Read the compilation unit die */ - abbrev = peek_die_abbrev (info_ptr, &bytes_read, &cu); - info_ptr = read_partial_die (&comp_unit_die, abbrev, bytes_read, - abfd, info_ptr, &cu); + info_ptr = read_full_die (&comp_unit_die, abfd, info_ptr, &cu, + &has_children); - if (comp_unit_die.tag == DW_TAG_partial_unit) + if (comp_unit_die->tag == DW_TAG_partial_unit) { info_ptr = (beg_of_comp_unit + cu.header.length + cu.header.initial_length_size); @@ -1564,20 +1722,27 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) } /* Set the language we're debugging */ - set_cu_language (comp_unit_die.language, &cu); + attr = dwarf2_attr (comp_unit_die, DW_AT_language, &cu); + if (attr != NULL) + set_cu_language (DW_UNSND (attr), &cu); + else + set_cu_language (language_minimal, &cu); /* Allocate a new partial symbol table structure */ - pst = start_psymtab_common (objfile, objfile->section_offsets, - comp_unit_die.name ? comp_unit_die.name : "", + attr = dwarf2_attr (comp_unit_die, DW_AT_name, &cu); + if (attr != NULL) + name = DW_STRING (attr); + else + name = ""; + pst = start_psymtab_common (objfile, objfile->section_offsets, name, /* TEXTLOW and TEXTHIGH are set below. */ 0, objfile->global_psymbols.next, objfile->static_psymbols.next); - if (comp_unit_die.dirname) - pst->dirname = obsavestring (comp_unit_die.dirname, - strlen (comp_unit_die.dirname), - &objfile->objfile_obstack); + attr = dwarf2_attr (comp_unit_die, DW_AT_comp_dir, &cu); + if (attr != NULL) + pst->dirname = xstrdup (DW_STRING (attr)); pst->read_symtab_private = (char *) this_cu; @@ -1607,24 +1772,17 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) /* Possibly set the default values of LOWPC and HIGHPC from `DW_AT_ranges'. */ - if (cu.has_ranges_offset) - { - if (dwarf2_ranges_read (cu.ranges_offset, &comp_unit_die.lowpc, - &comp_unit_die.highpc, &cu, pst)) - comp_unit_die.has_pc_info = 1; - } - else if (comp_unit_die.has_pc_info - && comp_unit_die.lowpc < comp_unit_die.highpc) - /* Store the contiguous range if it is not empty; it can be empty for - CUs with no code. */ - addrmap_set_empty (objfile->psymtabs_addrmap, - comp_unit_die.lowpc + baseaddr, - comp_unit_die.highpc + baseaddr - 1, pst); + has_pc_info = 0; + + if (dwarf2_get_pc_bounds (comp_unit_die, &best_lowpc, &best_highpc, &cu, + pst)) + has_pc_info = 1; + dwarf2_find_base_address (comp_unit_die, &cu); /* Check if comp unit has_children. If so, read the rest of the partial symbols from this comp unit. If not, there's no more debug_info for this comp unit. */ - if (comp_unit_die.has_children) + if (has_children) { struct partial_die_info *first_die; CORE_ADDR lowpc, highpc; @@ -1634,8 +1792,7 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) first_die = load_partial_dies (abfd, info_ptr, 1, &cu); - scan_partial_symbols (first_die, &lowpc, &highpc, - ! comp_unit_die.has_pc_info, &cu); + scan_partial_symbols (first_die, &lowpc, &highpc, ! has_pc_info, &cu); /* If we didn't find a lowpc, set it to highpc to avoid complaints from `maint check'. */ @@ -1644,14 +1801,14 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) /* If the compilation unit didn't have an explicit address range, then use the information extracted from its child dies. */ - if (! comp_unit_die.has_pc_info) + if (! has_pc_info) { - comp_unit_die.lowpc = lowpc; - comp_unit_die.highpc = highpc; + best_lowpc = lowpc; + best_highpc = highpc; } } - pst->textlow = comp_unit_die.lowpc + baseaddr; - pst->texthigh = comp_unit_die.highpc + baseaddr; + pst->textlow = best_lowpc + baseaddr; + pst->texthigh = best_highpc + baseaddr; pst->n_global_syms = objfile->global_psymbols.next - (objfile->global_psymbols.list + pst->globals_offset); @@ -1667,12 +1824,9 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) info_ptr = beg_of_comp_unit + cu.header.length + cu.header.initial_length_size; - if (comp_unit_die.has_stmt_list) - { - /* Get the list of files included in the current compilation unit, - and build a psymtab for each of them. */ - dwarf2_build_include_psymtabs (&cu, &comp_unit_die, pst); - } + /* Get the list of files included in the current compilation unit, + and build a psymtab for each of them. */ + dwarf2_build_include_psymtabs (&cu, comp_unit_die, pst); do_cleanups (back_to_inner); } @@ -1690,11 +1844,12 @@ load_comp_unit (struct dwarf2_per_cu_data *this_cu, struct objfile *objfile) { bfd *abfd = objfile->obfd; gdb_byte *info_ptr, *beg_of_comp_unit; - struct partial_die_info comp_unit_die; + struct die_info *comp_unit_die; struct dwarf2_cu *cu; - struct abbrev_info *abbrev; unsigned int bytes_read; struct cleanup *back_to; + struct attribute *attr; + int has_children; info_ptr = dwarf2_per_objfile->info_buffer + this_cu->offset; beg_of_comp_unit = info_ptr; @@ -1716,12 +1871,15 @@ load_comp_unit (struct dwarf2_per_cu_data *this_cu, struct objfile *objfile) back_to = make_cleanup (dwarf2_free_abbrev_table, cu); /* Read the compilation unit die. */ - abbrev = peek_die_abbrev (info_ptr, &bytes_read, cu); - info_ptr = read_partial_die (&comp_unit_die, abbrev, bytes_read, - abfd, info_ptr, cu); + info_ptr = read_full_die (&comp_unit_die, abfd, info_ptr, cu, + &has_children); /* Set the language we're debugging. */ - set_cu_language (comp_unit_die.language, cu); + attr = dwarf2_attr (comp_unit_die, DW_AT_language, cu); + if (attr) + set_cu_language (DW_UNSND (attr), cu); + else + set_cu_language (language_minimal, cu); /* Link this compilation unit into the compilation unit tree. */ this_cu->cu = cu; @@ -1731,7 +1889,7 @@ load_comp_unit (struct dwarf2_per_cu_data *this_cu, struct objfile *objfile) /* Check if comp unit has_children. If so, read the rest of the partial symbols from this comp unit. If not, there's no more debug_info for this comp unit. */ - if (comp_unit_die.has_children) + if (has_children) load_partial_dies (abfd, info_ptr, 0, cu); do_cleanups (back_to); @@ -1948,7 +2106,7 @@ partial_die_parent_scope (struct partial_die_info *pdi, ignoring them. */ complaint (&symfile_complaints, _("unhandled containing DIE tag %d for DIE at %d"), - parent->tag, pdi->offset); + parent->tag, real_pdi->offset); parent->scope = grandparent_scope; } @@ -1963,12 +2121,37 @@ partial_die_full_name (struct partial_die_info *pdi, struct dwarf2_cu *cu) { char *parent_scope; + struct partial_die_info *real_pdi; - parent_scope = partial_die_parent_scope (pdi, cu); - if (parent_scope == NULL) - return NULL; - else + /* We need to look at our parent DIE; if we have a DW_AT_specification, + then this means the parent of the specification DIE. + partial_die_parent_scope does this loop also, but we do it here + since we need to examine real_pdi->parent ourselves. */ + + real_pdi = pdi; + while (real_pdi->has_specification) + real_pdi = find_partial_die (real_pdi->spec_offset, cu); + + parent_scope = partial_die_parent_scope (real_pdi, cu); + if (parent_scope != NULL) return typename_concat (NULL, parent_scope, pdi->name, cu); + + if (!cu->has_namespace_info && pdi->linkage_name + && !real_pdi->die_parent) + { + char *actual_scope + = language_class_name_from_physname (cu->language_defn, + pdi->linkage_name); + if (actual_scope != NULL) + { + char *actual_name = typename_concat (NULL, actual_scope, + pdi->name, cu); + xfree (actual_scope); + return actual_name; + } + } + + return NULL; } static void @@ -1984,7 +2167,9 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - if (pdi_needs_namespace (pdi->tag)) + if (pdi->linkage_name != NULL) + actual_name = pdi->linkage_name; + else if (pdi_needs_namespace (pdi->tag)) { actual_name = partial_die_full_name (pdi, cu); if (actual_name) @@ -2133,9 +2318,8 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) if (cu->language == language_cplus && cu->has_namespace_info == 0 && psym != NULL - && SYMBOL_CPLUS_DEMANGLED_NAME (psym) != NULL) - cp_check_possible_namespace_symbols (SYMBOL_CPLUS_DEMANGLED_NAME (psym), - objfile); + && pdi->linkage_name != NULL) + cp_check_possible_namespace_symbols (actual_name, objfile); if (built_actual_name) xfree (actual_name); @@ -2158,6 +2342,14 @@ pdi_needs_namespace (enum dwarf_tag tag) case DW_TAG_union_type: case DW_TAG_enumeration_type: case DW_TAG_enumerator: + case DW_TAG_subprogram: + case DW_TAG_variable: + return 1; + case DW_TAG_member: + /* The only time we will encounter member variables in this + function is when we are creating a "linkage" name for them; + therefore they must be static members, so they do need a + class prefix. */ return 1; default: return 0; @@ -2290,11 +2482,11 @@ guess_structure_name (struct partial_die_info *struct_pdi, while (child_pdi != NULL) { - if (child_pdi->tag == DW_TAG_subprogram) + if (child_pdi->tag == DW_TAG_subprogram && child_pdi->linkage_name) { char *actual_class_name = language_class_name_from_physname (cu->language_defn, - child_pdi->name); + child_pdi->linkage_name); if (actual_class_name != NULL) { struct_pdi->name @@ -2741,7 +2933,6 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) CORE_ADDR lowpc, highpc; struct symtab *symtab; struct cleanup *back_to; - struct attribute *attr; CORE_ADDR baseaddr; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); @@ -2751,30 +2942,7 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) cu->list_in_scope = &file_symbols; - /* Find the base address of the compilation unit for range lists and - location lists. It will normally be specified by DW_AT_low_pc. - In DWARF-3 draft 4, the base address could be overridden by - DW_AT_entry_pc. It's been removed, but GCC still uses this for - compilation units with discontinuous ranges. */ - - cu->base_known = 0; - cu->base_address = 0; - - attr = dwarf2_attr (cu->dies, DW_AT_entry_pc, cu); - if (attr) - { - cu->base_address = DW_ADDR (attr); - cu->base_known = 1; - } - else - { - attr = dwarf2_attr (cu->dies, DW_AT_low_pc, cu); - if (attr) - { - cu->base_address = DW_ADDR (attr); - cu->base_known = 1; - } - } + dwarf2_find_base_address (cu->dies, cu); /* Do line number decoding in read_file_scope () */ process_die (cu->dies, cu); @@ -2805,6 +2973,7 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) static void process_die (struct die_info *die, struct dwarf2_cu *cu) { + switch (die->tag) { case DW_TAG_padding: @@ -2849,6 +3018,7 @@ process_die (struct die_info *die, struct dwarf2_cu *cu) case DW_TAG_base_type: case DW_TAG_subrange_type: + case DW_TAG_typedef: /* Add a typedef symbol for the type definition, if it has a DW_AT_name. */ new_symbol (die, read_type_die (die, cu), cu); @@ -2867,14 +3037,12 @@ process_die (struct die_info *die, struct dwarf2_cu *cu) break; case DW_TAG_imported_declaration: case DW_TAG_imported_module: - /* FIXME: carlton/2002-10-16: Eventually, we should use the - information contained in these. DW_TAG_imported_declaration - dies shouldn't have children; DW_TAG_imported_module dies - shouldn't in the C++ case, but conceivably could in the - Fortran case. */ processing_has_namespace_info = 1; - complaint (&symfile_complaints, _("unsupported tag: '%s'"), - dwarf_tag_name (die->tag)); + if (die->child != NULL && (die->tag == DW_TAG_imported_declaration + || cu->language != language_fortran)) + complaint (&symfile_complaints, _("Tag '%s' has unexpected children"), + dwarf_tag_name (die->tag)); + read_import_statement (die, cu); break; default: new_symbol (die, NULL, cu); @@ -2904,22 +3072,130 @@ dwarf2_full_name (struct die_info *die, struct dwarf2_cu *cu) return name; /* If no prefix is necessary for this type of DIE, return the - unqualified name. The other three tags listed could be handled - in pdi_needs_namespace, but that requires broader changes. */ - if (!pdi_needs_namespace (die->tag) - && die->tag != DW_TAG_subprogram - && die->tag != DW_TAG_variable - && die->tag != DW_TAG_member) + unqualified name. */ + if (!pdi_needs_namespace (die->tag)) return name; prefix = determine_prefix (die, cu); if (*prefix != '\0') - name = typename_concat (&cu->objfile->objfile_obstack, prefix, - name, cu); + { + char *prefixed_name = typename_concat (NULL, prefix, name, cu); + buf = mem_fileopen (); + fputs_unfiltered (prefixed_name, buf); + xfree (prefixed_name); + } + + if (cu->language == language_cplus && die->tag == DW_TAG_subprogram) + { + struct type *type = read_type_die (die, cu); + + if (buf == NULL) + { + buf = mem_fileopen (); + fputs_unfiltered (name, buf); + } + + c_type_print_args (type, buf, 0); + } + + if (buf != NULL) + { + long length; + name = ui_file_obsavestring (buf, &cu->objfile->objfile_obstack, + &length); + ui_file_delete (buf); + } return name; } +/* read the given die's decl_line number. Return -1 if in case of an error */ +static int dwarf2_read_decl_line (struct die_info *die, struct dwarf2_cu *cu){ + struct attribute *line_attr; + + line_attr = dwarf2_attr (die, DW_AT_decl_line, cu); + if (line_attr){ + return DW_UNSND (line_attr); + } + + return -1; +} + +/* Read the import statement specified by the given die and record it. */ + +static void +read_import_statement (struct die_info *die, struct dwarf2_cu *cu) +{ + struct attribute *import_attr; + struct die_info *imported_die; + const char *imported_name; + const char *imported_name_prefix; + char *canonical_name; + const char *import_alias; + const char *imported_declaration = ""; + const char *import_prefix; + + int line_number = -1; + + int is_anonymous = 0; + + import_attr = dwarf2_attr (die, DW_AT_import, cu); + if (import_attr == NULL) + { + complaint (&symfile_complaints, _("Tag '%s' has no DW_AT_import"), + dwarf_tag_name (die->tag)); + return; + } + + imported_die = follow_die_ref (die, import_attr, &cu); + imported_name = namespace_name (imported_die, &is_anonymous, cu); + if (imported_name == NULL) + { + /* C++ imports from std:: DW_TAG_base_type with no DW_AT_name - why? */ + return; + } + + /* Figure out the local name after import. */ + import_alias = dwarf2_name(die, cu); + if(import_alias == NULL){ + import_alias = ""; + } + + /* Determine the line number at which the import was made */ + line_number = dwarf2_read_decl_line(die, cu); + + /* Figure out where the statement is being imported to */ + import_prefix = determine_prefix (die, cu); + + /* + Figure out what the scope of the imported die is and prepend it + to the name of the imported die + */ + imported_name_prefix = determine_prefix (imported_die, cu); + + if(imported_die->tag != DW_TAG_namespace){ + imported_declaration = imported_name; + canonical_name = (char*)imported_name_prefix; + }else{ + if(strlen (imported_name_prefix) > 0){ + canonical_name = alloca (strlen (imported_name_prefix) + 2 + strlen (imported_name) + 1); + strcpy (canonical_name, imported_name_prefix); + strcat (canonical_name, "::"); + strcat (canonical_name, imported_name); + }else{ + canonical_name = alloca (strlen (imported_name) + 1); + strcpy (canonical_name, imported_name); + } + } + + using_directives = cp_add_using (import_prefix, + canonical_name, + import_alias, + imported_declaration, + line_number, + using_directives); +} + static void initialize_cu_func_list (struct dwarf2_cu *cu) { @@ -3076,6 +3352,103 @@ add_to_cu_func_list (const char *name, CORE_ADDR lowpc, CORE_ADDR highpc, cu->last_fn = thisfn; } +static int +unsigned_int_compar (const void *ap, const void *bp) +{ + unsigned int a = *(unsigned int *) ap; + unsigned int b = *(unsigned int *) bp; + + return (a > b) - (b > a); +} + +static void explore_abstract_origin(struct die_info *die, struct dwarf2_cu *cu, unsigned* die_children_p){ + struct attribute *attr; + unsigned die_children = *die_children_p; + struct die_info *child_die; + + attr = dwarf2_attr (die, DW_AT_abstract_origin, cu); + + /* GCC currently uses DW_AT_specification to indicate die inheritence + in the case of import statements. The following is to accommodate that */ + if(!attr){ + attr = dwarf2_attr (die, DW_AT_specification, cu); + } + + if (attr) + { + /* For the list of CHILD_DIEs. */ + unsigned *offsets; + unsigned *offsets_end, *offsetp; + struct die_info *origin_die, *origin_child_die; + struct cleanup *cleanups; + + origin_die = follow_die_ref (die, attr, &cu); + if (die->tag != origin_die->tag) + complaint (&symfile_complaints, + _("DIE 0x%x and its abstract origin 0x%x have different " + "tags"), + die->offset, origin_die->offset); + + offsets = xmalloc (sizeof (*offsets) * die_children); + cleanups = make_cleanup (xfree, offsets); + + offsets_end = offsets; + child_die = die->child; + while (child_die && child_die->tag) + { + attr = dwarf2_attr (child_die, DW_AT_abstract_origin, cu); + if (!attr) + complaint (&symfile_complaints, + _("Child DIE 0x%x of DIE 0x%x has missing " + "DW_AT_abstract_origin"), + child_die->offset, die->offset); + else + { + struct die_info *child_origin_die; + + child_origin_die = follow_die_ref (child_die, attr, &cu); + if (child_die->tag != child_origin_die->tag) + complaint (&symfile_complaints, + _("Child DIE 0x%x and its abstract origin 0x%x have " + "different tags"), + child_die->offset, child_origin_die->offset); + *offsets_end++ = child_origin_die->offset; + } + child_die = sibling_die (child_die); + } + qsort (offsets, offsets_end - offsets, sizeof (*offsets), + unsigned_int_compar); + /* Disabled as excessively expensive - check if we may ever complain. */ + if (0) + { + for (offsetp = offsets + 1; offsetp < offsets_end; offsetp++) + if (offsetp[-1] == *offsetp) + complaint (&symfile_complaints, + _("Child DIEs of DIE 0x%x duplicitly abstract-origin " + "referenced DIE 0x%x"), + die->offset, *offsetp); + } + + offsetp = offsets; + origin_child_die = origin_die->child; + while (origin_child_die && origin_child_die->tag) + { + /* Is origin_child_die referenced by any of the DIE children? */ + while (offsetp < offsets_end && *offsetp < origin_child_die->offset) + offsetp++; + if (offsetp >= offsets_end || *offsetp > origin_child_die->offset) + { + /* Found that origin_child_die is really not referenced. */ + process_die (origin_child_die, cu); + } + origin_child_die = sibling_die (origin_child_die); + } + + do_cleanups (cleanups); + } + +} + static void read_func_scope (struct die_info *die, struct dwarf2_cu *cu) { @@ -3088,16 +3461,27 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) char *name; CORE_ADDR baseaddr; struct block *block; + unsigned die_children = 0; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - name = dwarf2_linkage_name (die, cu); + name = dwarf2_name (die, cu); /* Ignore functions with missing or empty names and functions with missing or invalid low and high pc attributes. */ - if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu)) + if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL)){ + /* explore abstract origins if present. They might contain useful information + such as import statements. */ + child_die = die->child; + while (child_die && child_die->tag) + { + child_die = sibling_die (child_die); + die_children++; + } + explore_abstract_origin(die, cu, &die_children); return; - + } + lowpc += baseaddr; highpc += baseaddr; @@ -3124,16 +3508,91 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) cu->list_in_scope = &local_symbols; - if (die->child != NULL) + child_die = die->child; + die_children = 0; + while (child_die && child_die->tag) { + process_die (child_die, cu); + child_die = sibling_die (child_die); + die_children++; + } + + attr = dwarf2_attr (die, DW_AT_abstract_origin, cu); + if (attr) + { + /* For the list of CHILD_DIEs. */ + unsigned *offsets; + unsigned *offsets_end, *offsetp; + struct die_info *origin_die, *origin_child_die; + struct cleanup *cleanups; + + origin_die = follow_die_ref (die, attr, &cu); + if (die->tag != origin_die->tag) + complaint (&symfile_complaints, + _("DIE 0x%x and its abstract origin 0x%x have different " + "tags"), + die->offset, origin_die->offset); + + offsets = xmalloc (sizeof (*offsets) * die_children); + cleanups = make_cleanup (xfree, offsets); + + offsets_end = offsets; child_die = die->child; while (child_die && child_die->tag) { - process_die (child_die, cu); + attr = dwarf2_attr (child_die, DW_AT_abstract_origin, cu); + if (!attr) + complaint (&symfile_complaints, + _("Child DIE 0x%x of DIE 0x%x has missing " + "DW_AT_abstract_origin"), + child_die->offset, die->offset); + else + { + struct die_info *child_origin_die; + + child_origin_die = follow_die_ref (child_die, attr, &cu); + if (child_die->tag != child_origin_die->tag) + complaint (&symfile_complaints, + _("Child DIE 0x%x and its abstract origin 0x%x have " + "different tags"), + child_die->offset, child_origin_die->offset); + *offsets_end++ = child_origin_die->offset; + } child_die = sibling_die (child_die); } + qsort (offsets, offsets_end - offsets, sizeof (*offsets), + unsigned_int_compar); + /* Disabled as excessively expensive - check if we may ever complain. */ + if (0) + { + for (offsetp = offsets + 1; offsetp < offsets_end; offsetp++) + if (offsetp[-1] == *offsetp) + complaint (&symfile_complaints, + _("Child DIEs of DIE 0x%x duplicitly abstract-origin " + "referenced DIE 0x%x"), + die->offset, *offsetp); + } + + offsetp = offsets; + origin_child_die = origin_die->child; + while (origin_child_die && origin_child_die->tag) + { + /* Is origin_child_die referenced by any of the DIE children? */ + while (offsetp < offsets_end && *offsetp < origin_child_die->offset) + offsetp++; + if (offsetp >= offsets_end || *offsetp > origin_child_die->offset) + { + /* Found that origin_child_die is really not referenced. */ + process_die (origin_child_die, cu); + } + origin_child_die = sibling_die (origin_child_die); + } + + do_cleanups (cleanups); } + explore_abstract_origin(die, cu, &die_children); + new = pop_context (); /* Make a block for the local symbols within. */ block = finish_block (new->name, &local_symbols, new->old_blocks, @@ -3154,6 +3613,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) back to building a containing block's symbol lists. */ local_symbols = new->locals; param_symbols = new->params; + using_directives = new->using_directives; /* If we've finished processing a top-level function, subsequent symbols go in the file symbol list. */ @@ -3180,7 +3640,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu) as multiple lexical blocks? Handling children in a sane way would be nasty. Might be easier to properly extend generic blocks to describe ranges. */ - if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu)) + if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL)) return; lowpc += baseaddr; highpc += baseaddr; @@ -3216,6 +3676,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu) dwarf2_record_block_ranges (die, block, baseaddr, cu); } local_symbols = new->locals; + using_directives = new->using_directives; } /* Get low and high pc attributes from DW_AT_ranges attribute value OFFSET. @@ -3351,7 +3812,8 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return, discontinuous, i.e. derived from DW_AT_ranges information. */ static int dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, - CORE_ADDR *highpc, struct dwarf2_cu *cu) + CORE_ADDR *highpc, struct dwarf2_cu *cu, + struct partial_symtab *pst) { struct attribute *attr; CORE_ADDR low = 0; @@ -3379,7 +3841,7 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, { /* Value of the DW_AT_ranges attribute is the offset in the .debug_ranges section. */ - if (!dwarf2_ranges_read (DW_UNSND (attr), &low, &high, cu, NULL)) + if (!dwarf2_ranges_read (DW_UNSND (attr), &low, &high, cu, pst)) return 0; /* Found discontinuous range of addresses. */ ret = -1; @@ -3418,7 +3880,7 @@ dwarf2_get_subprogram_pc_bounds (struct die_info *die, CORE_ADDR low, high; struct die_info *child = die->child; - if (dwarf2_get_pc_bounds (die, &low, &high, cu)) + if (dwarf2_get_pc_bounds (die, &low, &high, cu, NULL)) { *lowpc = min (*lowpc, low); *highpc = max (*highpc, high); @@ -3455,7 +3917,7 @@ get_scope_pc_bounds (struct die_info *die, CORE_ADDR best_high = (CORE_ADDR) 0; CORE_ADDR current_low, current_high; - if (dwarf2_get_pc_bounds (die, ¤t_low, ¤t_high, cu)) + if (dwarf2_get_pc_bounds (die, ¤t_low, ¤t_high, cu, NULL)) { best_low = current_low; best_high = current_high; @@ -3750,8 +4212,14 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, if (fieldname == NULL) return; - /* Get physical name. */ + /* Get physical name. We prefer the linkage name if one was specified, + because this lets GDB find a non-debugging version of the symbol. + Otherwise construct the full name from type information. Ideally, + when GDB supports canonicalization of C++ symbol names, we will not + need the linkage name for anything. */ physname = dwarf2_linkage_name (die, cu); + if (physname == NULL) + physname = (char *) dwarf2_full_name (die, cu); /* The name is already allocated along with this objfile, so we don't need to duplicate it for the type. */ @@ -3881,8 +4349,14 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, if (fieldname == NULL) return; - /* Get the mangled name. */ + /* Get physical name. We prefer the linkage name if one was specified, + because this lets GDB find a non-debugging version of the symbol. + Otherwise construct the full name from type information. Ideally, + when GDB supports canonicalization of C++ symbol names, we will not + need the linkage name for anything. */ physname = dwarf2_linkage_name (die, cu); + if (physname == NULL) + physname = (char *) dwarf2_full_name (die, cu); /* Look up member function name in fieldlist. */ for (i = 0; i < fip->nfnfields; i++) @@ -3926,7 +4400,7 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, /* The name is already allocated along with this objfile, so we don't need to duplicate it for the type. */ fnp->physname = physname ? physname : ""; - fnp->type = alloc_type (objfile); + fnp->type = alloc_type (objfile, NULL); this_type = read_type_die (die, cu); if (this_type && TYPE_CODE (this_type) == TYPE_CODE_FUNC) { @@ -4110,7 +4584,7 @@ quirk_gcc_member_function_pointer (struct die_info *die, struct dwarf2_cu *cu) return NULL; domain_type = TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (pfn_type, 0)); - type = alloc_type (objfile); + type = alloc_type (objfile, NULL); smash_to_method_type (type, domain_type, TYPE_TARGET_TYPE (pfn_type), TYPE_FIELDS (pfn_type), TYPE_NFIELDS (pfn_type), TYPE_VARARGS (pfn_type)); @@ -4147,7 +4621,7 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu) if (type) return type; - type = alloc_type (objfile); + type = alloc_type (objfile, NULL); INIT_CPLUS_SPECIFIC (type); name = dwarf2_name (die, cu); if (name != NULL) @@ -4360,7 +4834,7 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu) struct attribute *attr; const char *name; - type = alloc_type (objfile); + type = alloc_type (objfile, NULL); TYPE_CODE (type) = TYPE_CODE_ENUM; name = dwarf2_full_name (die, cu); @@ -4410,10 +4884,15 @@ determine_class_name (struct die_info *die, struct dwarf2_cu *cu) { if (child->tag == DW_TAG_subprogram) { - char *phys_prefix + char *phys_prefix; + char *linkage_name = dwarf2_linkage_name (child, cu); + + if (linkage_name == NULL) + continue; + + phys_prefix = language_class_name_from_physname (cu->language_defn, - dwarf2_linkage_name - (child, cu)); + linkage_name); if (phys_prefix != NULL) { @@ -4510,6 +4989,29 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu) new_symbol (die, this_type, cu); } +/* Create a new array dimension referencing its target type TYPE. + + Multidimensional arrays are internally represented as a stack of + singledimensional arrays being referenced by their TYPE_TARGET_TYPE. */ + +static struct type * +create_single_array_dimension (struct type *type, struct type *range_type, + struct die_info *die, struct dwarf2_cu *cu) +{ + type = create_array_type (NULL, type, range_type); + + /* These generic type attributes need to be fetched by + evaluate_subexp_standard 's call of + value_subscripted_rvalue only for the innermost array type. */ + fetch_die_type_attrs (die, type, cu); + + /* These generic type attributes are checked for allocated/associated + validity while accessing FIELD_LOC_KIND_DWARF_BLOCK. */ + fetch_die_type_attrs (die, range_type, cu); + + return type; +} + /* Extract all information from a DW_TAG_array_type DIE and put it in the DIE's type field. For now, this only handles one dimensional arrays. */ @@ -4523,7 +5025,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; @@ -4570,16 +5072,11 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu) type = element_type; if (read_array_order (die, cu) == DW_ORD_col_major) - { - int i = 0; - while (i < ndim) - type = create_array_type (NULL, type, range_types[i++]); - } - else - { - while (ndim-- > 0) - type = create_array_type (NULL, type, range_types[ndim]); - } + for (i = 0; i < ndim; i++) + type = create_single_array_dimension (type, range_types[i], die, cu); + else /* (read_array_order (die, cu) == DW_ORD_row_major) */ + for (i = ndim - 1; i >= 0; i--) + type = create_single_array_dimension (type, range_types[i], die, cu); /* Understand Dwarf2 support for vector types (like they occur on the PowerPC w/ AltiVec). Gcc just adds another attribute to the @@ -4646,12 +5143,14 @@ read_set_type (struct die_info *die, struct dwarf2_cu *cu) return set_die_type (die, set_type, cu); } -/* First cut: install each common block member as a global variable. */ +/* Create appropriate locally-scoped variables for all the DW_TAG_common_block + entries. Create also TYPE_CODE_STRUCT listing all such variables to be + available for `info common'. COMMON_BLOCK_DOMAIN is used to sepate the + common blocks name namespace from regular variable names. */ static void read_common_block (struct die_info *die, struct dwarf2_cu *cu) { - struct die_info *child_die; struct attribute *attr; struct symbol *sym; CORE_ADDR base = (CORE_ADDR) 0; @@ -4676,10 +5175,40 @@ read_common_block (struct die_info *die, struct dwarf2_cu *cu) } if (die->child != NULL) { + struct objfile *objfile = cu->objfile; + struct die_info *child_die; + struct type *type; + struct field *field; + char *name; + struct symbol *sym; + + type = alloc_type (objfile, NULL); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + /* Artificial type to be used only by `info common'. */ + TYPE_NAME (type) = ""; + child_die = die->child; while (child_die && child_die->tag) { + TYPE_NFIELDS (type)++; + child_die = sibling_die (child_die); + } + + TYPE_FIELDS (type) = obstack_alloc (&objfile->objfile_obstack, + sizeof (*TYPE_FIELDS (type)) + * TYPE_NFIELDS (type)); + memset (TYPE_FIELDS (type), 0, sizeof (*TYPE_FIELDS (type)) + * TYPE_NFIELDS (type)); + + field = TYPE_FIELDS (type); + child_die = die->child; + while (child_die && child_die->tag) + { + /* Create the symbol in the DW_TAG_common_block block in the current + symbol scope. */ sym = new_symbol (child_die, NULL, cu); + + /* Undocumented in DWARF3, when it can be present? */ attr = dwarf2_attr (child_die, DW_AT_data_member_location, cu); if (attr) { @@ -4687,8 +5216,25 @@ read_common_block (struct die_info *die, struct dwarf2_cu *cu) base + decode_locdesc (DW_BLOCK (attr), cu); add_symbol_to_list (sym, &global_symbols); } + + if (SYMBOL_CLASS (sym) == LOC_STATIC) + SET_FIELD_PHYSADDR (*field, SYMBOL_VALUE_ADDRESS (sym)); + else + SET_FIELD_PHYSNAME (*field, SYMBOL_LINKAGE_NAME (sym)); + FIELD_TYPE (*field) = SYMBOL_TYPE (sym); + FIELD_NAME (*field) = SYMBOL_NATURAL_NAME (sym); + field++; child_die = sibling_die (child_die); } + + /* TYPE_LENGTH (type) is left 0 - it is only a virtual structure even + with no consecutive address space. */ + + sym = new_symbol (die, type, cu); + /* SYMBOL_VALUE_ADDRESS never gets used as all its fields are static. */ + SYMBOL_VALUE_ADDRESS (sym) = base; + + set_die_type (die, type, cu); } } @@ -4756,9 +5302,7 @@ read_namespace (struct die_info *die, struct dwarf2_cu *cu) if (is_anonymous) { const char *previous_prefix = determine_prefix (die, cu); - cp_add_using_directive (TYPE_NAME (type), - strlen (previous_prefix), - strlen (TYPE_NAME (type))); + cp_add_using_directive (previous_prefix, TYPE_NAME (type), "", "", dwarf2_read_decl_line(die, cu)); } } @@ -4951,29 +5495,95 @@ read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu) struct objfile *objfile = cu->objfile; struct type *type, *range_type, *index_type, *char_type; struct attribute *attr; - unsigned int length; + int length; + + index_type = builtin_type_int32; + /* RANGE_TYPE is allocated from OBJFILE, not OBJFILE_INTERNAL. */ + range_type = alloc_type (objfile, index_type); + /* LOW_BOUND and HIGH_BOUND are set for real below. */ + range_type = create_range_type (range_type, index_type, 0, -1); + + /* C/C++ should probably have the low bound 0 but C/C++ does not use + DW_TAG_string_type. */ + TYPE_LOW_BOUND (range_type) = 1; attr = dwarf2_attr (die, DW_AT_string_length, cu); - if (attr) - { - length = DW_UNSND (attr); - } - else - { - /* check for the DW_AT_byte_size attribute */ + switch (dwarf2_get_attr_constant_value (attr, &length)) + { + case dwarf2_attr_const: + /* We currently do not support a constant address where the location + should be read from - DWARF2_ATTR_BLOCK is expected instead. See + DWARF for the DW_AT_STRING_LENGTH vs. DW_AT_BYTE_SIZE difference. */ + /* PASSTHRU */ + case dwarf2_attr_unknown: attr = dwarf2_attr (die, DW_AT_byte_size, cu); - if (attr) - { - length = DW_UNSND (attr); - } - else - { - length = 1; - } + switch (dwarf2_get_attr_constant_value (attr, &length)) + { + case dwarf2_attr_unknown: + length = 1; + /* PASSTHRU */ + case dwarf2_attr_const: + TYPE_HIGH_BOUND (range_type) = length; + break; + case dwarf2_attr_block: + TYPE_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 1); + TYPE_FIELD_DWARF_BLOCK (range_type, 1) = + dwarf2_attr_to_locexpr_baton (attr, cu); + TYPE_DYNAMIC (range_type) = 1; + break; + } + break; + case dwarf2_attr_block: + /* Security check for a size overflow. */ + if (DW_BLOCK (attr)->size + 2 < DW_BLOCK (attr)->size) + { + TYPE_HIGH_BOUND (range_type) = 1; + break; + } + /* 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. */ + { + struct dwarf2_locexpr_baton *length_baton; + struct attribute *size_attr; + + length_baton = obstack_alloc (&cu->comp_unit_obstack, + sizeof (*length_baton)); + length_baton->per_cu = cu->per_cu; + length_baton->data = obstack_alloc (&cu->comp_unit_obstack, + DW_BLOCK (attr)->size + 2); + memcpy (length_baton->data, DW_BLOCK (attr)->data, + DW_BLOCK (attr)->size); + + /* DW_AT_BYTE_SIZE existing together with DW_AT_STRING_LENGTH specifies + the size of an integer to fetch. */ + + size_attr = dwarf2_attr (die, DW_AT_byte_size, cu); + if (size_attr) + { + length_baton->size = DW_BLOCK (attr)->size + 2; + length_baton->data[DW_BLOCK (attr)->size] = DW_OP_deref_size; + length_baton->data[DW_BLOCK (attr)->size + 1] + = DW_UNSND (size_attr); + if (length_baton->data[DW_BLOCK (attr)->size + 1] + != DW_UNSND (size_attr)) + complaint (&symfile_complaints, + _("DW_AT_string_length's DW_AT_byte_size integer " + "exceeds the byte size storage")); + } + else + { + length_baton->size = DW_BLOCK (attr)->size + 1; + length_baton->data[DW_BLOCK (attr)->size] = DW_OP_deref; + } + + TYPE_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 1); + TYPE_FIELD_DWARF_BLOCK (range_type, 1) = length_baton; + TYPE_DYNAMIC (range_type) = 1; + } + break; } - index_type = builtin_type_int32; - range_type = create_range_type (NULL, index_type, 1, length); type = create_string_type (NULL, range_type); return set_die_type (die, type, cu); @@ -5067,7 +5677,6 @@ static struct type * read_typedef (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; - struct attribute *attr; const char *name = NULL; struct type *this_type; @@ -5175,8 +5784,8 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) struct type *base_type; struct type *range_type; struct attribute *attr; - int low = 0; - int high = -1; + int low, high, byte_stride_int; + enum dwarf2_get_attr_constant_value high_type; char *name; base_type = die_type (die, cu); @@ -5189,42 +5798,90 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) 0, NULL, cu->objfile); } - if (cu->language == language_fortran) - { - /* FORTRAN implies a lower bound of 1, if not given. */ - low = 1; - } + /* LOW_BOUND and HIGH_BOUND are set for real below. */ + range_type = create_range_type (NULL, base_type, 0, -1); - /* FIXME: For variable sized arrays either of these could be - a variable rather than a constant value. We'll allow it, - but we don't know how to handle it. */ attr = dwarf2_attr (die, DW_AT_lower_bound, cu); - if (attr) - low = dwarf2_get_attr_constant_value (attr, 0); + switch (dwarf2_get_attr_constant_value (attr, &low)) + { + case dwarf2_attr_unknown: + 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; + } + /* PASSTHRU */ + case dwarf2_attr_const: + TYPE_LOW_BOUND (range_type) = low; + if (low >= 0) + TYPE_UNSIGNED (range_type) = 1; + break; + case dwarf2_attr_block: + TYPE_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 0); + TYPE_FIELD_DWARF_BLOCK (range_type, 0) = dwarf2_attr_to_locexpr_baton + (attr, cu); + TYPE_DYNAMIC (range_type) = 1; + /* For setting a default if DW_AT_UPPER_BOUND would be missing. */ + low = 0; + break; + } attr = dwarf2_attr (die, DW_AT_upper_bound, cu); - if (attr) - { - if (attr->form == DW_FORM_block1) - { - /* GCC encodes arrays with unspecified or dynamic length - with a DW_FORM_block1 attribute. - FIXME: GDB does not yet know how to handle dynamic - arrays properly, treat them as arrays with unspecified - length for now. - - FIXME: jimb/2003-09-22: GDB does not really know - how to handle arrays of unspecified length - either; we just represent them as zero-length - arrays. Choose an appropriate upper bound given - the lower bound we've computed above. */ - high = low - 1; - } - else - high = dwarf2_get_attr_constant_value (attr, 1); + high_type = dwarf2_get_attr_constant_value (attr, &high); + if (high_type == dwarf2_attr_unknown) + { + attr = dwarf2_attr (die, DW_AT_count, cu); + high_type = dwarf2_get_attr_constant_value (attr, &high); + /* It does not hurt but it is needlessly ineffective in check_typedef. */ + if (high_type != dwarf2_attr_unknown) + { + TYPE_RANGE_HIGH_BOUND_IS_COUNT (range_type) = 1; + TYPE_DYNAMIC (range_type) = 1; + } + /* Pass it now as the regular DW_AT_upper_bound. */ + } + switch (high_type) + { + case dwarf2_attr_unknown: + TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (range_type) = 1; + high = low - 1; + /* PASSTHRU */ + case dwarf2_attr_const: + TYPE_HIGH_BOUND (range_type) = high; + break; + case dwarf2_attr_block: + TYPE_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 1); + TYPE_FIELD_DWARF_BLOCK (range_type, 1) = dwarf2_attr_to_locexpr_baton + (attr, cu); + TYPE_DYNAMIC (range_type) = 1; + break; } - range_type = create_range_type (NULL, base_type, low, high); + /* DW_AT_bit_stride is currently unsupported as we count in bytes. */ + attr = dwarf2_attr (die, DW_AT_byte_stride, cu); + switch (dwarf2_get_attr_constant_value (attr, &byte_stride_int)) + { + case dwarf2_attr_unknown: + break; + case dwarf2_attr_const: + if (byte_stride_int == 0) + complaint (&symfile_complaints, + _("Found DW_AT_byte_stride with unsupported value 0")); + TYPE_BYTE_STRIDE (range_type) = byte_stride_int; + break; + case dwarf2_attr_block: + TYPE_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 2); + TYPE_FIELD_DWARF_BLOCK (range_type, 2) = dwarf2_attr_to_locexpr_baton + (attr, cu); + TYPE_DYNAMIC (range_type) = 1; + break; + } name = dwarf2_name (die, cu); if (name) @@ -5386,10 +6043,13 @@ read_die_and_siblings (gdb_byte *info_ptr, bfd *abfd, } /* Decompress a section that was compressed using zlib. Store the - decompressed buffer, and its size, in OUTBUF and OUTSIZE. */ + decompressed buffer, and its size, in OUTBUF and OUTSIZE. The + result is allocated on OBSTACK; if OBSTACK is NULL, xmalloc is + used. */ static void -zlib_decompress_section (struct objfile *objfile, asection *sectp, +zlib_decompress_section (struct objfile *objfile, struct obstack *obstack, + asection *sectp, gdb_byte **outbuf, bfd_size_type *outsize) { bfd *abfd = objfile->obfd; @@ -5405,6 +6065,7 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp, z_stream strm; int rc; int header_size = 12; + struct cleanup *old = NULL; if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 || bfd_bread (compressed_buffer, compressed_size, abfd) != compressed_size) @@ -5434,8 +6095,13 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp, strm.avail_in = compressed_size - header_size; strm.next_in = (Bytef*) compressed_buffer + header_size; strm.avail_out = uncompressed_size; - uncompressed_buffer = obstack_alloc (&objfile->objfile_obstack, - uncompressed_size); + if (obstack) + uncompressed_buffer = obstack_alloc (obstack, uncompressed_size); + else + { + uncompressed_buffer = xmalloc (uncompressed_size); + old = make_cleanup (xfree, uncompressed_buffer); + } rc = inflateInit (&strm); while (strm.avail_in > 0) { @@ -5456,6 +6122,8 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp, error (_("Dwarf Error: concluding DWARF uncompression in '%s': %d"), bfd_get_filename (abfd), rc); + if (old) + discard_cleanups (old); xfree (compressed_buffer); *outbuf = uncompressed_buffer; *outsize = uncompressed_size; @@ -5463,17 +6131,20 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp, } -/* Read the contents of the section at OFFSET and of size SIZE from the - object file specified by OBJFILE into the objfile_obstack and return it. - If the section is compressed, uncompress it before returning. */ +/* Read the contents of the section at OFFSET and of size SIZE from + the object file specified by OBJFILE into OBSTACK and return it. + If OBSTACK is NULL, xmalloc is used instead. If the section is + compressed, uncompress it before returning. */ -gdb_byte * -dwarf2_read_section (struct objfile *objfile, asection *sectp) +static gdb_byte * +dwarf2_read_section_1 (struct objfile *objfile, struct obstack *obstack, + asection *sectp) { bfd *abfd = objfile->obfd; gdb_byte *buf, *retbuf; bfd_size_type size = bfd_get_section_size (sectp); unsigned char header[4]; + struct cleanup *old = NULL; if (size == 0) return NULL; @@ -5486,30 +6157,49 @@ dwarf2_read_section (struct objfile *objfile, asection *sectp) /* Upon decompression, update the buffer and its size. */ if (strncmp (header, "ZLIB", sizeof (header)) == 0) { - zlib_decompress_section (objfile, sectp, &buf, &size); + zlib_decompress_section (objfile, obstack, sectp, &buf, &size); dwarf2_resize_section (sectp, size); return buf; } } /* If we get here, we are a normal, not-compressed section. */ - buf = obstack_alloc (&objfile->objfile_obstack, size); + if (obstack) + buf = obstack_alloc (obstack, size); + else + { + buf = xmalloc (size); + old = make_cleanup (xfree, buf); + } /* When debugging .o files, we may need to apply relocations; see http://sourceware.org/ml/gdb-patches/2002-04/msg00136.html . We never compress sections in .o files, so we only need to try this when the section is not compressed. */ retbuf = symfile_relocate_debug_section (abfd, sectp, buf); if (retbuf != NULL) - return retbuf; + { + if (old) + discard_cleanups (old); + return retbuf; + } if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 || bfd_bread (buf, size, abfd) != size) error (_("Dwarf Error: Can't read DWARF data from '%s'"), bfd_get_filename (abfd)); + if (old) + discard_cleanups (old); + return buf; } +gdb_byte * +dwarf2_read_section (struct objfile *objfile, asection *sectp) +{ + return dwarf2_read_section_1 (objfile, &objfile->objfile_obstack, sectp); +} + /* In DWARF version 2, the description of the debugging information is stored in a separate .debug_abbrev section. Before we read any dies from a section we read in all abbreviations and install them @@ -5914,15 +6604,6 @@ read_partial_die (struct partial_die_info *part_die, struct attribute attr; int has_low_pc_attr = 0; int has_high_pc_attr = 0; - CORE_ADDR base_address = 0; - enum - { - base_address_none, - base_address_low_pc, - /* Overrides BASE_ADDRESS_LOW_PC. */ - base_address_entry_pc - } - base_address_type = base_address_none; memset (part_die, 0, sizeof (struct partial_die_info)); @@ -5945,47 +6626,35 @@ read_partial_die (struct partial_die_info *part_die, switch (attr.name) { case DW_AT_name: - - /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name. */ - if (part_die->name == NULL) - part_die->name = DW_STRING (&attr); - break; - case DW_AT_comp_dir: - if (part_die->dirname == NULL) - part_die->dirname = DW_STRING (&attr); + switch (part_die->tag) + { + case DW_TAG_compile_unit: + /* Compilation units have a DW_AT_name that is a filename, not + a source language identifier. */ + case DW_TAG_enumeration_type: + case DW_TAG_enumerator: + /* These tags always have simple identifiers already; no need + to canonicalize them. */ + part_die->name = DW_STRING (&attr); + break; + default: + part_die->name + = dwarf2_canonicalize_name (DW_STRING (&attr), cu, + &cu->comp_unit_obstack); + break; + } break; case DW_AT_MIPS_linkage_name: - part_die->name = DW_STRING (&attr); + part_die->linkage_name = DW_STRING (&attr); break; case DW_AT_low_pc: has_low_pc_attr = 1; part_die->lowpc = DW_ADDR (&attr); - if (part_die->tag == DW_TAG_compile_unit - && base_address_type < base_address_low_pc) - { - base_address = DW_ADDR (&attr); - base_address_type = base_address_low_pc; - } break; case DW_AT_high_pc: has_high_pc_attr = 1; part_die->highpc = DW_ADDR (&attr); break; - case DW_AT_entry_pc: - if (part_die->tag == DW_TAG_compile_unit - && base_address_type < base_address_entry_pc) - { - base_address = DW_ADDR (&attr); - base_address_type = base_address_entry_pc; - } - break; - case DW_AT_ranges: - if (part_die->tag == DW_TAG_compile_unit) - { - cu->ranges_offset = DW_UNSND (&attr); - cu->has_ranges_offset = 1; - } - break; case DW_AT_location: /* Support the .debug_loc offsets */ if (attr_form_is_block (&attr)) @@ -6002,9 +6671,6 @@ read_partial_die (struct partial_die_info *part_die, "partial symbol information"); } break; - case DW_AT_language: - part_die->language = DW_UNSND (&attr); - break; case DW_AT_external: part_die->is_external = DW_UNSND (&attr); break; @@ -6029,10 +6695,6 @@ read_partial_die (struct partial_die_info *part_die, part_die->sibling = dwarf2_per_objfile->info_buffer + dwarf2_get_ref_die_offset (&attr); break; - case DW_AT_stmt_list: - part_die->has_stmt_list = 1; - part_die->line_offset = DW_UNSND (&attr); - break; case DW_AT_byte_size: part_die->has_byte_size = 1; break; @@ -6074,13 +6736,6 @@ read_partial_die (struct partial_die_info *part_die, || dwarf2_per_objfile->has_section_at_zero)) part_die->has_pc_info = 1; - if (base_address_type != base_address_none && !cu->base_known) - { - gdb_assert (part_die->tag == DW_TAG_compile_unit); - cu->base_known = 1; - cu->base_address = base_address; - } - return info_ptr; } @@ -6173,7 +6828,9 @@ fixup_partial_die (struct partial_die_info *part_die, /* If we found a reference attribute and the DIE has no name, try to find a name in the referred to DIE. */ - if (part_die->name == NULL && part_die->has_specification) + if (part_die->has_specification + && (part_die->name == NULL || part_die->linkage_name == NULL + || !part_die->is_external)) { struct partial_die_info *spec_die; @@ -6189,6 +6846,9 @@ fixup_partial_die (struct partial_die_info *part_die, if (spec_die->is_external) part_die->is_external = spec_die->is_external; } + + if (spec_die->linkage_name) + part_die->linkage_name = spec_die->linkage_name; } /* Set default names for some unnamed DIEs. */ @@ -7512,10 +8172,12 @@ var_decode_location (struct attribute *attr, struct symbol *sym, (i.e. when the value of a register or memory location is referenced, or a thread-local block, etc.). Then again, it might not be worthwhile. I'm assuming that it isn't unless performance - or memory numbers show me otherwise. */ + or memory numbers show me otherwise. + + SYMBOL_CLASS may get overriden by dwarf2_symbol_mark_computed. */ - dwarf2_symbol_mark_computed (attr, sym, cu); SYMBOL_CLASS (sym) = LOC_COMPUTED; + dwarf2_symbol_mark_computed (attr, sym, cu); } /* Given a pointer to a DWARF information entry, figure out if we need @@ -7538,20 +8200,43 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); if (die->tag != DW_TAG_namespace) - name = dwarf2_linkage_name (die, cu); + name = dwarf2_name (die, cu); else name = TYPE_NAME (type); if (name) { + const char *linkagename; + sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack, sizeof (struct symbol)); OBJSTAT (objfile, n_syms++); memset (sym, 0, sizeof (struct symbol)); + /* Some methods are called without checking SYMBOL_OPS validity. */ + SYMBOL_OPS (sym) = &dwarf2_missing_funcs; - /* Cache this symbol's name and the name's demangled form (if any). */ SYMBOL_LANGUAGE (sym) = cu->language; - SYMBOL_SET_NAMES (sym, name, strlen (name), objfile); + + /* Cache this symbol's name and the name's demangled form (if any). */ + + linkagename = dwarf2_linkage_name (die, cu); + if (linkagename) + /* We use the linkage name if available, for the same reason + we used it for TYPE_FN_FIELD_PHYSNAME earlier in this file. + This usage can be removed someday. */ + SYMBOL_SET_NAMES (sym, linkagename, strlen (linkagename), objfile); + else if (die->tag == DW_TAG_namespace) + SYMBOL_SET_LINKAGE_NAME (sym, name); + else + { + linkagename = dwarf2_full_name (die, cu); + + /* Set just the "linkage" name to the fully qualified name. + While this is not really a linkage name, it should match + the demangled version of the corresponding minimal symbol + if there is one. */ + SYMBOL_SET_LINKAGE_NAME (sym, (char *) linkagename); + } /* Default assumptions. Use the passed type or decode it from the die. */ @@ -7637,7 +8322,15 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) if (attr) { var_decode_location (attr, sym, cu); - attr2 = dwarf2_attr (die, DW_AT_external, cu); + + /* Fortran explicitely imports any global symbols to the local + scope by DW_TAG_common_block. DW_AT_external means for + Fortran the variable is importable versus it is automatically + imported. */ + if (cu->language == language_fortran) + attr2 = NULL; + else + attr2 = dwarf2_attr (die, DW_AT_external, cu); if (attr2 && (DW_UNSND (attr2) != 0)) add_symbol_to_list (sym, &global_symbols); else @@ -7780,6 +8473,11 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) SYMBOL_CLASS (sym) = LOC_TYPEDEF; add_symbol_to_list (sym, &global_symbols); break; + case DW_TAG_common_block: + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_DOMAIN (sym) = COMMON_BLOCK_DOMAIN; + add_symbol_to_list (sym, cu->list_in_scope); + break; default: /* Not a tag we recognize. Hopefully we aren't processing trash data, but since we must specifically ignore things @@ -8048,6 +8746,9 @@ read_type_die (struct die_info *die, struct dwarf2_cu *cu) break; } + if (this_type) + finalize_type (this_type); + return this_type; } @@ -8128,6 +8829,19 @@ determine_prefix (struct die_info *die, struct dwarf2_cu *cu) members; no typedefs, no member functions, et cetera. So it does not need a prefix. */ return ""; + + case DW_TAG_subprogram: + /* A class's symbol, or a variable's symbol, will live + directly in a function's block, so no prefix is + appropriate. However, what about methods of a + function-local class? They end up in the global symbol + table because they are separate functions... their mangling + normally would make them inaccessible. They'll show up + wrong in breakpoints too. This is a symptom of the + inconsistent way we handle symbol tables. Namespaces and + classes should have dictionaries just like blocks do. */ + return ""; + default: return determine_prefix (parent, cu); } @@ -8192,23 +8906,62 @@ dwarf2_linkage_name (struct die_info *die, struct dwarf2_cu *cu) attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu); if (attr && DW_STRING (attr)) return DW_STRING (attr); - attr = dwarf2_attr (die, DW_AT_name, cu); - if (attr && DW_STRING (attr)) - return DW_STRING (attr); return NULL; } /* Get name of a die, return NULL if not found. */ static char * +dwarf2_canonicalize_name (char *name, struct dwarf2_cu *cu, + struct obstack *obstack) +{ + if (cu->language == language_cplus) + { + char *canon_name = cp_canonicalize_string (name); + + if (canon_name != NULL) + { + if (strcmp (canon_name, name) != 0) + name = obsavestring (canon_name, strlen (canon_name), + obstack); + xfree (canon_name); + } + } + + return name; +} + +/* Get name of a die, return NULL if not found. */ + +static char * dwarf2_name (struct die_info *die, struct dwarf2_cu *cu) { struct attribute *attr; attr = dwarf2_attr (die, DW_AT_name, cu); - if (attr && DW_STRING (attr)) - return DW_STRING (attr); - return NULL; + if (!attr || !DW_STRING (attr)) + return NULL; + + switch (die->tag) + { + case DW_TAG_compile_unit: + /* Compilation units have a DW_AT_name that is a filename, not + a source language identifier. */ + case DW_TAG_enumeration_type: + case DW_TAG_enumerator: + /* These tags always have simple identifiers already; no need + to canonicalize them. */ + return DW_STRING (attr); + default: + if (attr->form != GDB_FORM_cached_string) + { + DW_STRING (attr) + = dwarf2_canonicalize_name (DW_STRING (attr), cu, + &cu->objfile->objfile_obstack); + attr->form = GDB_FORM_cached_string; + } + return DW_STRING (attr); + } } /* Return the die that this die in an extension of, or NULL if there @@ -8703,6 +9456,8 @@ dwarf_form_name (unsigned form) return "DW_FORM_ref_udata"; case DW_FORM_indirect: return "DW_FORM_indirect"; + case GDB_FORM_cached_string: + return "GDB_FORM_cached_string"; default: return "DW_FORM_"; } @@ -9248,6 +10003,7 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) break; case DW_FORM_string: case DW_FORM_strp: + case GDB_FORM_cached_string: fprintf_unfiltered (f, "string: \"%s\"", DW_STRING (&die->attrs[i]) ? DW_STRING (&die->attrs[i]) : ""); @@ -9353,26 +10109,35 @@ dwarf2_get_ref_die_offset (struct attribute *attr) return result; } -/* Return the constant value held by the given attribute. Return -1 - if the value held by the attribute is not constant. */ +/* (*val_return) is filled only if returning dwarf2_attr_const. */ -static int -dwarf2_get_attr_constant_value (struct attribute *attr, int default_value) +static enum dwarf2_get_attr_constant_value +dwarf2_get_attr_constant_value (struct attribute *attr, int *val_return) { + if (attr == NULL) + return dwarf2_attr_unknown; if (attr->form == DW_FORM_sdata) - return DW_SND (attr); - else if (attr->form == DW_FORM_udata - || attr->form == DW_FORM_data1 - || attr->form == DW_FORM_data2 - || attr->form == DW_FORM_data4 - || attr->form == DW_FORM_data8) - return DW_UNSND (attr); - else { - complaint (&symfile_complaints, _("Attribute value is not a constant (%s)"), - dwarf_form_name (attr->form)); - return default_value; + *val_return = DW_SND (attr); + return dwarf2_attr_const; } + if (attr->form == DW_FORM_udata + || attr->form == DW_FORM_data1 + || attr->form == DW_FORM_data2 + || attr->form == DW_FORM_data4 + || attr->form == DW_FORM_data8) + { + *val_return = DW_UNSND (attr); + return dwarf2_attr_const; + } + if (attr->form == DW_FORM_block + || attr->form == DW_FORM_block1 + || attr->form == DW_FORM_block2 + || attr->form == DW_FORM_block4) + return dwarf2_attr_block; + complaint (&symfile_complaints, _("Attribute value is not a constant (%s)"), + dwarf_form_name (attr->form)); + return dwarf2_attr_unknown; } /* THIS_CU has a reference to PER_CU. If necessary, load the new compilation @@ -9963,6 +10728,17 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, { gdb_byte *mac_ptr, *mac_end; struct macro_source_file *current_file = 0; + enum dwarf_macinfo_record_type macinfo_type; + + /* Flag is in use by the second pass and determines if GDB is still before + first DW_MACINFO_start_file. If true GDB is still reading the definitions + from command line. First DW_MACINFO_start_file will need to be ignored as + it was already executed to create CURRENT_FILE for the main source holding + also the command line definitions. On first met DW_MACINFO_start_file + this flag is reset to normally execute all the remaining + DW_MACINFO_start_file macinfos. */ + + int at_commandline; if (dwarf2_per_objfile->macinfo_buffer == NULL) { @@ -9970,19 +10746,24 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, return; } + /* Start the first pass to find ahead the main source file name. GDB has to + create CURRENT_FILE where to place the macros given to the compiler + from the command line. Such command line macros are present before first + DW_MACINFO_start_file but still those macros are associated to the + compilation unit. The compilation unit GDB identifies by its main source + file name. */ + mac_ptr = dwarf2_per_objfile->macinfo_buffer + offset; mac_end = dwarf2_per_objfile->macinfo_buffer + dwarf2_per_objfile->macinfo_size; - for (;;) + do { - enum dwarf_macinfo_record_type macinfo_type; - /* Do we at least have room for a macinfo type byte? */ if (mac_ptr >= mac_end) { dwarf2_macros_too_long_complaint (); - return; + break; } macinfo_type = read_1_byte (abfd, mac_ptr); @@ -9993,7 +10774,81 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, /* A zero macinfo type indicates the end of the macro information. */ case 0: - return; + break; + + case DW_MACINFO_define: + case DW_MACINFO_undef: + /* Only skip the data by MAC_PTR. */ + { + unsigned int bytes_read; + + read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); + mac_ptr += bytes_read; + read_string (abfd, mac_ptr, &bytes_read); + mac_ptr += bytes_read; + } + break; + + case DW_MACINFO_start_file: + { + unsigned int bytes_read; + int line, file; + + line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); + mac_ptr += bytes_read; + file = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); + mac_ptr += bytes_read; + + current_file = macro_start_file (file, line, current_file, comp_dir, + lh, cu->objfile); + } + break; + + case DW_MACINFO_end_file: + /* No data to skip by MAC_PTR. */ + break; + + case DW_MACINFO_vendor_ext: + /* Only skip the data by MAC_PTR. */ + { + unsigned int bytes_read; + + read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); + mac_ptr += bytes_read; + read_string (abfd, mac_ptr, &bytes_read); + mac_ptr += bytes_read; + } + break; + + default: + break; + } + } while (macinfo_type != 0 && current_file == NULL); + + /* Here is the second pass to read in the macros starting from the ones + defined at the command line. */ + + mac_ptr = dwarf2_per_objfile->macinfo_buffer + offset; + at_commandline = 1; + + do + { + /* Do we at least have room for a macinfo type byte? */ + if (mac_ptr >= mac_end) + { + /* Complaint is in the first pass above. */ + break; + } + + macinfo_type = read_1_byte (abfd, mac_ptr); + mac_ptr++; + + switch (macinfo_type) + { + /* A zero macinfo type indicates the end of the macro + information. */ + case 0: + break; case DW_MACINFO_define: case DW_MACINFO_undef: @@ -10008,19 +10863,31 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, mac_ptr += bytes_read; if (! current_file) + { + /* DWARF violation as no main source is present. */ + complaint (&symfile_complaints, + _("debug info with no main source gives macro %s " + "on line %d: %s"), + macinfo_type == + DW_MACINFO_define ? _("definition") : macinfo_type == + DW_MACINFO_undef ? _("undefinition") : + "something-or-other", line, body); + break; + } + if (at_commandline != (line == 0)) complaint (&symfile_complaints, - _("debug info gives macro %s outside of any file: %s"), + _("debug info gives %s macro %s with %s line %d: %s"), + at_commandline ? _("command-line") : _("in-file"), macinfo_type == - DW_MACINFO_define ? "definition" : macinfo_type == - DW_MACINFO_undef ? "undefinition" : - "something-or-other", body); - else - { - if (macinfo_type == DW_MACINFO_define) - parse_macro_definition (current_file, line, body); - else if (macinfo_type == DW_MACINFO_undef) - macro_undef (current_file, line, body); - } + DW_MACINFO_define ? _("definition") : macinfo_type == + DW_MACINFO_undef ? _("undefinition") : + "something-or-other", + line == 0 ? _("zero") : _("non-zero"), line, body); + + if (macinfo_type == DW_MACINFO_define) + parse_macro_definition (current_file, line, body); + else if (macinfo_type == DW_MACINFO_undef) + macro_undef (current_file, line, body); } break; @@ -10034,9 +10901,22 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, file = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); mac_ptr += bytes_read; - current_file = macro_start_file (file, line, - current_file, comp_dir, - lh, cu->objfile); + if (at_commandline != (line == 0)) + complaint (&symfile_complaints, + _("debug info gives source %d included " + "from %s at %s line %d"), + file, at_commandline ? _("command-line") : _("file"), + line == 0 ? _("zero") : _("non-zero"), line); + + if (at_commandline) + { + /* This DW_MACINFO_start_file was executed in the pass one. */ + at_commandline = 0; + } + else + current_file = macro_start_file (file, line, + current_file, comp_dir, + lh, cu->objfile); } break; @@ -10090,7 +10970,7 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, } break; } - } + } while (macinfo_type != 0); } /* Check if the attribute's form is a DW_FORM_block* @@ -10150,6 +11030,34 @@ attr_form_is_constant (struct attribute *attr) } } +/* Convert DW_BLOCK into struct dwarf2_locexpr_baton. ATTR must be a DW_BLOCK + attribute type. */ + +static struct dwarf2_locexpr_baton * +dwarf2_attr_to_locexpr_baton (struct attribute *attr, struct dwarf2_cu *cu) +{ + struct dwarf2_locexpr_baton *baton; + + gdb_assert (attr_form_is_block (attr)); + + baton = obstack_alloc (&cu->objfile->objfile_obstack, sizeof (*baton)); + baton->per_cu = cu->per_cu; + gdb_assert (baton->per_cu); + + /* Note that we're just copying the block's data pointer + here, not the actual data. We're still pointing into the + info_buffer for SYM's objfile; right now we never release + that buffer, but when we do clean up properly this may + need to change. */ + baton->size = DW_BLOCK (attr)->size; + baton->data = DW_BLOCK (attr)->data; + gdb_assert (baton->size == 0 || baton->data != NULL); + + return baton; +} + +/* SYM may get its SYMBOL_CLASS overriden on invalid ATTR content. */ + static void dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu) @@ -10179,35 +11087,24 @@ dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, SYMBOL_OPS (sym) = &dwarf2_loclist_funcs; SYMBOL_LOCATION_BATON (sym) = baton; } + else if (attr_form_is_block (attr)) + { + SYMBOL_OPS (sym) = &dwarf2_locexpr_funcs; + SYMBOL_LOCATION_BATON (sym) = dwarf2_attr_to_locexpr_baton (attr, cu); + } else { - struct dwarf2_locexpr_baton *baton; + dwarf2_invalid_attrib_class_complaint ("location description", + SYMBOL_NATURAL_NAME (sym)); - baton = obstack_alloc (&cu->objfile->objfile_obstack, - sizeof (struct dwarf2_locexpr_baton)); - baton->per_cu = cu->per_cu; - gdb_assert (baton->per_cu); + /* Some methods are called without checking SYMBOL_OPS validity. */ + SYMBOL_OPS (sym) = &dwarf2_missing_funcs; + SYMBOL_LOCATION_BATON (sym) = NULL; - if (attr_form_is_block (attr)) - { - /* Note that we're just copying the block's data pointer - here, not the actual data. We're still pointing into the - info_buffer for SYM's objfile; right now we never release - that buffer, but when we do clean up properly this may - need to change. */ - baton->size = DW_BLOCK (attr)->size; - baton->data = DW_BLOCK (attr)->data; - } - else - { - dwarf2_invalid_attrib_class_complaint ("location description", - SYMBOL_NATURAL_NAME (sym)); - baton->size = 0; - baton->data = NULL; - } - - SYMBOL_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; } } @@ -10482,6 +11379,31 @@ offset_and_type_eq (const void *item_lhs, const void *item_rhs) return ofs_lhs->offset == ofs_rhs->offset; } +/* Fill in generic attributes applicable for type DIEs. */ + +static void +fetch_die_type_attrs (struct die_info *die, struct type *type, + struct dwarf2_cu *cu) +{ + struct attribute *attr; + + attr = dwarf2_attr (die, DW_AT_data_location, cu); + if (attr_form_is_block (attr)) + TYPE_DATA_LOCATION_DWARF_BLOCK (type) = dwarf2_attr_to_locexpr_baton (attr, + cu); + gdb_assert (!TYPE_DATA_LOCATION_IS_ADDR (type)); + + attr = dwarf2_attr (die, DW_AT_allocated, cu); + if (attr_form_is_block (attr)) + TYPE_ALLOCATED (type) = dwarf2_attr_to_locexpr_baton (attr, cu); + gdb_assert (!TYPE_NOT_ALLOCATED (type)); + + attr = dwarf2_attr (die, DW_AT_associated, cu); + if (attr_form_is_block (attr)) + TYPE_ASSOCIATED (type) = dwarf2_attr_to_locexpr_baton (attr, cu); + gdb_assert (!TYPE_NOT_ASSOCIATED (type)); +} + /* Set the type associated with DIE to TYPE. Save it in CU's hash table if necessary. For convenience, return TYPE. */ @@ -10490,6 +11412,8 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu) { struct dwarf2_offset_and_type **slot, ofs; + fetch_die_type_attrs (die, type, cu); + if (cu->type_hash == NULL) { gdb_assert (cu->per_cu != NULL); diff --git a/gdb/elfread.c b/gdb/elfread.c index ff220a2..13158f4 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -727,10 +727,18 @@ elf_symfile_read (struct objfile *objfile, int mainline) str_sect->filepos, bfd_section_size (abfd, str_sect)); } + + if (dwarf2_has_info (objfile)) + dwarf2_create_quick_addrmap (objfile); +} + +static void +read_psyms (struct objfile *objfile) +{ if (dwarf2_has_info (objfile)) { /* DWARF 2 sections */ - dwarf2_build_psymtabs (objfile, mainline); + dwarf2_build_psymtabs (objfile, 0); } /* FIXME: kettenis/20030504: This still needs to be integrated with @@ -880,6 +888,7 @@ static struct sym_fns elf_sym_fns = elf_new_init, /* sym_new_init: init anything gbl to entire symtab */ elf_symfile_init, /* sym_init: read initial info, setup for sym_read() */ elf_symfile_read, /* sym_read: read a symbol file into symtab */ + read_psyms, /* sym_read_psymbols */ elf_symfile_finish, /* sym_finish: finished with file, cleanup */ default_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */ elf_symfile_segments, /* sym_segments: Get segment information from diff --git a/gdb/eval.c b/gdb/eval.c index 1d35571..6a97e09 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -39,10 +39,16 @@ #include "exceptions.h" #include "regcache.h" #include "user-regs.h" +#include "python/python.h" #include "valprint.h" +#include "dwarf2loc.h" +#include "gdb_obstack.h" +#include "objfiles.h" #include "gdb_assert.h" +#include + /* This is defined in valops.c */ extern int overload_resolution; @@ -651,6 +657,64 @@ ptrmath_type_p (struct type *type) } } +/* Compares the two method/function types T1 and T2 for "equality" + with respect to the the methods' parameters. If the types of the + two parameter lists are the same, returns 1; 0 otherwise. This + comparison ignores any artificial this pointer. */ +int +compare_parameters (struct type *t1, struct type *t2) +{ + int i, has_this; + /* Hacky: we don't know a priori whether or not t1 is a static + method, so we skip any artificial "this" pointer and hope + for the best. t2, which comes as user input, never contains a + "this" pointer (a user would never enter it into expressions. */ + if (TYPE_NFIELDS (t1) > 0) + has_this = TYPE_FIELD_ARTIFICIAL (t1, 0) ? 1 : 0; + else + has_this = 0; + + /* Special case: a method taking void. t1 will contain either + no fields or just "this". t2 will contain TYPE_CODE_VOID. */ + if ((TYPE_NFIELDS (t1) - has_this) == 0 && TYPE_NFIELDS (t2) == 1 + && TYPE_CODE (TYPE_FIELD_TYPE (t2, 0)) == TYPE_CODE_VOID) + return 1; + + if ((TYPE_NFIELDS (t1) - has_this) == TYPE_NFIELDS (t2)) + { + for (i = has_this; i < TYPE_NFIELDS (t1); ++i) + { + if (rank_one_type (TYPE_FIELD_TYPE (t1, i), + TYPE_FIELD_TYPE (t2, i - has_this)) + != 0) + return 0; + } + + return 1; + } + + return 0; +} + +/* Constructs a fake method with the given parameter types. */ + +static struct type * +make_params (int num_types, struct type **param_types) +{ + struct type *type = alloc_type (NULL, NULL); + TYPE_LENGTH (type) = 1; + TYPE_CODE (type) = TYPE_CODE_METHOD; + TYPE_NFIELDS (type) = num_types; + TYPE_FIELDS (type) = (struct field *) + TYPE_ALLOC (type, sizeof (struct field) * num_types); + memset (TYPE_FIELDS (type), 0, sizeof (struct field) * num_types); + + while (num_types-- > 0) + TYPE_FIELD_TYPE (type, num_types) = param_types[num_types]; + + return type; +} + struct value * evaluate_subexp_standard (struct type *expect_type, struct expression *exp, int *pos, @@ -671,6 +735,7 @@ evaluate_subexp_standard (struct type *expect_type, long mem_offset; struct type **arg_types; int save_pos1; + struct cleanup *old_chain; pc = (*pos)++; op = exp->elts[pc].opcode; @@ -684,7 +749,7 @@ evaluate_subexp_standard (struct type *expect_type, goto nosideret; arg1 = value_aggregate_elt (exp->elts[pc + 1].type, &exp->elts[pc + 3].string, - 0, noside); + expect_type, 0, noside); if (arg1 == NULL) error (_("There is no field named %s"), &exp->elts[pc + 3].string); return arg1; @@ -1208,9 +1273,9 @@ evaluate_subexp_standard (struct type *expect_type, if (TYPE_CODE (value_type (method)) != TYPE_CODE_FUNC) error (_("method address has symbol information with non-function type; skipping")); if (struct_return) - VALUE_ADDRESS (method) = value_as_address (msg_send_stret); + set_value_address (method, value_as_address (msg_send_stret)); else - VALUE_ADDRESS (method) = value_as_address (msg_send); + set_value_address (method, value_as_address (msg_send)); called_method = method; } else @@ -1284,7 +1349,6 @@ evaluate_subexp_standard (struct type *expect_type, argvec = (struct value **) alloca (sizeof (struct value *) * (nargs + 3)); if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) { - nargs++; /* First, evaluate the structure into arg2 */ pc2 = (*pos)++; @@ -1308,21 +1372,40 @@ evaluate_subexp_standard (struct type *expect_type, arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); - if (TYPE_CODE (check_typedef (value_type (arg1))) - != TYPE_CODE_METHODPTR) - error (_("Non-pointer-to-member value used in pointer-to-member " - "construct")); - - if (noside == EVAL_AVOID_SIDE_EFFECTS) + type = check_typedef (value_type (arg1)); + switch (TYPE_CODE (type)) { - struct type *method_type = check_typedef (value_type (arg1)); - arg1 = value_zero (method_type, not_lval); + case TYPE_CODE_METHODPTR: + if (noside == EVAL_AVOID_SIDE_EFFECTS) + arg1 = value_zero (TYPE_TARGET_TYPE (type), not_lval); + else + arg1 = cplus_method_ptr_to_value (&arg2, arg1); + + /* Now, say which argument to start evaluating from */ + nargs++; + tem = 2; + argvec[1] = arg2; + break; + + case TYPE_CODE_MEMBERPTR: + /* Now, convert these values to an address. */ + arg2 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)), + arg2); + + mem_offset = value_as_long (arg1); + + arg1 = value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)), + value_as_long (arg2) + mem_offset); + arg1 = value_ind (arg1); + tem = 1; + break; + + default: + error (_("Non-pointer-to-member value used in pointer-to-member " + "construct")); } - else - arg1 = cplus_method_ptr_to_value (&arg2, arg1); - /* Now, say which argument to start evaluating from */ - tem = 2; + argvec[0] = arg1; } else if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR) { @@ -1434,7 +1517,7 @@ evaluate_subexp_standard (struct type *expect_type, of the ``this'' pointer if necessary, so modify argvec[1] to reflect any ``this'' changes. */ arg2 = value_from_longest (lookup_pointer_type(value_type (temp)), - VALUE_ADDRESS (temp) + value_offset (temp) + value_address (temp) + value_embedded_offset (temp)); argvec[1] = arg2; /* the ``this'' pointer */ } @@ -1448,8 +1531,7 @@ evaluate_subexp_standard (struct type *expect_type, } else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) { - argvec[1] = arg2; - argvec[0] = arg1; + /* Pointer to member. argvec is already set up. */ } else if (op == OP_VAR_VALUE) { @@ -1512,6 +1594,9 @@ evaluate_subexp_standard (struct type *expect_type, else error (_("Expression of type other than \"Function returning ...\" used as function")); } + if (TYPE_CODE (value_type (argvec[0])) == TYPE_CODE_INTERNAL_FUNCTION) + return call_internal_function (argvec[0], nargs, argvec + 1); + return call_function_by_hand (argvec[0], nargs, argvec + 1); /* pai: FIXME save value from call_function_by_hand, then adjust pc by adjust_fn_pc if +ve */ @@ -1529,7 +1614,10 @@ evaluate_subexp_standard (struct type *expect_type, /* First determine the type code we are dealing with. */ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + old_chain = make_cleanup (null_cleanup, 0); + object_address_set (VALUE_ADDRESS (arg1)); type = check_typedef (value_type (arg1)); + do_cleanups (old_chain); code = TYPE_CODE (type); if (code == TYPE_CODE_PTR) @@ -1696,6 +1784,37 @@ evaluate_subexp_standard (struct type *expect_type, error (_("non-pointer-to-member value used in pointer-to-member construct")); } + case TYPE_INSTANCE: + nargs = longest_to_int (exp->elts[pc + 1].longconst); + arg_types = (struct type **) alloca (nargs * sizeof (struct type *)); + for (ix = 0; ix < nargs; ++ix) + arg_types[ix] = exp->elts[pc + 1 + ix + 1].type; + + expect_type = make_params (nargs, arg_types); + *(pos) += 3 + nargs; + return evaluate_subexp_standard (expect_type, exp, pos, noside); + + case TYPE_INSTANCE_LOOKUP: + { + int i; + struct symbol *sym; + struct type **arg_types; + (*pos) += 3; + printf ("TYPE_INSTANCE_LOOKUP\n"); + arg_types = (struct type **) alloca (TYPE_NFIELDS (expect_type) + * sizeof (struct type *)); + for (i = 0; i < TYPE_NFIELDS (expect_type); ++i) + arg_types[i] = TYPE_FIELD_TYPE (expect_type, i); + (void) find_overload_match (arg_types, TYPE_NFIELDS (expect_type), + NULL /* no need for name */, + 0 /* not method */, + 0 /* strict match */, + NULL, exp->elts[pc + 1].symbol, NULL, + &sym, NULL); + i = 0; + } + break; + case BINOP_CONCAT: arg1 = evaluate_subexp_with_coercion (exp, pos, noside); arg2 = evaluate_subexp_with_coercion (exp, pos, noside); @@ -1963,13 +2082,19 @@ evaluate_subexp_standard (struct type *expect_type, { int subscript_array[MAX_FORTRAN_DIMS]; int array_size_array[MAX_FORTRAN_DIMS]; + int byte_stride_array[MAX_FORTRAN_DIMS]; int ndimensions = 1, i; struct type *tmp_type; int offset_item; /* The array offset where the item lives */ + CORE_ADDR offset_byte; /* byte_stride based offset */ + unsigned element_size; if (nargs > MAX_FORTRAN_DIMS) error (_("Too many subscripts for F77 (%d Max)"), MAX_FORTRAN_DIMS); + old_chain = make_cleanup (null_cleanup, 0); + object_address_set (VALUE_ADDRESS (arg1)); + tmp_type = check_typedef (value_type (arg1)); ndimensions = calc_f77_array_dims (type); @@ -1999,6 +2124,9 @@ evaluate_subexp_standard (struct type *expect_type, upper = f77_get_upperbound (tmp_type); lower = f77_get_lowerbound (tmp_type); + byte_stride_array[nargs - i - 1] = + TYPE_ARRAY_BYTE_STRIDE_VALUE (tmp_type); + array_size_array[nargs - i - 1] = upper - lower + 1; /* Zero-normalize subscripts so that offsetting will work. */ @@ -2017,17 +2145,25 @@ evaluate_subexp_standard (struct type *expect_type, tmp_type = check_typedef (TYPE_TARGET_TYPE (tmp_type)); } - /* Now let us calculate the offset for this item */ + /* Kept for the f77_get_upperbound / f77_get_lowerbound calls above. */ + do_cleanups (old_chain); - offset_item = subscript_array[ndimensions - 1]; + /* Now let us calculate the offset for this item */ - for (i = ndimensions - 1; i > 0; --i) - offset_item = - array_size_array[i - 1] * offset_item + subscript_array[i - 1]; + offset_item = 0; + offset_byte = 0; - /* Construct a value node with the value of the offset */ + for (i = ndimensions - 1; i >= 0; --i) + { + offset_item *= array_size_array[i]; + if (byte_stride_array[i] == 0) + offset_item += subscript_array[i]; + else + offset_byte += subscript_array[i] * byte_stride_array[i]; + } - arg2 = value_from_longest (builtin_type_int32, offset_item); + element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (tmp_type)); + offset_byte += offset_item * element_size; /* Let us now play a dirty trick: we will take arg1 which is a value node pointing to the topmost level @@ -2037,7 +2173,7 @@ evaluate_subexp_standard (struct type *expect_type, returns the correct type value */ deprecated_set_value_type (arg1, tmp_type); - return value_subscripted_rvalue (arg1, arg2, 0); + return value_subscripted_rvalue (arg1, offset_byte); } case BINOP_LOGICAL_AND: @@ -2475,7 +2611,17 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP) goto nosideret; else if (noside == EVAL_AVOID_SIDE_EFFECTS) - return allocate_value (exp->elts[pc + 1].type); + { + struct type *type = exp->elts[pc + 1].type; + /* If this is a typedef, then find its immediate target. We + use check_typedef to resolve stubs, but we ignore its + result because we do not want to dig past all + typedefs. */ + check_typedef (type); + if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) + type = TYPE_TARGET_TYPE (type); + return allocate_value (type); + } else error (_("Attempt to use a type name as an expression")); @@ -2568,7 +2714,7 @@ evaluate_subexp_for_address (struct expression *exp, int *pos, (*pos) += 5 + BYTES_TO_EXP_ELEM (tem + 1); x = value_aggregate_elt (exp->elts[pc + 1].type, &exp->elts[pc + 3].string, - 1, noside); + NULL, 1, noside); if (x == NULL) error (_("There is no field named %s"), &exp->elts[pc + 3].string); return x; @@ -2613,7 +2759,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; @@ -2624,12 +2770,17 @@ evaluate_subexp_with_coercion (struct expression *exp, { case OP_VAR_VALUE: var = exp->elts[pc + 2].symbol; + /* address_of_variable will call object_address_set for check_typedef. + Call it only if required as it can error-out on VAR in register. */ + if (TYPE_DYNAMIC (SYMBOL_TYPE (var))) + val = address_of_variable (var, exp->elts[pc + 1].block); type = check_typedef (SYMBOL_TYPE (var)); if (TYPE_CODE (type) == TYPE_CODE_ARRAY && CAST_IS_CONVERSION) { (*pos) += 4; - val = address_of_variable (var, exp->elts[pc + 1].block); + if (!val) + val = address_of_variable (var, exp->elts[pc + 1].block); return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)), val); } @@ -2681,9 +2832,13 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos) case OP_VAR_VALUE: (*pos) += 4; - type = check_typedef (SYMBOL_TYPE (exp->elts[pc + 2].symbol)); - return - value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type)); + /* We do not need to call read_var_value but the object evaluation may + need to have executed object_address_set which needs valid + SYMBOL_VALUE_ADDRESS of the symbol. Still VALUE returned by + read_var_value we left as lazy. */ + type = value_type (read_var_value (exp->elts[pc + 2].symbol, + deprecated_safe_get_selected_frame ())); + return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type)); default: val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); diff --git a/gdb/expprint.c b/gdb/expprint.c index 89bae03..f768940 100644 --- a/gdb/expprint.c +++ b/gdb/expprint.c @@ -186,8 +186,8 @@ print_subexp_standard (struct expression *exp, int *pos, If necessary, we can temporarily set it to zero, or pass it as an additional parameter to LA_PRINT_STRING. -fnf */ get_user_print_options (&opts); - LA_PRINT_STRING (stream, &exp->elts[pc + 2].string, nargs, 1, 0, - &opts); + LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char, + &exp->elts[pc + 2].string, nargs, 0, &opts); } return; @@ -205,8 +205,8 @@ print_subexp_standard (struct expression *exp, int *pos, (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1); fputs_filtered ("@\"", stream); get_user_print_options (&opts); - LA_PRINT_STRING (stream, &exp->elts[pc + 2].string, nargs, 1, 0, - &opts); + LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char, + &exp->elts[pc + 2].string, nargs, 0, &opts); fputs_filtered ("\"", stream); } return; @@ -291,8 +291,8 @@ print_subexp_standard (struct expression *exp, int *pos, { struct value_print_options opts; get_user_print_options (&opts); - LA_PRINT_STRING (stream, tempstr, nargs - 1, 1, 0, - &opts); + LA_PRINT_STRING (stream, builtin_type (exp->gdbarch)->builtin_char, + tempstr, nargs - 1, 0, &opts); (*pos) = pc; } else diff --git a/gdb/expression.h b/gdb/expression.h index 12163e3..789cb89 100644 --- a/gdb/expression.h +++ b/gdb/expression.h @@ -88,6 +88,16 @@ enum exp_opcode when X is a pointer instead of an aggregate. */ STRUCTOP_MPTR, + /* TYPE_INSTANCE is used when the user specifies a specific + type instantiation for overloaded methods/functions. The format + is: TYPE_INSTANCE num_types type0 ... typeN num_types TYPE_INSTANCE*/ + TYPE_INSTANCE, + + /* TYPE_INSTANCE_LOOKUP is used when the user specifies a specific + type instantiation of a function (not a method). In this case, + we must toss the results of the parser and manually do the lookup. */ + TYPE_INSTANCE_LOOKUP, + /* end of C++. */ /* For Modula-2 integer division DIV */ @@ -426,6 +436,8 @@ enum noside extern struct value *evaluate_subexp_standard (struct type *, struct expression *, int *, enum noside); +extern int compare_parameters (struct type *, struct type *); + /* From expprint.c */ extern void print_expression (struct expression *, struct ui_file *); @@ -435,4 +447,5 @@ extern char *op_string (enum exp_opcode); extern void dump_raw_expression (struct expression *, struct ui_file *, char *); extern void dump_prefix_expression (struct expression *, struct ui_file *); + #endif /* !defined (EXPRESSION_H) */ diff --git a/gdb/f-exp.y b/gdb/f-exp.y index d91c413..c984e85 100644 --- a/gdb/f-exp.y +++ b/gdb/f-exp.y @@ -198,6 +198,7 @@ static int parse_number (char *, int, int, YYSTYPE *); /* Special type cases, put in to allow the parser to distinguish different legal basetypes. */ %token INT_KEYWORD INT_S2_KEYWORD LOGICAL_S1_KEYWORD LOGICAL_S2_KEYWORD +%token LOGICAL_S8_KEYWORD %token LOGICAL_KEYWORD REAL_KEYWORD REAL_S8_KEYWORD REAL_S16_KEYWORD %token COMPLEX_S8_KEYWORD COMPLEX_S16_KEYWORD COMPLEX_S32_KEYWORD %token BOOL_AND BOOL_OR BOOL_NOT @@ -608,6 +609,8 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */ { $$ = parse_f_type->builtin_integer_s2; } | CHARACTER { $$ = parse_f_type->builtin_character; } + | LOGICAL_S8_KEYWORD + { $$ = parse_f_type->builtin_logical_s8;} | LOGICAL_KEYWORD { $$ = parse_f_type->builtin_logical; } | LOGICAL_S2_KEYWORD @@ -860,6 +863,7 @@ static const struct token f77_keywords[] = { "integer_2", INT_S2_KEYWORD, BINOP_END }, { "logical_1", LOGICAL_S1_KEYWORD, BINOP_END }, { "logical_2", LOGICAL_S2_KEYWORD, BINOP_END }, + { "logical_8", LOGICAL_S8_KEYWORD, BINOP_END }, { "complex_8", COMPLEX_S8_KEYWORD, BINOP_END }, { "integer", INT_KEYWORD, BINOP_END }, { "logical", LOGICAL_KEYWORD, BINOP_END }, diff --git a/gdb/f-lang.c b/gdb/f-lang.c index 6359841..1754c44 100644 --- a/gdb/f-lang.c +++ b/gdb/f-lang.c @@ -55,23 +55,10 @@ typedef struct saved_bf_symnum SAVED_BF, *SAVED_BF_PTR; /* Local functions */ extern void _initialize_f_language (void); -#if 0 -static void clear_function_list (void); -static long get_bf_for_fcn (long); -static void clear_bf_list (void); -static void patch_all_commons_by_name (char *, CORE_ADDR, int); -static SAVED_F77_COMMON_PTR find_first_common_named (char *); -static void add_common_entry (struct symbol *); -static void add_common_block (char *, CORE_ADDR, int, char *); -static SAVED_FUNCTION *allocate_saved_function_node (void); -static SAVED_BF_PTR allocate_saved_bf_node (void); -static COMMON_ENTRY_PTR allocate_common_entry_node (void); -static SAVED_F77_COMMON_PTR allocate_saved_f77_common_node (void); -static void patch_common_entries (SAVED_F77_COMMON_PTR, CORE_ADDR, int); -#endif - -static void f_printchar (int c, struct ui_file * stream); -static void f_emit_char (int c, struct ui_file * stream, int quoter); + +static void f_printchar (int c, struct type *type, struct ui_file * stream); +static void f_emit_char (int c, struct type *type, + struct ui_file * stream, int quoter); /* Print the character C on STREAM as part of the contents of a literal string whose delimiter is QUOTER. Note that that format for printing @@ -80,7 +67,7 @@ static void f_emit_char (int c, struct ui_file * stream, int quoter); be replaced with a true F77 version. */ static void -f_emit_char (int c, struct ui_file *stream, int quoter) +f_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) { c &= 0xFF; /* Avoid sign bit follies */ @@ -126,10 +113,10 @@ f_emit_char (int c, struct ui_file *stream, int quoter) be replaced with a true F77version. */ static void -f_printchar (int c, struct ui_file *stream) +f_printchar (int c, struct type *type, struct ui_file *stream) { fputs_filtered ("'", stream); - LA_EMIT_CHAR (c, stream, '\''); + LA_EMIT_CHAR (c, type, stream, '\''); fputs_filtered ("'", stream); } @@ -141,14 +128,15 @@ f_printchar (int c, struct ui_file *stream) be replaced with a true F77 version. */ static void -f_printstr (struct ui_file *stream, const gdb_byte *string, - unsigned int length, int width, int force_ellipses, +f_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string, + unsigned int length, int force_ellipses, const struct value_print_options *options) { unsigned int i; unsigned int things_printed = 0; int in_quotes = 0; int need_comma = 0; + int width = TYPE_LENGTH (type); if (length == 0) { @@ -190,7 +178,7 @@ f_printstr (struct ui_file *stream, const gdb_byte *string, fputs_filtered ("', ", stream); in_quotes = 0; } - f_printchar (string[i], stream); + f_printchar (string[i], type, stream); fprintf_filtered (stream, " ", reps); i = rep1 - 1; things_printed += options->repeat_count_threshold; @@ -206,7 +194,7 @@ f_printstr (struct ui_file *stream, const gdb_byte *string, fputs_filtered ("'", stream); in_quotes = 1; } - LA_EMIT_CHAR (string[i], stream, '"'); + LA_EMIT_CHAR (string[i], type, stream, '"'); ++things_printed; } } @@ -257,6 +245,7 @@ enum f_primitive_types { f_primitive_type_logical, f_primitive_type_logical_s1, f_primitive_type_logical_s2, + f_primitive_type_logical_s8, f_primitive_type_integer, f_primitive_type_integer_s2, f_primitive_type_real, @@ -287,6 +276,8 @@ f_language_arch_info (struct gdbarch *gdbarch, = builtin->builtin_logical_s1; lai->primitive_type_vector [f_primitive_type_logical_s2] = builtin->builtin_logical_s2; + lai->primitive_type_vector [f_primitive_type_logical_s8] + = builtin->builtin_logical_s8; lai->primitive_type_vector [f_primitive_type_real] = builtin->builtin_real; lai->primitive_type_vector [f_primitive_type_real_s8] @@ -378,6 +369,11 @@ build_fortran_types (struct gdbarch *gdbarch) gdbarch_short_bit (gdbarch) / TARGET_CHAR_BIT, TYPE_FLAG_UNSIGNED, "logical*2", (struct objfile *) NULL); + builtin_f_type->builtin_logical_s8 = + init_type (TYPE_CODE_BOOL, + gdbarch_long_long_bit (gdbarch) / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "logical*8", (struct objfile *) NULL); + builtin_f_type->builtin_integer = init_type (TYPE_CODE_INT, gdbarch_int_bit (gdbarch) / TARGET_CHAR_BIT, @@ -451,395 +447,3 @@ _initialize_f_language (void) add_language (&f_language_defn); } - -#if 0 -static SAVED_BF_PTR -allocate_saved_bf_node (void) -{ - SAVED_BF_PTR new; - - new = (SAVED_BF_PTR) xmalloc (sizeof (SAVED_BF)); - return (new); -} - -static SAVED_FUNCTION * -allocate_saved_function_node (void) -{ - SAVED_FUNCTION *new; - - new = (SAVED_FUNCTION *) xmalloc (sizeof (SAVED_FUNCTION)); - return (new); -} - -static SAVED_F77_COMMON_PTR -allocate_saved_f77_common_node (void) -{ - SAVED_F77_COMMON_PTR new; - - new = (SAVED_F77_COMMON_PTR) xmalloc (sizeof (SAVED_F77_COMMON)); - return (new); -} - -static COMMON_ENTRY_PTR -allocate_common_entry_node (void) -{ - COMMON_ENTRY_PTR new; - - new = (COMMON_ENTRY_PTR) xmalloc (sizeof (COMMON_ENTRY)); - return (new); -} -#endif - -SAVED_F77_COMMON_PTR head_common_list = NULL; /* Ptr to 1st saved COMMON */ -SAVED_F77_COMMON_PTR tail_common_list = NULL; /* Ptr to last saved COMMON */ -SAVED_F77_COMMON_PTR current_common = NULL; /* Ptr to current COMMON */ - -#if 0 -static SAVED_BF_PTR saved_bf_list = NULL; /* Ptr to (.bf,function) - list */ -static SAVED_BF_PTR saved_bf_list_end = NULL; /* Ptr to above list's end */ -static SAVED_BF_PTR current_head_bf_list = NULL; /* Current head of above list - */ - -static SAVED_BF_PTR tmp_bf_ptr; /* Generic temporary for use - in macros */ - -/* The following function simply enters a given common block onto - the global common block chain */ - -static void -add_common_block (char *name, CORE_ADDR offset, int secnum, char *func_stab) -{ - SAVED_F77_COMMON_PTR tmp; - char *c, *local_copy_func_stab; - - /* If the COMMON block we are trying to add has a blank - name (i.e. "#BLNK_COM") then we set it to __BLANK - because the darn "#" character makes GDB's input - parser have fits. */ - - - if (strcmp (name, BLANK_COMMON_NAME_ORIGINAL) == 0 - || strcmp (name, BLANK_COMMON_NAME_MF77) == 0) - { - - xfree (name); - name = alloca (strlen (BLANK_COMMON_NAME_LOCAL) + 1); - strcpy (name, BLANK_COMMON_NAME_LOCAL); - } - - tmp = allocate_saved_f77_common_node (); - - local_copy_func_stab = xmalloc (strlen (func_stab) + 1); - strcpy (local_copy_func_stab, func_stab); - - tmp->name = xmalloc (strlen (name) + 1); - - /* local_copy_func_stab is a stabstring, let us first extract the - function name from the stab by NULLing out the ':' character. */ - - - c = NULL; - c = strchr (local_copy_func_stab, ':'); - - if (c) - *c = '\0'; - else - error (_("Malformed function STAB found in add_common_block()")); - - - tmp->owning_function = xmalloc (strlen (local_copy_func_stab) + 1); - - strcpy (tmp->owning_function, local_copy_func_stab); - - strcpy (tmp->name, name); - tmp->offset = offset; - tmp->next = NULL; - tmp->entries = NULL; - tmp->secnum = secnum; - - current_common = tmp; - - if (head_common_list == NULL) - { - head_common_list = tail_common_list = tmp; - } - else - { - tail_common_list->next = tmp; - tail_common_list = tmp; - } -} -#endif - -/* The following function simply enters a given common entry onto - the "current_common" block that has been saved away. */ - -#if 0 -static void -add_common_entry (struct symbol *entry_sym_ptr) -{ - COMMON_ENTRY_PTR tmp; - - - - /* The order of this list is important, since - we expect the entries to appear in decl. - order when we later issue "info common" calls */ - - tmp = allocate_common_entry_node (); - - tmp->next = NULL; - tmp->symbol = entry_sym_ptr; - - if (current_common == NULL) - error (_("Attempt to add COMMON entry with no block open!")); - else - { - if (current_common->entries == NULL) - { - current_common->entries = tmp; - current_common->end_of_entries = tmp; - } - else - { - current_common->end_of_entries->next = tmp; - current_common->end_of_entries = tmp; - } - } -} -#endif - -/* This routine finds the first encountred COMMON block named "name" */ - -#if 0 -static SAVED_F77_COMMON_PTR -find_first_common_named (char *name) -{ - - SAVED_F77_COMMON_PTR tmp; - - tmp = head_common_list; - - while (tmp != NULL) - { - if (strcmp (tmp->name, name) == 0) - return (tmp); - else - tmp = tmp->next; - } - return (NULL); -} -#endif - -/* This routine finds the first encountred COMMON block named "name" - that belongs to function funcname */ - -SAVED_F77_COMMON_PTR -find_common_for_function (char *name, char *funcname) -{ - - SAVED_F77_COMMON_PTR tmp; - - tmp = head_common_list; - - while (tmp != NULL) - { - if (strcmp (tmp->name, name) == 0 - && strcmp (tmp->owning_function, funcname) == 0) - return (tmp); - else - tmp = tmp->next; - } - return (NULL); -} - - -#if 0 - -/* The following function is called to patch up the offsets - for the statics contained in the COMMON block named - "name." */ - -static void -patch_common_entries (SAVED_F77_COMMON_PTR blk, CORE_ADDR offset, int secnum) -{ - COMMON_ENTRY_PTR entry; - - blk->offset = offset; /* Keep this around for future use. */ - - entry = blk->entries; - - while (entry != NULL) - { - SYMBOL_VALUE (entry->symbol) += offset; - SYMBOL_SECTION (entry->symbol) = secnum; - - entry = entry->next; - } - blk->secnum = secnum; -} - -/* Patch all commons named "name" that need patching.Since COMMON - blocks occur with relative infrequency, we simply do a linear scan on - the name. Eventually, the best way to do this will be a - hashed-lookup. Secnum is the section number for the .bss section - (which is where common data lives). */ - -static void -patch_all_commons_by_name (char *name, CORE_ADDR offset, int secnum) -{ - - SAVED_F77_COMMON_PTR tmp; - - /* For blank common blocks, change the canonical reprsentation - of a blank name */ - - if (strcmp (name, BLANK_COMMON_NAME_ORIGINAL) == 0 - || strcmp (name, BLANK_COMMON_NAME_MF77) == 0) - { - xfree (name); - name = alloca (strlen (BLANK_COMMON_NAME_LOCAL) + 1); - strcpy (name, BLANK_COMMON_NAME_LOCAL); - } - - tmp = head_common_list; - - while (tmp != NULL) - { - if (COMMON_NEEDS_PATCHING (tmp)) - if (strcmp (tmp->name, name) == 0) - patch_common_entries (tmp, offset, secnum); - - tmp = tmp->next; - } -} -#endif - -/* This macro adds the symbol-number for the start of the function - (the symbol number of the .bf) referenced by symnum_fcn to a - list. This list, in reality should be a FIFO queue but since - #line pragmas sometimes cause line ranges to get messed up - we simply create a linear list. This list can then be searched - first by a queueing algorithm and upon failure fall back to - a linear scan. */ - -#if 0 -#define ADD_BF_SYMNUM(bf_sym,fcn_sym) \ - \ - if (saved_bf_list == NULL) \ -{ \ - tmp_bf_ptr = allocate_saved_bf_node(); \ - \ - tmp_bf_ptr->symnum_bf = (bf_sym); \ - tmp_bf_ptr->symnum_fcn = (fcn_sym); \ - tmp_bf_ptr->next = NULL; \ - \ - current_head_bf_list = saved_bf_list = tmp_bf_ptr; \ - saved_bf_list_end = tmp_bf_ptr; \ - } \ -else \ -{ \ - tmp_bf_ptr = allocate_saved_bf_node(); \ - \ - tmp_bf_ptr->symnum_bf = (bf_sym); \ - tmp_bf_ptr->symnum_fcn = (fcn_sym); \ - tmp_bf_ptr->next = NULL; \ - \ - saved_bf_list_end->next = tmp_bf_ptr; \ - saved_bf_list_end = tmp_bf_ptr; \ - } -#endif - -/* This function frees the entire (.bf,function) list */ - -#if 0 -static void -clear_bf_list (void) -{ - - SAVED_BF_PTR tmp = saved_bf_list; - SAVED_BF_PTR next = NULL; - - while (tmp != NULL) - { - next = tmp->next; - xfree (tmp); - tmp = next; - } - saved_bf_list = NULL; -} -#endif - -int global_remote_debug; - -#if 0 - -static long -get_bf_for_fcn (long the_function) -{ - SAVED_BF_PTR tmp; - int nprobes = 0; - - /* First use a simple queuing algorithm (i.e. look and see if the - item at the head of the queue is the one you want) */ - - if (saved_bf_list == NULL) - internal_error (__FILE__, __LINE__, - _("cannot get .bf node off empty list")); - - if (current_head_bf_list != NULL) - if (current_head_bf_list->symnum_fcn == the_function) - { - if (global_remote_debug) - fprintf_unfiltered (gdb_stderr, "*"); - - tmp = current_head_bf_list; - current_head_bf_list = current_head_bf_list->next; - return (tmp->symnum_bf); - } - - /* If the above did not work (probably because #line directives were - used in the sourcefile and they messed up our internal tables) we now do - the ugly linear scan */ - - if (global_remote_debug) - fprintf_unfiltered (gdb_stderr, "\ndefaulting to linear scan\n"); - - nprobes = 0; - tmp = saved_bf_list; - while (tmp != NULL) - { - nprobes++; - if (tmp->symnum_fcn == the_function) - { - if (global_remote_debug) - fprintf_unfiltered (gdb_stderr, "Found in %d probes\n", nprobes); - current_head_bf_list = tmp->next; - return (tmp->symnum_bf); - } - tmp = tmp->next; - } - - return (-1); -} - -static SAVED_FUNCTION_PTR saved_function_list = NULL; -static SAVED_FUNCTION_PTR saved_function_list_end = NULL; - -static void -clear_function_list (void) -{ - SAVED_FUNCTION_PTR tmp = saved_function_list; - SAVED_FUNCTION_PTR next = NULL; - - while (tmp != NULL) - { - next = tmp->next; - xfree (tmp); - tmp = next; - } - - saved_function_list = NULL; -} -#endif diff --git a/gdb/f-lang.h b/gdb/f-lang.h index 711bdba..cd2f804 100644 --- a/gdb/f-lang.h +++ b/gdb/f-lang.h @@ -28,6 +28,10 @@ extern void f_error (char *); /* Defined in f-exp.y */ extern void f_print_type (struct type *, char *, struct ui_file *, int, int); +extern const char *f_object_address_data_valid_print_to_stream + (struct type *type, struct ui_file *stream); +extern void f_object_address_data_valid_or_error (struct type *type); + extern int f_val_print (struct type *, const gdb_byte *, int, CORE_ADDR, struct ui_file *, int, const struct value_print_options *); @@ -47,41 +51,8 @@ enum f90_range_type NONE_BOUND_DEFAULT /* "(low:high)" */ }; -struct common_entry - { - struct symbol *symbol; /* The symbol node corresponding - to this component */ - struct common_entry *next; /* The next component */ - }; - -struct saved_f77_common - { - char *name; /* Name of COMMON */ - char *owning_function; /* Name of parent function */ - int secnum; /* Section # of .bss */ - CORE_ADDR offset; /* Offset from .bss for - this block */ - struct common_entry *entries; /* List of block's components */ - struct common_entry *end_of_entries; /* ptr. to end of components */ - struct saved_f77_common *next; /* Next saved COMMON block */ - }; - -typedef struct saved_f77_common SAVED_F77_COMMON, *SAVED_F77_COMMON_PTR; - -typedef struct common_entry COMMON_ENTRY, *COMMON_ENTRY_PTR; - -extern SAVED_F77_COMMON_PTR head_common_list; /* Ptr to 1st saved COMMON */ -extern SAVED_F77_COMMON_PTR tail_common_list; /* Ptr to last saved COMMON */ -extern SAVED_F77_COMMON_PTR current_common; /* Ptr to current COMMON */ - -extern SAVED_F77_COMMON_PTR find_common_for_function (char *, char *); - -#define UNINITIALIZED_SECNUM -1 -#define COMMON_NEEDS_PATCHING(blk) ((blk)->secnum == UNINITIALIZED_SECNUM) - #define BLANK_COMMON_NAME_ORIGINAL "#BLNK_COM" /* XLF assigned */ #define BLANK_COMMON_NAME_MF77 "__BLNK__" /* MF77 assigned */ -#define BLANK_COMMON_NAME_LOCAL "__BLANK" /* Local GDB */ /* When reasonable array bounds cannot be fetched, such as when you ask to 'mt print symbols' and there is no stack frame and @@ -113,6 +84,7 @@ struct builtin_f_type struct type *builtin_logical; struct type *builtin_logical_s1; struct type *builtin_logical_s2; + struct type *builtin_logical_s8; struct type *builtin_real; struct type *builtin_real_s8; struct type *builtin_real_s16; diff --git a/gdb/f-typeprint.c b/gdb/f-typeprint.c index 6c9668f..852b9a8 100644 --- a/gdb/f-typeprint.c +++ b/gdb/f-typeprint.c @@ -31,7 +31,7 @@ #include "gdbcore.h" #include "target.h" #include "f-lang.h" - +#include "dwarf2loc.h" #include "gdb_string.h" #include @@ -48,6 +48,34 @@ void f_type_print_varspec_prefix (struct type *, struct ui_file *, void f_type_print_base (struct type *, struct ui_file *, int, int); +const char * +f_object_address_data_valid_print_to_stream (struct type *type, + struct ui_file *stream) +{ + const char *msg; + + msg = object_address_data_not_valid (type); + if (msg != NULL) + { + /* Assuming the content printed to STREAM should not be localized. */ + fprintf_filtered (stream, "<%s>", msg); + } + + return msg; +} + +void +f_object_address_data_valid_or_error (struct type *type) +{ + const char *msg; + + msg = object_address_data_not_valid (type); + if (msg != NULL) + { + error (_("Cannot access it because the %s."), _(msg)); + } +} + /* LEVEL is the depth to indent lines by. */ void @@ -57,6 +85,9 @@ f_print_type (struct type *type, char *varstring, struct ui_file *stream, enum type_code code; int demangled_args; + if (f_object_address_data_valid_print_to_stream (type, stream) != NULL) + return; + f_type_print_base (type, stream, show, level); code = TYPE_CODE (type); if ((varstring != NULL && *varstring != '\0') @@ -166,6 +197,9 @@ f_type_print_varspec_suffix (struct type *type, struct ui_file *stream, QUIT; + if (TYPE_CODE (type) != TYPE_CODE_TYPEDEF) + CHECK_TYPEDEF (type); + switch (TYPE_CODE (type)) { case TYPE_CODE_ARRAY: diff --git a/gdb/f-valprint.c b/gdb/f-valprint.c index 5721041..2cff7bc 100644 --- a/gdb/f-valprint.c +++ b/gdb/f-valprint.c @@ -34,10 +34,8 @@ #include "gdbcore.h" #include "command.h" #include "block.h" - -#if 0 -static int there_is_a_visible_common_named (char *); -#endif +#include "dictionary.h" +#include "gdb_assert.h" extern void _initialize_f_valprint (void); static void info_common_command (char *, int); @@ -54,15 +52,17 @@ int f77_array_offset_tbl[MAX_FORTRAN_DIMS + 1][2]; /* The following macro gives us the size of the nth dimension, Where n is 1 based. */ -#define F77_DIM_SIZE(n) (f77_array_offset_tbl[n][1]) +#define F77_DIM_COUNT(n) (f77_array_offset_tbl[n][1]) -/* The following gives us the offset for row n where n is 1-based. */ +/* The following gives us the element size for row n where n is 1-based. */ -#define F77_DIM_OFFSET(n) (f77_array_offset_tbl[n][0]) +#define F77_DIM_BYTE_STRIDE(n) (f77_array_offset_tbl[n][0]) int f77_get_lowerbound (struct type *type) { + f_object_address_data_valid_or_error (type); + if (TYPE_ARRAY_LOWER_BOUND_IS_UNDEFINED (type)) error (_("Lower bound may not be '*' in F77")); @@ -72,14 +72,17 @@ f77_get_lowerbound (struct type *type) int f77_get_upperbound (struct type *type) { + f_object_address_data_valid_or_error (type); + if (TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type)) { - /* We have an assumed size array on our hands. Assume that - upper_bound == lower_bound so that we show at least 1 element. - If the user wants to see more elements, let him manually ask for 'em - and we'll subscript the array and show him. */ + /* We have an assumed size array on our hands. As type_length_get + already assumes a length zero of arrays with underfined bounds VALADDR + passed to the Fortran functions does not contained the real inferior + memory content. User should request printing of specific array + elements instead. */ - return f77_get_lowerbound (type); + return f77_get_lowerbound (type) - 1; } return TYPE_ARRAY_UPPER_BOUND_VALUE (type); @@ -135,24 +138,29 @@ f77_create_arrayprint_offset_tbl (struct type *type, struct ui_file *stream) upper = f77_get_upperbound (tmp_type); lower = f77_get_lowerbound (tmp_type); - F77_DIM_SIZE (ndimen) = upper - lower + 1; + F77_DIM_COUNT (ndimen) = upper - lower + 1; + + F77_DIM_BYTE_STRIDE (ndimen) = + TYPE_ARRAY_BYTE_STRIDE_VALUE (tmp_type); tmp_type = TYPE_TARGET_TYPE (tmp_type); ndimen++; } - /* Now we multiply eltlen by all the offsets, so that later we + /* Now we multiply eltlen by all the BYTE_STRIDEs, so that later we can print out array elements correctly. Up till now we - know an offset to apply to get the item but we also + know an eltlen to apply to get the item but we also have to know how much to add to get to the next item */ ndimen--; eltlen = TYPE_LENGTH (tmp_type); - F77_DIM_OFFSET (ndimen) = eltlen; + if (F77_DIM_BYTE_STRIDE (ndimen) == 0) + F77_DIM_BYTE_STRIDE (ndimen) = eltlen; while (--ndimen > 0) { - eltlen *= F77_DIM_SIZE (ndimen + 1); - F77_DIM_OFFSET (ndimen) = eltlen; + eltlen *= F77_DIM_COUNT (ndimen + 1); + if (F77_DIM_BYTE_STRIDE (ndimen) == 0) + F77_DIM_BYTE_STRIDE (ndimen) = eltlen; } } @@ -172,34 +180,34 @@ f77_print_array_1 (int nss, int ndimensions, struct type *type, if (nss != ndimensions) { - for (i = 0; (i < F77_DIM_SIZE (nss) && (*elts) < options->print_max); i++) + for (i = 0; (i < F77_DIM_COUNT (nss) && (*elts) < options->print_max); i++) { fprintf_filtered (stream, "( "); f77_print_array_1 (nss + 1, ndimensions, TYPE_TARGET_TYPE (type), - valaddr + i * F77_DIM_OFFSET (nss), - address + i * F77_DIM_OFFSET (nss), + valaddr + i * F77_DIM_BYTE_STRIDE (nss), + address + i * F77_DIM_BYTE_STRIDE (nss), stream, recurse, options, elts); fprintf_filtered (stream, ") "); } - if (*elts >= options->print_max && i < F77_DIM_SIZE (nss)) + if (*elts >= options->print_max && i < F77_DIM_COUNT (nss)) fprintf_filtered (stream, "..."); } else { - for (i = 0; i < F77_DIM_SIZE (nss) && (*elts) < options->print_max; + for (i = 0; i < F77_DIM_COUNT (nss) && (*elts) < options->print_max; i++, (*elts)++) { val_print (TYPE_TARGET_TYPE (type), - valaddr + i * F77_DIM_OFFSET (ndimensions), + valaddr + i * F77_DIM_BYTE_STRIDE (ndimensions), 0, - address + i * F77_DIM_OFFSET (ndimensions), + address + i * F77_DIM_BYTE_STRIDE (ndimensions), stream, recurse, options, current_language); - if (i != (F77_DIM_SIZE (nss) - 1)) + if (i != (F77_DIM_COUNT (nss) - 1)) fprintf_filtered (stream, ", "); if ((*elts == options->print_max - 1) - && (i != (F77_DIM_SIZE (nss) - 1))) + && (i != (F77_DIM_COUNT (nss) - 1))) fprintf_filtered (stream, "..."); } } @@ -251,12 +259,16 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, CORE_ADDR addr; int index; + if (f_object_address_data_valid_print_to_stream (type, stream) != NULL) + return 0; + CHECK_TYPEDEF (type); switch (TYPE_CODE (type)) { case TYPE_CODE_STRING: f77_get_dynamic_length_of_aggregate (type); - LA_PRINT_STRING (stream, valaddr, TYPE_LENGTH (type), 1, 0, options); + LA_PRINT_STRING (stream, builtin_type (current_gdbarch)->builtin_char, + valaddr, TYPE_LENGTH (type), 0, options); break; case TYPE_CODE_ARRAY: @@ -293,7 +305,7 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, && TYPE_CODE (elttype) == TYPE_CODE_INT && (options->format == 0 || options->format == 's') && addr != 0) - i = val_print_string (addr, -1, TYPE_LENGTH (elttype), stream, + i = val_print_string (TYPE_TARGET_TYPE (type), addr, -1, stream, options); /* Return number of characters printed, including the terminating @@ -365,7 +377,7 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, { fputs_filtered (" ", stream); LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr), - stream); + type, stream); } } break; @@ -464,22 +476,54 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, return 0; } -static void -list_all_visible_commons (char *funname) +static int +info_common_command_for_block (struct block *block, struct frame_info *frame, + const char *comname) { - SAVED_F77_COMMON_PTR tmp; - - tmp = head_common_list; - - printf_filtered (_("All COMMON blocks visible at this level:\n\n")); - - while (tmp != NULL) - { - if (strcmp (tmp->owning_function, funname) == 0) - printf_filtered ("%s\n", tmp->name); - - tmp = tmp->next; - } + struct dict_iterator iter; + struct symbol *sym; + int values_printed = 0; + const char *name; + struct value_print_options opts; + + get_user_print_options (&opts); + + ALL_BLOCK_SYMBOLS (block, iter, sym) + if (SYMBOL_DOMAIN (sym) == COMMON_BLOCK_DOMAIN) + { + struct type *type = SYMBOL_TYPE (sym); + int index; + + gdb_assert (SYMBOL_CLASS (sym) == LOC_STATIC); + gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT); + + if (comname && (!SYMBOL_LINKAGE_NAME (sym) + || strcmp (comname, SYMBOL_LINKAGE_NAME (sym)) != 0)) + continue; + + values_printed = 1; + if (SYMBOL_PRINT_NAME (sym)) + printf_filtered (_("Contents of F77 COMMON block '%s':\n"), + SYMBOL_PRINT_NAME (sym)); + else + printf_filtered (_("Contents of blank COMMON block:\n")); + + for (index = 0; index < TYPE_NFIELDS (type); index++) + { + struct value *val; + + gdb_assert (field_is_static (&TYPE_FIELD (type, index))); + val = value_static_field (type, index); + + printf_filtered ("%s = ", TYPE_FIELD_NAME (type, index)); + value_print (val, gdb_stdout, &opts); + putchar_filtered ('\n'); + } + + putchar_filtered ('\n'); + } + + return values_printed; } /* This function is used to print out the values in a given COMMON @@ -489,11 +533,9 @@ list_all_visible_commons (char *funname) static void info_common_command (char *comname, int from_tty) { - SAVED_F77_COMMON_PTR the_common; - COMMON_ENTRY_PTR entry; struct frame_info *fi; - char *funname = 0; - struct symbol *func; + struct block *block; + int values_printed = 0; /* We have been told to display the contents of F77 COMMON block supposedly visible in this function. Let us @@ -505,136 +547,32 @@ info_common_command (char *comname, int from_tty) /* The following is generally ripped off from stack.c's routine print_frame_info() */ - func = find_pc_function (get_frame_pc (fi)); - if (func) - { - /* In certain pathological cases, the symtabs give the wrong - function (when we are in the first function in a file which - is compiled without debugging symbols, the previous function - is compiled with debugging symbols, and the "foo.o" symbol - that is supposed to tell us where the file with debugging symbols - ends has been truncated by ar because it is longer than 15 - characters). - - So look in the minimal symbol tables as well, and if it comes - up with a larger address for the function use that instead. - I don't think this can ever cause any problems; there shouldn't - be any minimal symbols in the middle of a function. - FIXME: (Not necessarily true. What about text labels) */ - - struct minimal_symbol *msymbol = - lookup_minimal_symbol_by_pc (get_frame_pc (fi)); - - if (msymbol != NULL - && (SYMBOL_VALUE_ADDRESS (msymbol) - > BLOCK_START (SYMBOL_BLOCK_VALUE (func)))) - funname = SYMBOL_LINKAGE_NAME (msymbol); - else - funname = SYMBOL_LINKAGE_NAME (func); - } - else - { - struct minimal_symbol *msymbol = - lookup_minimal_symbol_by_pc (get_frame_pc (fi)); - - if (msymbol != NULL) - funname = SYMBOL_LINKAGE_NAME (msymbol); - else /* Got no 'funname', code below will fail. */ - error (_("No function found for frame.")); - } - - /* If comname is NULL, we assume the user wishes to see the - which COMMON blocks are visible here and then return */ - - if (comname == 0) + block = get_frame_block (fi, 0); + if (block == NULL) { - list_all_visible_commons (funname); + printf_filtered (_("No symbol table info available.\n")); return; } - the_common = find_common_for_function (comname, funname); - - if (the_common) + while (block) { - if (strcmp (comname, BLANK_COMMON_NAME_LOCAL) == 0) - printf_filtered (_("Contents of blank COMMON block:\n")); - else - printf_filtered (_("Contents of F77 COMMON block '%s':\n"), comname); - - printf_filtered ("\n"); - entry = the_common->entries; - - while (entry != NULL) - { - print_variable_and_value (NULL, entry->symbol, fi, gdb_stdout, 0); - entry = entry->next; - } + if (info_common_command_for_block (block, fi, comname)) + values_printed = 1; + /* After handling the function's top-level block, stop. Don't + continue to its superblock, the block of per-file symbols. */ + if (BLOCK_FUNCTION (block)) + break; + block = BLOCK_SUPERBLOCK (block); } - else - printf_filtered (_("Cannot locate the common block %s in function '%s'\n"), - comname, funname); -} - -/* This function is used to determine whether there is a - F77 common block visible at the current scope called 'comname'. */ - -#if 0 -static int -there_is_a_visible_common_named (char *comname) -{ - SAVED_F77_COMMON_PTR the_common; - struct frame_info *fi; - char *funname = 0; - struct symbol *func; - - if (comname == NULL) - error (_("Cannot deal with NULL common name!")); - fi = get_selected_frame (_("No frame selected")); - - /* The following is generally ripped off from stack.c's routine - print_frame_info() */ - - func = find_pc_function (fi->pc); - if (func) + if (!values_printed) { - /* In certain pathological cases, the symtabs give the wrong - function (when we are in the first function in a file which - is compiled without debugging symbols, the previous function - is compiled with debugging symbols, and the "foo.o" symbol - that is supposed to tell us where the file with debugging symbols - ends has been truncated by ar because it is longer than 15 - characters). - - So look in the minimal symbol tables as well, and if it comes - up with a larger address for the function use that instead. - I don't think this can ever cause any problems; there shouldn't - be any minimal symbols in the middle of a function. - FIXME: (Not necessarily true. What about text labels) */ - - struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc); - - if (msymbol != NULL - && (SYMBOL_VALUE_ADDRESS (msymbol) - > BLOCK_START (SYMBOL_BLOCK_VALUE (func)))) - funname = SYMBOL_LINKAGE_NAME (msymbol); + if (comname) + printf_filtered (_("No common block '%s'.\n"), comname); else - funname = SYMBOL_LINKAGE_NAME (func); + printf_filtered (_("No common blocks.\n")); } - else - { - struct minimal_symbol *msymbol = - lookup_minimal_symbol_by_pc (fi->pc); - - if (msymbol != NULL) - funname = SYMBOL_LINKAGE_NAME (msymbol); - } - - the_common = find_common_for_function (comname, funname); - - return (the_common ? 1 : 0); } -#endif void _initialize_f_valprint (void) diff --git a/gdb/findcmd.c b/gdb/findcmd.c index 7ae43e5..2894948 100644 --- a/gdb/findcmd.c +++ b/gdb/findcmd.c @@ -26,7 +26,7 @@ /* Copied from bfd_put_bits. */ -static void +void put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p) { int i; @@ -44,6 +44,41 @@ put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p) } } +/* Allocates a buffer in *PATTERN_BUF, with a hard-coded initial size which + will be returned in *PATTERN_BUF_SIZE. *PATTERN_BUF_END points to the same + place as *PATTERN_BUF, indicating that the buffer is initially empty. */ + +void +allocate_pattern_buffer (char **pattern_buf, char **pattern_buf_end, + ULONGEST *pattern_buf_size) +{ +#define INITIAL_PATTERN_BUF_SIZE 100 + *pattern_buf_size = INITIAL_PATTERN_BUF_SIZE; + *pattern_buf = xmalloc (*pattern_buf_size); + *pattern_buf_end = *pattern_buf; +} + +/* Grows *PATTERN_BUF by a factor of two if it's not large enough to hold + VAL_BYTES more bytes or a 64-bit value, whichever is larger. + *PATTERN_BUF_END is updated as necessary. */ + +void +increase_pattern_buffer (char **pattern_buf, char **pattern_buf_end, + ULONGEST *pattern_buf_size, int val_bytes) +{ + /* Keep it simple and assume size == 'g' when watching for when we + need to grow the pattern buf. */ + if ((*pattern_buf_end - *pattern_buf + max (val_bytes, sizeof (int64_t))) + > *pattern_buf_size) + { + size_t current_offset = *pattern_buf_end - *pattern_buf; + + *pattern_buf_size *= 2; + *pattern_buf = xrealloc (*pattern_buf, *pattern_buf_size); + *pattern_buf_end = *pattern_buf + current_offset; + } +} + /* Subroutine of find_command to simplify it. Parse the arguments of the "find" command. */ @@ -59,8 +94,7 @@ parse_find_args (char *args, ULONGEST *max_countp, char *pattern_buf; /* Current size of search pattern buffer. We realloc space as needed. */ -#define INITIAL_PATTERN_BUF_SIZE 100 - ULONGEST pattern_buf_size = INITIAL_PATTERN_BUF_SIZE; + ULONGEST pattern_buf_size; /* Pointer to one past the last in-use part of pattern_buf. */ char *pattern_buf_end; ULONGEST pattern_len; @@ -74,8 +108,7 @@ parse_find_args (char *args, ULONGEST *max_countp, if (args == NULL) error (_("Missing search parameters.")); - pattern_buf = xmalloc (pattern_buf_size); - pattern_buf_end = pattern_buf; + allocate_pattern_buffer (&pattern_buf, &pattern_buf_end, &pattern_buf_size); old_cleanups = make_cleanup (free_current_contents, &pattern_buf); /* Get search granularity and/or max count if specified. @@ -172,16 +205,8 @@ parse_find_args (char *args, ULONGEST *max_countp, v = parse_to_comma_and_eval (&s); val_bytes = TYPE_LENGTH (value_type (v)); - /* Keep it simple and assume size == 'g' when watching for when we - need to grow the pattern buf. */ - if ((pattern_buf_end - pattern_buf + max (val_bytes, sizeof (int64_t))) - > pattern_buf_size) - { - size_t current_offset = pattern_buf_end - pattern_buf; - pattern_buf_size *= 2; - pattern_buf = xrealloc (pattern_buf, pattern_buf_size); - pattern_buf_end = pattern_buf + current_offset; - } + increase_pattern_buffer (&pattern_buf, &pattern_buf_end, + &pattern_buf_size, val_bytes); if (size != '\0') { @@ -236,6 +261,45 @@ parse_find_args (char *args, ULONGEST *max_countp, discard_cleanups (old_cleanups); } +/* Drives target_search_memory to sweep through the specified search space, + possibly in several iterations (with one call to this function for each + iteration). *START_ADDR is the address where the search starts, and is + updated to the next starting address to continue the search. + *SEARCH_SPACE_LEN is the amount of bytes which will be searched, and is + updated for the next iteration. PATTERN_BUF holds the pattern to be searched + for, PATTERN_LEN is the size of the pattern in bytes. If a match is found, + it's address is put in *FOUND_ADDR. + + Returns 1 if found, 0 if not found, and -1 if there was an error requiring + halting of the search (e.g. memory read error). */ + +int +search_memory (CORE_ADDR *start_addr, ULONGEST *search_space_len, + const char *pattern_buf, ULONGEST pattern_len, + CORE_ADDR *found_addr) +{ + /* Offset from start of this iteration to the next iteration. */ + ULONGEST next_iter_incr; + int found; + + found = target_search_memory (*start_addr, *search_space_len, + pattern_buf, pattern_len, found_addr); + if (found <= 0) + return found; + + /* Begin next iteration at one byte past this match. */ + next_iter_incr = (*found_addr - *start_addr) + 1; + + /* For robustness, we don't let search_space_len go -ve here. */ + if (*search_space_len >= next_iter_incr) + *search_space_len -= next_iter_incr; + else + *search_space_len = 0; + *start_addr += next_iter_incr; + + return found; +} + static void find_command (char *args, int from_tty) { @@ -264,12 +328,11 @@ find_command (char *args, int from_tty) while (search_space_len >= pattern_len && found_count < max_count) { - /* Offset from start of this iteration to the next iteration. */ - ULONGEST next_iter_incr; CORE_ADDR found_addr; - int found = target_search_memory (start_addr, search_space_len, - pattern_buf, pattern_len, &found_addr); + int found; + found = search_memory (&start_addr, &search_space_len, pattern_buf, + pattern_len, &found_addr); if (found <= 0) break; @@ -277,16 +340,6 @@ find_command (char *args, int from_tty) printf_filtered ("\n"); ++found_count; last_found_addr = found_addr; - - /* Begin next iteration at one byte past this match. */ - next_iter_incr = (found_addr - start_addr) + 1; - - /* For robustness, we don't let search_space_len go -ve here. */ - if (search_space_len >= next_iter_incr) - search_space_len -= next_iter_incr; - else - search_space_len = 0; - start_addr += next_iter_incr; } /* Record and print the results. */ diff --git a/gdb/findvar.c b/gdb/findvar.c index 1048887..b958ec6 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -35,6 +35,7 @@ #include "user-regs.h" #include "block.h" #include "objfiles.h" +#include "dwarf2loc.h" /* Basic byte-swapping routines. GDB has needed these for a long time... All extract a target-format integer at ADDR which is LEN bytes long. */ @@ -275,7 +276,7 @@ value_of_register (int regnum, struct frame_info *frame) memcpy (value_contents_raw (reg_val), raw_buffer, register_size (gdbarch, regnum)); VALUE_LVAL (reg_val) = lval; - VALUE_ADDRESS (reg_val) = addr; + set_value_address (reg_val, addr); VALUE_REGNUM (reg_val) = regnum; set_value_optimized_out (reg_val, optim); VALUE_FRAME_ID (reg_val) = get_frame_id (frame); @@ -382,27 +383,16 @@ symbol_read_needs_frame (struct symbol *sym) /* Given a struct symbol for a variable, and a stack frame id, read the value of the variable and return a (pointer to a) struct value containing the value. - If the variable cannot be found, return a zero pointer. */ + If the variable cannot be found, return a zero pointer. + We have to first find the address of the variable before allocating struct + value to return as its size may depend on DW_OP_PUSH_OBJECT_ADDRESS possibly + used by its type. */ struct value * read_var_value (struct symbol *var, struct frame_info *frame) { - struct value *v; struct type *type = SYMBOL_TYPE (var); CORE_ADDR addr; - int len; - - if (SYMBOL_CLASS (var) == LOC_COMPUTED - || SYMBOL_CLASS (var) == LOC_REGISTER) - /* These cases do not use V. */ - v = NULL; - else - { - v = allocate_value (type); - VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */ - } - - len = TYPE_LENGTH (type); if (symbol_read_needs_frame (var)) gdb_assert (frame); @@ -410,31 +400,39 @@ read_var_value (struct symbol *var, struct frame_info *frame) switch (SYMBOL_CLASS (var)) { case LOC_CONST: - /* Put the constant back in target format. */ - store_signed_integer (value_contents_raw (v), len, - (LONGEST) SYMBOL_VALUE (var)); - VALUE_LVAL (v) = not_lval; - return v; + { + /* Put the constant back in target format. */ + struct value *v = allocate_value (type); + VALUE_LVAL (v) = not_lval; + store_signed_integer (value_contents_raw (v), TYPE_LENGTH (type), + (LONGEST) SYMBOL_VALUE (var)); + return v; + } case LOC_LABEL: - /* Put the constant back in target format. */ - if (overlay_debugging) - { - CORE_ADDR addr - = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var), - SYMBOL_OBJ_SECTION (var)); - store_typed_address (value_contents_raw (v), type, addr); - } - else - store_typed_address (value_contents_raw (v), type, - SYMBOL_VALUE_ADDRESS (var)); - VALUE_LVAL (v) = not_lval; - return v; + { + /* Put the constant back in target format. */ + struct value *v = allocate_value (type); + VALUE_LVAL (v) = not_lval; + if (overlay_debugging) + { + CORE_ADDR addr + = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var), + SYMBOL_OBJ_SECTION (var)); + store_typed_address (value_contents_raw (v), type, addr); + } + else + store_typed_address (value_contents_raw (v), type, + SYMBOL_VALUE_ADDRESS (var)); + return v; + } case LOC_CONST_BYTES: { - memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var), len); + struct value *v = allocate_value (type); VALUE_LVAL (v) = not_lval; + memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var), + TYPE_LENGTH (type)); return v; } @@ -476,12 +474,23 @@ read_var_value (struct symbol *var, struct frame_info *frame) break; case LOC_BLOCK: - if (overlay_debugging) - VALUE_ADDRESS (v) = symbol_overlayed_address - (BLOCK_START (SYMBOL_BLOCK_VALUE (var)), SYMBOL_OBJ_SECTION (var)); - else - VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); - return v; + { + CORE_ADDR addr; + struct value *v; + + if (overlay_debugging) + addr = symbol_overlayed_address + (BLOCK_START (SYMBOL_BLOCK_VALUE (var)), SYMBOL_OBJ_SECTION (var)); + else + addr = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); + /* ADDR is set here for ALLOCATE_VALUE's CHECK_TYPEDEF for + DW_OP_push_object_address. */ + object_address_set (addr); + v = allocate_value (type); + VALUE_ADDRESS (v) = addr; + VALUE_LVAL (v) = lval_memory; + return v; + } case LOC_REGISTER: case LOC_REGPARM_ADDR: @@ -499,7 +508,6 @@ read_var_value (struct symbol *var, struct frame_info *frame) error (_("Value of register variable not available.")); addr = value_as_address (regval); - VALUE_LVAL (v) = lval_memory; } else { @@ -542,18 +550,33 @@ read_var_value (struct symbol *var, struct frame_info *frame) break; case LOC_OPTIMIZED_OUT: - VALUE_LVAL (v) = not_lval; - set_value_optimized_out (v, 1); - return v; + { + struct value *v = allocate_value (type); + + VALUE_LVAL (v) = not_lval; + set_value_optimized_out (v, 1); + return v; + } default: error (_("Cannot look up value of a botched symbol.")); break; } - VALUE_ADDRESS (v) = addr; - set_value_lazy (v, 1); - return v; + { + struct value *v; + + /* ADDR is set here for ALLOCATE_VALUE's CHECK_TYPEDEF for + DW_OP_PUSH_OBJECT_ADDRESS. */ + object_address_set (addr); + v = allocate_value (type); + VALUE_ADDRESS (v) = addr; + VALUE_LVAL (v) = lval_memory; + + set_value_lazy (v, 1); + + return v; + } } /* Install default attributes for register values. */ @@ -590,10 +613,11 @@ struct value * value_from_register (struct type *type, int regnum, struct frame_info *frame) { struct gdbarch *gdbarch = get_frame_arch (frame); - struct type *type1 = check_typedef (type); struct value *v; - if (gdbarch_convert_register_p (gdbarch, regnum, type1)) + type = check_typedef (type); + + if (gdbarch_convert_register_p (gdbarch, regnum, type)) { /* The ISA/ABI need to something weird when obtaining the specified value from this register. It might need to @@ -607,7 +631,7 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame) VALUE_FRAME_ID (v) = get_frame_id (frame); VALUE_REGNUM (v) = regnum; gdbarch_register_to_value (gdbarch, - frame, regnum, type1, value_contents_raw (v)); + frame, regnum, type, value_contents_raw (v)); } else { diff --git a/gdb/frame.c b/gdb/frame.c index dfd6b3d..2ea37c3 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -596,7 +596,7 @@ frame_register_unwind (struct frame_info *frame, int regnum, *optimizedp = value_optimized_out (value); *lvalp = VALUE_LVAL (value); - *addrp = VALUE_ADDRESS (value); + *addrp = value_address (value); *realnump = VALUE_REGNUM (value); if (bufferp) @@ -682,7 +682,7 @@ frame_unwind_register_value (struct frame_info *frame, int regnum) VALUE_REGNUM (value)); else if (VALUE_LVAL (value) == lval_memory) fprintf_unfiltered (gdb_stdlog, " address=0x%s", - paddr_nz (VALUE_ADDRESS (value))); + paddr_nz (value_address (value))); else fprintf_unfiltered (gdb_stdlog, " computed"); diff --git a/gdb/frv-tdep.c b/gdb/frv-tdep.c index ff387db..452f70c 100644 --- a/gdb/frv-tdep.c +++ b/gdb/frv-tdep.c @@ -1230,7 +1230,7 @@ frv_push_dummy_call (struct gdbarch *gdbarch, struct value *function, if (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION) { - store_unsigned_integer (valbuf, 4, VALUE_ADDRESS (arg)); + store_unsigned_integer (valbuf, 4, value_address (arg)); typecode = TYPE_CODE_PTR; len = 4; val = valbuf; diff --git a/gdb/gdb_locale.h b/gdb/gdb_locale.h index e8ba0ea..4fa4d3d 100644 --- a/gdb/gdb_locale.h +++ b/gdb/gdb_locale.h @@ -41,4 +41,8 @@ # define N_(String) (String) #endif +#ifdef HAVE_LANGINFO_CODESET +#include +#endif + #endif /* GDB_LOCALE_H */ diff --git a/gdb/gdb_obstack.h b/gdb/gdb_obstack.h index 48f49cd..cd1a1d7 100644 --- a/gdb/gdb_obstack.h +++ b/gdb/gdb_obstack.h @@ -45,4 +45,7 @@ #define obstack_grow_str0(OBSTACK,STRING) \ obstack_grow0 (OBSTACK, STRING, strlen (STRING)) +#define obstack_grow_wstr(OBSTACK, WSTRING) \ + obstack_grow (OBSTACK, WSTRING, sizeof (wchar_t) * wcslen (WSTRING)) + #endif diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 3273b34..d6c737b 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -243,6 +243,11 @@ struct gdbarch gdbarch_target_signal_to_host_ftype *target_signal_to_host; gdbarch_get_siginfo_type_ftype *get_siginfo_type; gdbarch_record_special_symbol_ftype *record_special_symbol; + gdbarch_get_syscall_number_ftype *get_syscall_number; + gdbarch_get_syscall_by_number_ftype *get_syscall_by_number; + gdbarch_get_syscall_by_name_ftype *get_syscall_by_name; + gdbarch_get_syscall_names_ftype *get_syscall_names; + const char * xml_syscall_filename; int has_global_solist; }; @@ -378,6 +383,11 @@ struct gdbarch startup_gdbarch = default_target_signal_to_host, /* target_signal_to_host */ 0, /* get_siginfo_type */ 0, /* record_special_symbol */ + 0, /* get_syscall_number */ + 0, /* get_syscall_by_number */ + 0, /* get_syscall_by_name */ + 0, /* get_syscall_names */ + 0, /* xml_syscall_filename */ 0, /* has_global_solist */ /* startup_gdbarch() */ }; @@ -634,6 +644,11 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of target_signal_to_host, invalid_p == 0 */ /* Skip verify of get_siginfo_type, has predicate */ /* Skip verify of record_special_symbol, has predicate */ + /* Skip verify of get_syscall_number, has predicate */ + /* Skip verify of get_syscall_by_number, has predicate */ + /* Skip verify of get_syscall_by_name, has predicate */ + /* Skip verify of get_syscall_names, has predicate */ + /* Skip verify of xml_syscall_filename, invalid_p == 0 */ /* Skip verify of has_global_solist, invalid_p == 0 */ buf = ui_file_xstrdup (log, &dummy); make_cleanup (xfree, buf); @@ -859,6 +874,30 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "gdbarch_dump: get_siginfo_type = <%s>\n", host_address_to_string (gdbarch->get_siginfo_type)); fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_get_syscall_by_name_p() = %d\n", + gdbarch_get_syscall_by_name_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: get_syscall_by_name = <%s>\n", + host_address_to_string (gdbarch->get_syscall_by_name)); + fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_get_syscall_by_number_p() = %d\n", + gdbarch_get_syscall_by_number_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: get_syscall_by_number = <%s>\n", + host_address_to_string (gdbarch->get_syscall_by_number)); + fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_get_syscall_names_p() = %d\n", + gdbarch_get_syscall_names_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: get_syscall_names = <%s>\n", + host_address_to_string (gdbarch->get_syscall_names)); + fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_get_syscall_number_p() = %d\n", + gdbarch_get_syscall_number_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: get_syscall_number = <%s>\n", + host_address_to_string (gdbarch->get_syscall_number)); + fprintf_unfiltered (file, "gdbarch_dump: has_global_solist = %s\n", plongest (gdbarch->has_global_solist)); fprintf_unfiltered (file, @@ -1122,6 +1161,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: write_pc = <%s>\n", host_address_to_string (gdbarch->write_pc)); + fprintf_unfiltered (file, + "gdbarch_dump: xml_syscall_filename = %s\n", + gdbarch->xml_syscall_filename); if (gdbarch->dump_tdep != NULL) gdbarch->dump_tdep (gdbarch, file); } @@ -3333,6 +3375,119 @@ set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, } int +gdbarch_get_syscall_number_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->get_syscall_number != NULL; +} + +LONGEST +gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->get_syscall_number != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_number called\n"); + return gdbarch->get_syscall_number (gdbarch, ptid); +} + +void +set_gdbarch_get_syscall_number (struct gdbarch *gdbarch, + gdbarch_get_syscall_number_ftype get_syscall_number) +{ + gdbarch->get_syscall_number = get_syscall_number; +} + +int +gdbarch_get_syscall_by_number_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->get_syscall_by_number != NULL; +} + +void +gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, int syscall_number, struct syscall *s) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->get_syscall_by_number != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_by_number called\n"); + gdbarch->get_syscall_by_number (gdbarch, syscall_number, s); +} + +void +set_gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, + gdbarch_get_syscall_by_number_ftype get_syscall_by_number) +{ + gdbarch->get_syscall_by_number = get_syscall_by_number; +} + +int +gdbarch_get_syscall_by_name_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->get_syscall_by_name != NULL; +} + +void +gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->get_syscall_by_name != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_by_name called\n"); + gdbarch->get_syscall_by_name (gdbarch, syscall_name, s); +} + +void +set_gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, + gdbarch_get_syscall_by_name_ftype get_syscall_by_name) +{ + gdbarch->get_syscall_by_name = get_syscall_by_name; +} + +int +gdbarch_get_syscall_names_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->get_syscall_names != NULL; +} + +const char ** +gdbarch_get_syscall_names (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->get_syscall_names != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_names called\n"); + return gdbarch->get_syscall_names (gdbarch); +} + +void +set_gdbarch_get_syscall_names (struct gdbarch *gdbarch, + gdbarch_get_syscall_names_ftype get_syscall_names) +{ + gdbarch->get_syscall_names = get_syscall_names; +} + +const char * +gdbarch_xml_syscall_filename (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + /* Skip verify of xml_syscall_filename, invalid_p == 0 */ + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_xml_syscall_filename called\n"); + return gdbarch->xml_syscall_filename; +} + +void +set_gdbarch_xml_syscall_filename (struct gdbarch *gdbarch, + const char * xml_syscall_filename) +{ + gdbarch->xml_syscall_filename = xml_syscall_filename; +} + +int gdbarch_has_global_solist (struct gdbarch *gdbarch) { gdb_assert (gdbarch != NULL); diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 04c8920..017b9df 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -52,6 +52,7 @@ struct bp_target_info; struct target_desc; struct displaced_step_closure; struct core_regset_section; +struct syscall; extern struct gdbarch *current_gdbarch; extern struct gdbarch *target_gdbarch; @@ -839,6 +840,47 @@ typedef void (gdbarch_record_special_symbol_ftype) (struct gdbarch *gdbarch, str extern void gdbarch_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, asymbol *sym); extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_record_special_symbol_ftype *record_special_symbol); +/* Functions for the 'catch syscall' feature. + Get architecture-specific system calls information from registers. */ + +extern int gdbarch_get_syscall_number_p (struct gdbarch *gdbarch); + +typedef LONGEST (gdbarch_get_syscall_number_ftype) (struct gdbarch *gdbarch, ptid_t ptid); +extern LONGEST gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid); +extern void set_gdbarch_get_syscall_number (struct gdbarch *gdbarch, gdbarch_get_syscall_number_ftype *get_syscall_number); + +/* Fills the struct syscall (passed as argument) with the corresponding + system call represented by syscall_number. */ + +extern int gdbarch_get_syscall_by_number_p (struct gdbarch *gdbarch); + +typedef void (gdbarch_get_syscall_by_number_ftype) (struct gdbarch *gdbarch, int syscall_number, struct syscall *s); +extern void gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, int syscall_number, struct syscall *s); +extern void set_gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, gdbarch_get_syscall_by_number_ftype *get_syscall_by_number); + +/* Fills the struct syscall (passed as argument) with the corresponding + system call represented by syscall_name. */ + +extern int gdbarch_get_syscall_by_name_p (struct gdbarch *gdbarch); + +typedef void (gdbarch_get_syscall_by_name_ftype) (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s); +extern void gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s); +extern void set_gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, gdbarch_get_syscall_by_name_ftype *get_syscall_by_name); + +/* Returns the array containing the syscall names for the architecture. */ + +extern int gdbarch_get_syscall_names_p (struct gdbarch *gdbarch); + +typedef const char ** (gdbarch_get_syscall_names_ftype) (struct gdbarch *gdbarch); +extern const char ** gdbarch_get_syscall_names (struct gdbarch *gdbarch); +extern void set_gdbarch_get_syscall_names (struct gdbarch *gdbarch, gdbarch_get_syscall_names_ftype *get_syscall_names); + +/* Stores the name of syscall's XML file. Contains NULL if the file + was not set. */ + +extern const char * gdbarch_xml_syscall_filename (struct gdbarch *gdbarch); +extern void set_gdbarch_xml_syscall_filename (struct gdbarch *gdbarch, const char * xml_syscall_filename); + /* True if the list of shared libraries is one and only for all processes, as opposed to a list of shared libraries per inferior. When this property is true, GDB assumes that since shared libraries @@ -848,6 +890,9 @@ extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_ extern int gdbarch_has_global_solist (struct gdbarch *gdbarch); extern void set_gdbarch_has_global_solist (struct gdbarch *gdbarch, int has_global_solist); +/* Definition for an unknown syscall, used basically in error-cases. */ +#define UNKNOWN_SYSCALL (-1) + extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index f93bfc1..66cbcd0 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -724,6 +724,26 @@ M:struct type *:get_siginfo_type:void: # Record architecture-specific information from the symbol table. M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym +# Functions for the 'catch syscall' feature. + +# Get architecture-specific system calls information from registers. +M:LONGEST:get_syscall_number:ptid_t ptid:ptid + +# Fills the struct syscall (passed as argument) with the corresponding +# system call represented by syscall_number. +M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s + +# Fills the struct syscall (passed as argument) with the corresponding +# system call represented by syscall_name. +M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s + +# Returns the array containing the syscall names for the architecture. +M:const char **:get_syscall_names:void: + +# Stores the name of syscall's XML file. Contains NULL if the file +# was not set. +v:const char *:xml_syscall_filename:::0:0::0:gdbarch->xml_syscall_filename + # True if the list of shared libraries is one and only for all # processes, as opposed to a list of shared libraries per inferior. # When this property is true, GDB assumes that since shared libraries @@ -842,6 +862,7 @@ struct bp_target_info; struct target_desc; struct displaced_step_closure; struct core_regset_section; +struct syscall; extern struct gdbarch *current_gdbarch; extern struct gdbarch *target_gdbarch; @@ -911,6 +932,9 @@ done # close it off cat <objfile_obstack, struct type); TYPE_MAIN_TYPE (type) = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct main_type); OBJSTAT (objfile, n_types++); + break; } /* Initialize the fields that might not be zero. */ @@ -180,6 +201,9 @@ alloc_type (struct objfile *objfile) TYPE_VPTR_FIELDNO (type) = -1; TYPE_CHAIN (type) = type; /* Chain back to itself. */ + if (objfile == NULL) + type_init_refc (type, parent); + return (type); } @@ -194,16 +218,24 @@ alloc_type_instance (struct type *oldtype) /* Allocate the structure. */ - if (TYPE_OBJFILE (oldtype) == NULL) - type = XZALLOC (struct type); - else - type = OBSTACK_ZALLOC (&TYPE_OBJFILE (oldtype)->objfile_obstack, - struct type); - + switch ((long) TYPE_OBJFILE (oldtype)) + { + case (long) OBJFILE_INTERNAL: + case (long) OBJFILE_MALLOC: + type = XZALLOC (struct type); + break; + default: + type = OBSTACK_ZALLOC (&TYPE_OBJFILE (oldtype)->objfile_obstack, + struct type); + break; + } TYPE_MAIN_TYPE (type) = TYPE_MAIN_TYPE (oldtype); TYPE_CHAIN (type) = type; /* Chain back to itself for now. */ + if (TYPE_OBJFILE (oldtype) == NULL) + type_init_refc (type, oldtype); + return (type); } @@ -248,7 +280,7 @@ make_pointer_type (struct type *type, struct type **typeptr) if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ { - ntype = alloc_type (TYPE_OBJFILE (type)); + ntype = alloc_type (TYPE_OBJFILE (type), type); if (typeptr) *typeptr = ntype; } @@ -260,6 +292,9 @@ make_pointer_type (struct type *type, struct type **typeptr) smash_type (ntype); TYPE_CHAIN (ntype) = chain; TYPE_OBJFILE (ntype) = objfile; + + /* Callers may only supply storage if there is an objfile. */ + gdb_assert (objfile); } TYPE_TARGET_TYPE (ntype) = type; @@ -328,7 +363,7 @@ make_reference_type (struct type *type, struct type **typeptr) if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ { - ntype = alloc_type (TYPE_OBJFILE (type)); + ntype = alloc_type (TYPE_OBJFILE (type), type); if (typeptr) *typeptr = ntype; } @@ -340,6 +375,9 @@ make_reference_type (struct type *type, struct type **typeptr) smash_type (ntype); TYPE_CHAIN (ntype) = chain; TYPE_OBJFILE (ntype) = objfile; + + /* Callers may only supply storage if there is an objfile. */ + gdb_assert (objfile); } TYPE_TARGET_TYPE (ntype) = type; @@ -388,7 +426,7 @@ make_function_type (struct type *type, struct type **typeptr) if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ { - ntype = alloc_type (TYPE_OBJFILE (type)); + ntype = alloc_type (TYPE_OBJFILE (type), type); if (typeptr) *typeptr = ntype; } @@ -398,6 +436,9 @@ make_function_type (struct type *type, struct type **typeptr) objfile = TYPE_OBJFILE (ntype); smash_type (ntype); TYPE_OBJFILE (ntype) = objfile; + + /* Callers may only supply storage if there is an objfile. */ + gdb_assert (objfile); } TYPE_TARGET_TYPE (ntype) = type; @@ -643,7 +684,7 @@ lookup_memberptr_type (struct type *type, struct type *domain) { struct type *mtype; - mtype = alloc_type (TYPE_OBJFILE (type)); + mtype = alloc_type (TYPE_OBJFILE (type), NULL); smash_to_memberptr_type (mtype, domain, type); return (mtype); } @@ -655,7 +696,7 @@ lookup_methodptr_type (struct type *to_type) { struct type *mtype; - mtype = alloc_type (TYPE_OBJFILE (to_type)); + mtype = alloc_type (TYPE_OBJFILE (to_type), NULL); TYPE_TARGET_TYPE (mtype) = to_type; TYPE_DOMAIN_TYPE (mtype) = TYPE_DOMAIN_TYPE (to_type); TYPE_LENGTH (mtype) = cplus_method_ptr_size (to_type); @@ -696,19 +737,20 @@ create_range_type (struct type *result_type, struct type *index_type, int low_bound, int high_bound) { if (result_type == NULL) - result_type = alloc_type (TYPE_OBJFILE (index_type)); + result_type = alloc_type (TYPE_OBJFILE (index_type), index_type); TYPE_CODE (result_type) = TYPE_CODE_RANGE; TYPE_TARGET_TYPE (result_type) = index_type; if (TYPE_STUB (index_type)) TYPE_TARGET_STUB (result_type) = 1; else TYPE_LENGTH (result_type) = TYPE_LENGTH (check_typedef (index_type)); - TYPE_NFIELDS (result_type) = 2; + TYPE_NFIELDS (result_type) = 3; TYPE_FIELDS (result_type) = TYPE_ZALLOC (result_type, TYPE_NFIELDS (result_type) * sizeof (struct field)); TYPE_LOW_BOUND (result_type) = low_bound; TYPE_HIGH_BOUND (result_type) = high_bound; + TYPE_BYTE_STRIDE (result_type) = 0; if (low_bound >= 0) TYPE_UNSIGNED (result_type) = 1; @@ -727,6 +769,9 @@ get_discrete_bounds (struct type *type, LONGEST *lowp, LONGEST *highp) switch (TYPE_CODE (type)) { case TYPE_CODE_RANGE: + if (TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (type) + || TYPE_RANGE_LOWER_BOUND_IS_UNDEFINED (type)) + return -1; *lowp = TYPE_LOW_BOUND (type); *highp = TYPE_HIGH_BOUND (type); return 1; @@ -805,30 +850,56 @@ create_array_type (struct type *result_type, if (result_type == NULL) { - result_type = alloc_type (TYPE_OBJFILE (range_type)); + result_type = alloc_type (TYPE_OBJFILE (range_type), range_type); } + else + { + /* Callers may only supply storage if there is an objfile. */ + gdb_assert (TYPE_OBJFILE (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)); + /* FIXME: type alloc. */ TYPE_INDEX_TYPE (result_type) = range_type; TYPE_VPTR_FIELDNO (result_type) = -1; - /* TYPE_FLAG_TARGET_STUB will take care of zero length arrays */ + /* DWARF blocks may depend on runtime information like + DW_OP_PUSH_OBJECT_ADDRESS not being available during the + CREATE_ARRAY_TYPE time. */ + if (TYPE_RANGE_BOUND_IS_DWARF_BLOCK (range_type, 0) + || TYPE_RANGE_BOUND_IS_DWARF_BLOCK (range_type, 1) + || TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (range_type) + || TYPE_RANGE_LOWER_BOUND_IS_UNDEFINED (range_type) + || get_discrete_bounds (range_type, &low_bound, &high_bound) < 0) + { + low_bound = 0; + high_bound = -1; + } + + /* Be careful when setting the array length. Ada arrays can be + empty arrays with the high_bound being smaller than the low_bound. + In such cases, the array length should be zero. TYPE_TARGET_STUB needs to + be checked as it may have dependencies on DWARF blocks depending on + runtime information not available during the CREATE_ARRAY_TYPE time. */ + if (high_bound < low_bound || TYPE_TARGET_STUB (element_type)) + TYPE_LENGTH (result_type) = 0; + else + { + CHECK_TYPEDEF (element_type); + TYPE_LENGTH (result_type) = + TYPE_LENGTH (element_type) * (high_bound - low_bound + 1); + } + if (TYPE_LENGTH (result_type) == 0) - TYPE_TARGET_STUB (result_type) = 1; + { + /* The real size will be computed for specific instances by + CHECK_TYPEDEF. */ + TYPE_TARGET_STUB (result_type) = 1; + } return (result_type); } @@ -865,7 +936,12 @@ create_set_type (struct type *result_type, struct type *domain_type) { if (result_type == NULL) { - result_type = alloc_type (TYPE_OBJFILE (domain_type)); + result_type = alloc_type (TYPE_OBJFILE (domain_type), domain_type); + } + else + { + /* Callers may only supply storage if there is an objfile. */ + gdb_assert (TYPE_OBJFILE (result_type)); } TYPE_CODE (result_type) = TYPE_CODE_SET; TYPE_NFIELDS (result_type) = 1; @@ -1368,6 +1444,84 @@ stub_noname_complaint (void) complaint (&symfile_complaints, _("stub type has NULL name")); } +/* Calculate the memory length of array TYPE. + + TARGET_TYPE should be set to `check_typedef (TYPE_TARGET_TYPE (type))' as + a performance hint. Feel free to pass NULL. Set FULL_SPAN to return the + size incl. the possible padding of the last element - it may differ from the + cleared FULL_SPAN return value (the expected SIZEOF) for non-zero + TYPE_BYTE_STRIDE values. */ + +static CORE_ADDR +type_length_get (struct type *type, struct type *target_type, int full_span) +{ + struct type *range_type; + int count; + CORE_ADDR byte_stride = 0; /* `= 0' for a false GCC warning. */ + CORE_ADDR element_size; + + if (TYPE_CODE (type) != TYPE_CODE_ARRAY + && TYPE_CODE (type) != TYPE_CODE_STRING) + return TYPE_LENGTH (type); + + /* Avoid executing TYPE_HIGH_BOUND for invalid (unallocated/unassociated) + Fortran arrays. The allocated data will never be used so they can be + zero-length. */ + if (object_address_data_not_valid (type)) + return 0; + + range_type = TYPE_INDEX_TYPE (type); + if (TYPE_RANGE_LOWER_BOUND_IS_UNDEFINED (range_type) + || TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (range_type)) + return 0; + count = TYPE_HIGH_BOUND (range_type) - TYPE_LOW_BOUND (range_type) + 1; + /* It may happen for wrong DWARF annotations returning garbage data. */ + if (count < 0) + warning (_("Range for type %s has invalid bounds %d..%d"), + TYPE_NAME (type), TYPE_LOW_BOUND (range_type), + TYPE_HIGH_BOUND (range_type)); + /* The code below does not handle count == 0 right. */ + if (count <= 0) + return 0; + if (full_span || count > 1) + { + /* We do not use TYPE_ARRAY_BYTE_STRIDE_VALUE (type) here as we want to + force FULL_SPAN to 1. */ + byte_stride = TYPE_BYTE_STRIDE (range_type); + if (byte_stride == 0) + { + if (target_type == NULL) + target_type = check_typedef (TYPE_TARGET_TYPE (type)); + byte_stride = type_length_get (target_type, NULL, 1); + } + } + if (full_span) + return count * byte_stride; + if (target_type == NULL) + target_type = check_typedef (TYPE_TARGET_TYPE (type)); + element_size = type_length_get (target_type, NULL, 1); + return (count - 1) * byte_stride + element_size; +} + +/* Prepare TYPE after being read in by the backend. Currently this function + only propagates the TYPE_DYNAMIC flag. */ + +void +finalize_type (struct type *type) +{ + int i; + + for (i = 0; i < TYPE_NFIELDS (type); ++i) + if (TYPE_FIELD_TYPE (type, i) && TYPE_DYNAMIC (TYPE_FIELD_TYPE (type, i))) + break; + + /* FIXME: cplus_stuff is ignored here. */ + if (i < TYPE_NFIELDS (type) + || (TYPE_VPTR_BASETYPE (type) && TYPE_DYNAMIC (TYPE_VPTR_BASETYPE (type))) + || (TYPE_TARGET_TYPE (type) && TYPE_DYNAMIC (TYPE_TARGET_TYPE (type)))) + TYPE_DYNAMIC (type) = 1; +} + /* Added by Bryan Boreham, Kewill, Sun Sep 17 18:07:17 1989. If this is a stubbed struct (i.e. declared as struct foo *), see if @@ -1384,7 +1538,8 @@ stub_noname_complaint (void) /* Find the real type of TYPE. This function returns the real type, after removing all layers of typedefs and completing opaque or stub types. Completion changes the TYPE argument, but stripping of - typedefs does not. */ + typedefs does not. Still original passed TYPE will have TYPE_LENGTH + updated. FIXME: Remove this dependency (only ada_to_fixed_type?). */ struct type * check_typedef (struct type *type) @@ -1420,7 +1575,7 @@ check_typedef (struct type *type) if (sym) TYPE_TARGET_TYPE (type) = SYMBOL_TYPE (sym); else /* TYPE_CODE_UNDEF */ - TYPE_TARGET_TYPE (type) = alloc_type (NULL); + TYPE_TARGET_TYPE (type) = alloc_type (NULL, NULL); } type = TYPE_TARGET_TYPE (type); } @@ -1494,34 +1649,37 @@ check_typedef (struct type *type) } } - if (TYPE_TARGET_STUB (type)) + /* copy_type_recursive automatically makes the resulting type containing only + constant values expected by the callers of this function. */ + if (TYPE_DYNAMIC (type)) + { + htab_t copied_types; + struct type *type_old = type; + + copied_types = create_copied_types_hash (NULL); + type = copy_type_recursive (type, copied_types); + htab_delete (copied_types); + + gdb_assert (TYPE_DYNAMIC (type) == 0); + } + + if (!currently_reading_symtab + && (TYPE_TARGET_STUB (type) || TYPE_DYNAMIC (type))) { - struct type *range_type; struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type)); + if (TYPE_DYNAMIC (type)) + TYPE_TARGET_TYPE (type) = target_type; if (TYPE_STUB (target_type) || TYPE_TARGET_STUB (target_type)) { /* Empty. */ } else if (TYPE_CODE (type) == TYPE_CODE_ARRAY - && TYPE_NFIELDS (type) == 1 - && (TYPE_CODE (range_type = TYPE_INDEX_TYPE (type)) - == TYPE_CODE_RANGE)) + || TYPE_CODE (type) == TYPE_CODE_STRING) { /* Now recompute the length of the array type, based on its - number of elements and the target type's length. - Watch out for Ada null Ada arrays where the high bound - is smaller than the low bound. */ - const int low_bound = TYPE_LOW_BOUND (range_type); - const int high_bound = TYPE_HIGH_BOUND (range_type); - int nb_elements; - - if (high_bound < low_bound) - nb_elements = 0; - else - nb_elements = high_bound - low_bound + 1; - - TYPE_LENGTH (type) = nb_elements * TYPE_LENGTH (target_type); + number of elements and the target type's length. */ + TYPE_LENGTH (type) = type_length_get (type, target_type, 0); TYPE_TARGET_STUB (type) = 0; } else if (TYPE_CODE (type) == TYPE_CODE_RANGE) @@ -1529,9 +1687,12 @@ check_typedef (struct type *type) TYPE_LENGTH (type) = TYPE_LENGTH (target_type); TYPE_TARGET_STUB (type) = 0; } + TYPE_DYNAMIC (type) = 0; } + /* Cache TYPE_LENGTH for future use. */ TYPE_LENGTH (orig_type) = TYPE_LENGTH (type); + return type; } @@ -1753,7 +1914,7 @@ init_type (enum type_code code, int length, int flags, { struct type *type; - type = alloc_type (objfile); + type = alloc_type (objfile, NULL); TYPE_CODE (type) = code; TYPE_LENGTH (type) = length; @@ -1783,15 +1944,24 @@ init_type (enum type_code code, int length, int flags, if (flags & TYPE_FLAG_FIXED_INSTANCE) TYPE_FIXED_INSTANCE (type) = 1; - if ((name != NULL) && (objfile != NULL)) - { - TYPE_NAME (type) = obsavestring (name, strlen (name), - &objfile->objfile_obstack); - } - else - { - TYPE_NAME (type) = name; - } + if (name) + switch ((long) objfile) + { + case (long) OBJFILE_INTERNAL: + TYPE_NAME (type) = name; + break; + case (long) OBJFILE_MALLOC: + TYPE_NAME (type) = xstrdup (name); + break; +#if 0 /* OBJFILE_MALLOC duplication now. */ + case (long) NULL: + internal_error (__FILE__, __LINE__, + _("OBJFILE pointer NULL should be OBJFILE_* instead")); +#endif + default: + TYPE_NAME (type) = obsavestring (name, strlen (name), + &objfile->objfile_obstack); + } /* C++ fancies. */ @@ -1803,6 +1973,10 @@ init_type (enum type_code code, int length, int flags, { INIT_CPLUS_SPECIFIC (type); } + + if (!objfile) + type_incref (type); + return (type); } @@ -2916,33 +3090,47 @@ 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. + REPRESENTATIVE is a pointer to a type. This is used to register + newly-created types in the type_refc_table. Initially it pointer + to a NULL pointer, but it is filled in the first time a type is + copied. 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 **representative) { struct type_pair *stored, pair; void **slot; struct type *new_type; - if (TYPE_OBJFILE (type) == NULL) + if (TYPE_OBJFILE (type) == OBJFILE_INTERNAL + || (objfile == OBJFILE_MALLOC && !TYPE_DYNAMIC (type))) return type; /* This type shouldn't be pointing to any types in other objfiles; @@ -2954,11 +3142,15 @@ copy_type_recursive (struct objfile *objfile, if (*slot != NULL) return ((struct type_pair *) *slot)->new; - new_type = alloc_type (NULL); + new_type = alloc_type (OBJFILE_MALLOC, *representative); + if (!*representative) + *representative = new_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; @@ -2968,6 +3160,13 @@ copy_type_recursive (struct objfile *objfile, *TYPE_MAIN_TYPE (new_type) = *TYPE_MAIN_TYPE (type); TYPE_OBJFILE (new_type) = NULL; + /* 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)) @@ -2976,12 +3175,45 @@ copy_type_recursive (struct objfile *objfile, TYPE_INSTANCE_FLAGS (new_type) = TYPE_INSTANCE_FLAGS (type); TYPE_LENGTH (new_type) = TYPE_LENGTH (type); + if (TYPE_ALLOCATED (new_type)) + { + gdb_assert (!TYPE_NOT_ALLOCATED (new_type)); + + if (!dwarf_locexpr_baton_eval (TYPE_ALLOCATED (new_type))) + TYPE_NOT_ALLOCATED (new_type) = 1; + TYPE_ALLOCATED (new_type) = NULL; + } + + if (TYPE_ASSOCIATED (new_type)) + { + gdb_assert (!TYPE_NOT_ASSOCIATED (new_type)); + + if (!dwarf_locexpr_baton_eval (TYPE_ASSOCIATED (new_type))) + TYPE_NOT_ASSOCIATED (new_type) = 1; + TYPE_ASSOCIATED (new_type) = NULL; + } + + if (!TYPE_DATA_LOCATION_IS_ADDR (new_type) + && TYPE_DATA_LOCATION_DWARF_BLOCK (new_type)) + { + if (TYPE_NOT_ALLOCATED (new_type) + || TYPE_NOT_ASSOCIATED (new_type)) + TYPE_DATA_LOCATION_DWARF_BLOCK (new_type) = NULL; + else + { + TYPE_DATA_LOCATION_IS_ADDR (new_type) = 1; + TYPE_DATA_LOCATION_ADDR (new_type) = dwarf_locexpr_baton_eval + (TYPE_DATA_LOCATION_DWARF_BLOCK (new_type)); + } + } + /* Copy the fields. */ if (TYPE_NFIELDS (type)) { int i, nfields; nfields = TYPE_NFIELDS (type); + TYPE_NFIELDS (new_type) = nfields; TYPE_FIELDS (new_type) = XCALLOC (nfields, struct field); for (i = 0; i < nfields; i++) { @@ -2990,8 +3222,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, representative); if (TYPE_FIELD_NAME (type, i)) TYPE_FIELD_NAME (new_type, i) = xstrdup (TYPE_FIELD_NAME (type, i)); @@ -3010,6 +3242,16 @@ copy_type_recursive (struct objfile *objfile, xstrdup (TYPE_FIELD_STATIC_PHYSNAME (type, i))); break; + case FIELD_LOC_KIND_DWARF_BLOCK: + /* `struct dwarf2_locexpr_baton' is too bound to its objfile so + it is expected to be made constant by CHECK_TYPEDEF. */ + if (TYPE_NOT_ALLOCATED (new_type) + || TYPE_NOT_ASSOCIATED (new_type)) + SET_FIELD_DWARF_BLOCK (TYPE_FIELD (new_type, i), NULL); + else + SET_FIELD_BITPOS (TYPE_FIELD (new_type, i), + dwarf_locexpr_baton_eval (TYPE_FIELD_DWARF_BLOCK (type, i))); + break; default: internal_error (__FILE__, __LINE__, _("Unexpected type field location kind: %d"), @@ -3018,17 +3260,32 @@ copy_type_recursive (struct objfile *objfile, } } + /* Convert TYPE_RANGE_HIGH_BOUND_IS_COUNT into a regular bound. */ + if (TYPE_CODE (type) == TYPE_CODE_RANGE + && TYPE_RANGE_HIGH_BOUND_IS_COUNT (type)) + { + TYPE_RANGE_HIGH_BOUND_IS_COUNT (new_type) = 0; + TYPE_HIGH_BOUND (new_type) = TYPE_LOW_BOUND (type) + + TYPE_HIGH_BOUND (type) - 1; + } + + /* Both FIELD_LOC_KIND_DWARF_BLOCK and TYPE_RANGE_HIGH_BOUND_IS_COUNT were + possibly converted. */ + TYPE_DYNAMIC (new_type) = 0; + /* Copy pointers to other types. */ if (TYPE_TARGET_TYPE (type)) TYPE_TARGET_TYPE (new_type) = - copy_type_recursive (objfile, - TYPE_TARGET_TYPE (type), - copied_types); + copy_type_recursive_1 (objfile, + TYPE_TARGET_TYPE (type), + copied_types, + representative); 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, + representative); /* Maybe copy the type_specific bits. NOTE drow/2005-12-09: We do not copy the C++-specific bits like @@ -3046,6 +3303,20 @@ 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) +{ + struct type *representative = NULL; + + return copy_type_recursive_1 (TYPE_OBJFILE (type), type, copied_types, + &representative); +} + /* Make a copy of the given TYPE, except that the pointer & reference types are not preserved. @@ -3059,7 +3330,7 @@ copy_type (const struct type *type) gdb_assert (TYPE_OBJFILE (type) != NULL); - new_type = alloc_type (TYPE_OBJFILE (type)); + new_type = alloc_type (TYPE_OBJFILE (type), NULL); TYPE_INSTANCE_FLAGS (new_type) = TYPE_INSTANCE_FLAGS (type); TYPE_LENGTH (new_type) = TYPE_LENGTH (type); memcpy (TYPE_MAIN_TYPE (new_type), TYPE_MAIN_TYPE (type), @@ -3068,6 +3339,232 @@ copy_type (const struct type *type) return new_type; } +static void delete_type (struct type *type); + +/* 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 main_type *main_type) +{ + int i; + void **slot; + struct + { + struct main_type *main_type; + } type_local = { main_type }, *type = &type_local; + + gdb_assert (TYPE_OBJFILE (type) == OBJFILE_MALLOC); + + 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)); + + /* Strangely, HAVE_CPLUS_STRUCT will return true when there isn't + one at all. */ + gdb_assert (!HAVE_CPLUS_STRUCT (type) || !TYPE_CPLUS_SPECIFIC (type)); + + xfree (TYPE_MAIN_TYPE (type)); +} + +/* Store `struct main_type *' entries which got `struct type *' deleted. */ + +static htab_t deleted_main_types_hash; + +/* To be called before any call of delete_type. */ + +static void +delete_type_begin (void) +{ + gdb_assert (deleted_main_types_hash == NULL); + + deleted_main_types_hash = htab_create_alloc (10, htab_hash_pointer, + htab_eq_pointer, NULL, xcalloc, xfree); +} + +/* Helper for delete_type_finish. */ + +static int +delete_type_finish_traverse (void **slot, void *unused) +{ + struct main_type *main_type = *slot; + + delete_main_type (main_type); + + return 1; +} + +/* To be called after all the calls of delete_type. Each MAIN_TYPE must have + either none or all of its TYPE entries deleted. */ + +static void +delete_type_finish (void) +{ + htab_traverse (deleted_main_types_hash, delete_type_finish_traverse, NULL); + + htab_delete (deleted_main_types_hash); + deleted_main_types_hash = NULL; +} + +/* Delete TYPE and remember MAIN_TYPE it references. TYPE must have been + allocated using xmalloc -- not using an objfile. You must wrap calls of + this function by delete_type_begin and delete_type_finish. */ + +static void +delete_type (struct type *type) +{ + void **slot; + + if (!type) + return; + + if (TYPE_OBJFILE (type) == OBJFILE_INTERNAL) + return; + gdb_assert (TYPE_OBJFILE (type) == OBJFILE_MALLOC); + + slot = htab_find_slot (deleted_main_types_hash, TYPE_MAIN_TYPE (type), + INSERT); + gdb_assert (!*slot); + *slot = TYPE_MAIN_TYPE (type); + + xfree (type); +} + +/* Hash function for type_refc_table. */ + +static hashval_t +type_refc_hash (const void *p) +{ + const struct type_refc_entry *entry = p; + return htab_hash_pointer (entry->type); +} + +/* Equality function for type_refc_table. */ + +static int +type_refc_equal (const void *a, const void *b) +{ + const struct type_refc_entry *left = a; + const struct type_refc_entry *right = b; + return left->type == right->type; +} + +/* Insert the new type NEW_TYPE into the table. Does nothing if + NEW_TYPE has an objfile. If PARENT_TYPE is not NULL, then NEW_TYPE + will be inserted into the same hierarchy as PARENT_TYPE. In this + case, PARENT_TYPE must already exist in the reference count map. + If PARENT_TYPE is NULL, a new reference count is allocated and set + to one. */ + +static void +type_init_refc (struct type *new_type, struct type *parent_type) +{ + int *refc; + void **slot; + struct type_refc_entry *new_entry; + + if (TYPE_OBJFILE (new_type)) + return; + + if (parent_type) + { + struct type_refc_entry entry, *found; + entry.type = parent_type; + found = htab_find (type_refc_table, &entry); + gdb_assert (found); + refc = found->refc; + } + else + { + refc = xmalloc (sizeof (int)); + *refc = 0; + } + + new_entry = XNEW (struct type_refc_entry); + new_entry->type = new_type; + new_entry->refc = refc; + + slot = htab_find_slot (type_refc_table, new_entry, INSERT); + gdb_assert (!*slot); + *slot = new_entry; +} + +/* Increment the reference count for TYPE. */ + +void +type_incref (struct type *type) +{ + struct type_refc_entry entry, *found; + + if (TYPE_OBJFILE (type)) + return; + + entry.type = type; + found = htab_find (type_refc_table, &entry); + gdb_assert (found); + ++*(found->refc); +} + +/* A traverse callback for type_refc_table which removes any entry + whose reference count is zero (unused entry). */ + +static int +type_refc_remove (void **slot, void *unused) +{ + struct type_refc_entry *entry = *slot; + + if (*entry->refc == 0) + { + delete_type (entry->type); + + xfree (entry); + htab_clear_slot (type_refc_table, slot); + } + + return 1; +} + +/* Decrement the reference count for TYPE. Even if TYPE has no more + references still do not delete it as callers may hold pointers to types + dynamically generated by check_typedef where type_incref is never called. + Always rely on the free_all_types garbage collector. */ + +void +type_decref (struct type *type) +{ + struct type_refc_entry entry, *found; + + if (TYPE_OBJFILE (type)) + return; + + entry.type = type; + found = htab_find (type_refc_table, &entry); + gdb_assert (found); + gdb_assert (found->refc > 0); + --*(found->refc); +} + +/* Free all the types that have been allocated and that are not used according + to type_refc_entry->refc. Called after each command, successful or not. + Use this cleanup only in the GDB idle state as GDB code does not necessarily + use type_incref / type_decref during temporary use of types. */ + +void +free_all_types (void) +{ + delete_type_begin (); + htab_traverse (type_refc_table, type_refc_remove, NULL); + delete_type_finish (); +} + static struct type * build_flt (int bit, char *name, const struct floatformat **floatformats) { @@ -3105,7 +3602,7 @@ build_complex (int bit, char *name, struct type *target_type) return builtin_type_error; } t = init_type (TYPE_CODE_COMPLEX, 2 * bit / TARGET_CHAR_BIT, - 0, name, (struct objfile *) NULL); + 0, name, OBJFILE_INTERNAL); TYPE_TARGET_TYPE (t) = target_type; return t; } @@ -3119,56 +3616,56 @@ gdbtypes_post_init (struct gdbarch *gdbarch) builtin_type->builtin_void = init_type (TYPE_CODE_VOID, 1, 0, - "void", (struct objfile *) NULL); + "void", OBJFILE_INTERNAL); builtin_type->builtin_char = init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, (TYPE_FLAG_NOSIGN | (gdbarch_char_signed (gdbarch) ? 0 : TYPE_FLAG_UNSIGNED)), - "char", (struct objfile *) NULL); + "char", OBJFILE_INTERNAL); builtin_type->builtin_signed_char = init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, 0, - "signed char", (struct objfile *) NULL); + "signed char", OBJFILE_INTERNAL); builtin_type->builtin_unsigned_char = init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, TYPE_FLAG_UNSIGNED, - "unsigned char", (struct objfile *) NULL); + "unsigned char", OBJFILE_INTERNAL); builtin_type->builtin_short = init_type (TYPE_CODE_INT, gdbarch_short_bit (gdbarch) / TARGET_CHAR_BIT, - 0, "short", (struct objfile *) NULL); + 0, "short", OBJFILE_INTERNAL); builtin_type->builtin_unsigned_short = init_type (TYPE_CODE_INT, gdbarch_short_bit (gdbarch) / TARGET_CHAR_BIT, TYPE_FLAG_UNSIGNED, "unsigned short", - (struct objfile *) NULL); + OBJFILE_INTERNAL); builtin_type->builtin_int = init_type (TYPE_CODE_INT, gdbarch_int_bit (gdbarch) / TARGET_CHAR_BIT, - 0, "int", (struct objfile *) NULL); + 0, "int", OBJFILE_INTERNAL); builtin_type->builtin_unsigned_int = init_type (TYPE_CODE_INT, gdbarch_int_bit (gdbarch) / TARGET_CHAR_BIT, TYPE_FLAG_UNSIGNED, "unsigned int", - (struct objfile *) NULL); + OBJFILE_INTERNAL); builtin_type->builtin_long = init_type (TYPE_CODE_INT, gdbarch_long_bit (gdbarch) / TARGET_CHAR_BIT, - 0, "long", (struct objfile *) NULL); + 0, "long", OBJFILE_INTERNAL); builtin_type->builtin_unsigned_long = init_type (TYPE_CODE_INT, gdbarch_long_bit (gdbarch) / TARGET_CHAR_BIT, TYPE_FLAG_UNSIGNED, "unsigned long", - (struct objfile *) NULL); + OBJFILE_INTERNAL); builtin_type->builtin_long_long = init_type (TYPE_CODE_INT, gdbarch_long_long_bit (gdbarch) / TARGET_CHAR_BIT, - 0, "long long", (struct objfile *) NULL); + 0, "long long", OBJFILE_INTERNAL); builtin_type->builtin_unsigned_long_long = init_type (TYPE_CODE_INT, gdbarch_long_long_bit (gdbarch) / TARGET_CHAR_BIT, TYPE_FLAG_UNSIGNED, "unsigned long long", - (struct objfile *) NULL); + OBJFILE_INTERNAL); builtin_type->builtin_float = build_flt (gdbarch_float_bit (gdbarch), "float", gdbarch_float_format (gdbarch)); @@ -3187,26 +3684,26 @@ gdbtypes_post_init (struct gdbarch *gdbarch) builtin_type->builtin_string = init_type (TYPE_CODE_STRING, TARGET_CHAR_BIT / TARGET_CHAR_BIT, 0, - "string", (struct objfile *) NULL); + "string", OBJFILE_INTERNAL); builtin_type->builtin_bool = init_type (TYPE_CODE_BOOL, TARGET_CHAR_BIT / TARGET_CHAR_BIT, 0, - "bool", (struct objfile *) NULL); + "bool", OBJFILE_INTERNAL); /* The following three are about decimal floating point types, which are 32-bits, 64-bits and 128-bits respectively. */ builtin_type->builtin_decfloat = init_type (TYPE_CODE_DECFLOAT, 32 / 8, 0, - "_Decimal32", (struct objfile *) NULL); + "_Decimal32", OBJFILE_INTERNAL); builtin_type->builtin_decdouble = init_type (TYPE_CODE_DECFLOAT, 64 / 8, 0, - "_Decimal64", (struct objfile *) NULL); + "_Decimal64", OBJFILE_INTERNAL); builtin_type->builtin_declong = init_type (TYPE_CODE_DECFLOAT, 128 / 8, 0, - "_Decimal128", (struct objfile *) NULL); + "_Decimal128", OBJFILE_INTERNAL); /* Pointer/Address types. */ @@ -3245,27 +3742,28 @@ gdbtypes_post_init (struct gdbarch *gdbarch) init_type (TYPE_CODE_INT, gdbarch_addr_bit (gdbarch) / 8, TYPE_FLAG_UNSIGNED, - "__CORE_ADDR", (struct objfile *) NULL); + "__CORE_ADDR", OBJFILE_INTERNAL); /* The following set of types is used for symbols with no debug information. */ builtin_type->nodebug_text_symbol = init_type (TYPE_CODE_FUNC, 1, 0, - "", NULL); + "", OBJFILE_INTERNAL); TYPE_TARGET_TYPE (builtin_type->nodebug_text_symbol) = builtin_type->builtin_int; builtin_type->nodebug_data_symbol = init_type (TYPE_CODE_INT, gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, 0, - "", NULL); + "", OBJFILE_INTERNAL); builtin_type->nodebug_unknown_symbol = init_type (TYPE_CODE_INT, 1, 0, - "", NULL); + "", + OBJFILE_INTERNAL); builtin_type->nodebug_tls_symbol = init_type (TYPE_CODE_INT, gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, 0, - "", NULL); + "", OBJFILE_INTERNAL); return builtin_type; } @@ -3276,6 +3774,9 @@ _initialize_gdbtypes (void) { gdbtypes_data = gdbarch_data_register_post_init (gdbtypes_post_init); + type_refc_table = htab_create_alloc (20, type_refc_hash, type_refc_equal, + NULL, xcalloc, xfree); + /* FIXME: The following types are architecture-neutral. However, they contain pointer_type and reference_type fields potentially caching pointer or reference types that *are* architecture @@ -3284,47 +3785,47 @@ _initialize_gdbtypes (void) builtin_type_int0 = init_type (TYPE_CODE_INT, 0 / 8, 0, - "int0_t", (struct objfile *) NULL); + "int0_t", OBJFILE_INTERNAL); builtin_type_int8 = init_type (TYPE_CODE_INT, 8 / 8, TYPE_FLAG_NOTTEXT, - "int8_t", (struct objfile *) NULL); + "int8_t", OBJFILE_INTERNAL); builtin_type_uint8 = init_type (TYPE_CODE_INT, 8 / 8, TYPE_FLAG_UNSIGNED | TYPE_FLAG_NOTTEXT, - "uint8_t", (struct objfile *) NULL); + "uint8_t", OBJFILE_INTERNAL); builtin_type_int16 = init_type (TYPE_CODE_INT, 16 / 8, 0, - "int16_t", (struct objfile *) NULL); + "int16_t", OBJFILE_INTERNAL); builtin_type_uint16 = init_type (TYPE_CODE_INT, 16 / 8, TYPE_FLAG_UNSIGNED, - "uint16_t", (struct objfile *) NULL); + "uint16_t", OBJFILE_INTERNAL); builtin_type_int32 = init_type (TYPE_CODE_INT, 32 / 8, 0, - "int32_t", (struct objfile *) NULL); + "int32_t", OBJFILE_INTERNAL); builtin_type_uint32 = init_type (TYPE_CODE_INT, 32 / 8, TYPE_FLAG_UNSIGNED, - "uint32_t", (struct objfile *) NULL); + "uint32_t", OBJFILE_INTERNAL); builtin_type_int64 = init_type (TYPE_CODE_INT, 64 / 8, 0, - "int64_t", (struct objfile *) NULL); + "int64_t", OBJFILE_INTERNAL); builtin_type_uint64 = init_type (TYPE_CODE_INT, 64 / 8, TYPE_FLAG_UNSIGNED, - "uint64_t", (struct objfile *) NULL); + "uint64_t", OBJFILE_INTERNAL); builtin_type_int128 = init_type (TYPE_CODE_INT, 128 / 8, 0, - "int128_t", (struct objfile *) NULL); + "int128_t", OBJFILE_INTERNAL); builtin_type_uint128 = init_type (TYPE_CODE_INT, 128 / 8, TYPE_FLAG_UNSIGNED, - "uint128_t", (struct objfile *) NULL); + "uint128_t", OBJFILE_INTERNAL); builtin_type_ieee_single = build_flt (-1, "builtin_type_ieee_single", floatformats_ieee_single); @@ -3344,15 +3845,15 @@ _initialize_gdbtypes (void) builtin_type_void = init_type (TYPE_CODE_VOID, 1, 0, - "void", (struct objfile *) NULL); + "void", OBJFILE_INTERNAL); builtin_type_true_char = init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT, 0, - "true character", (struct objfile *) NULL); + "true character", OBJFILE_INTERNAL); builtin_type_true_unsigned_char = init_type (TYPE_CODE_CHAR, TARGET_CHAR_BIT / TARGET_CHAR_BIT, TYPE_FLAG_UNSIGNED, - "true character", (struct objfile *) NULL); + "true character", OBJFILE_INTERNAL); add_setshow_zinteger_cmd ("overload", no_class, &overload_debug, _("\ Set debugging of C++ overloading."), _("\ diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index c90b6d7..077b89c 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -134,7 +134,10 @@ enum type_code TYPE_CODE_NAMESPACE, /* C++ namespace. */ - TYPE_CODE_DECFLOAT /* Decimal floating point. */ + TYPE_CODE_DECFLOAT, /* Decimal floating point. */ + + /* Internal function type. */ + TYPE_CODE_INTERNAL_FUNCTION }; /* For now allow source to use TYPE_CODE_CLASS for C++ classes, as an @@ -209,6 +212,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 @@ -266,6 +274,36 @@ enum type_instance_flag_value #define TYPE_NOTTEXT(t) (TYPE_MAIN_TYPE (t)->flag_nottext) +/* 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_ADDRESS copy. 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. */ @@ -352,6 +390,11 @@ struct main_type unsigned int flag_stub_supported : 1; unsigned int flag_nottext : 1; unsigned int flag_fixed_instance : 1; + unsigned int flag_dynamic : 1; + unsigned int flag_range_high_bound_is_count : 1; + unsigned int flag_not_allocated : 1; + unsigned int flag_not_associated : 1; + unsigned int flag_data_location_is_addr : 1; /* Number of fields described for this type. This field appears at this location because it packs nicely here. */ @@ -414,6 +457,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. @@ -795,9 +852,9 @@ extern void allocate_cplus_struct_type (struct type *); #define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type #define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type #define TYPE_CHAIN(thistype) (thistype)->chain -/* Note that if thistype is a TYPEDEF type, you have to call check_typedef. - But check_typedef does set the TYPE_LENGTH of the TYPEDEF type, - so you only have to call check_typedef once. Since allocate_value +/* Note that if thistype is a TYPEDEF, ARRAY or STRING type, you have to call + check_typedef. But check_typedef does set the TYPE_LENGTH of the TYPEDEF + type, so you only have to call check_typedef once. Since allocate_value calls check_typedef, TYPE_LENGTH (VALUE_TYPE (X)) is safe. */ #define TYPE_LENGTH(thistype) (thistype)->length #define TYPE_OBJFILE(thistype) TYPE_MAIN_TYPE(thistype)->objfile @@ -807,23 +864,44 @@ extern void allocate_cplus_struct_type (struct type *); #define TYPE_NFIELDS(thistype) TYPE_MAIN_TYPE(thistype)->nfields #define TYPE_FIELDS(thistype) TYPE_MAIN_TYPE(thistype)->fields #define TYPE_TEMPLATE_ARGS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->template_args +#define TYPE_DATA_LOCATION_DWARF_BLOCK(thistype) TYPE_MAIN_TYPE (thistype)->data_location.dwarf_block +#define TYPE_DATA_LOCATION_ADDR(thistype) TYPE_MAIN_TYPE (thistype)->data_location.addr +#define TYPE_ALLOCATED(thistype) TYPE_MAIN_TYPE (thistype)->allocated +#define TYPE_ASSOCIATED(thistype) TYPE_MAIN_TYPE (thistype)->associated #define TYPE_INDEX_TYPE(type) TYPE_FIELD_TYPE (type, 0) #define TYPE_LOW_BOUND(range_type) TYPE_FIELD_BITPOS (range_type, 0) #define TYPE_HIGH_BOUND(range_type) TYPE_FIELD_BITPOS (range_type, 1) - -/* Moto-specific stuff for FORTRAN arrays */ - -#define TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED(arraytype) \ - (TYPE_FIELD_ARTIFICIAL(TYPE_INDEX_TYPE((arraytype)),1)) +#define TYPE_BYTE_STRIDE(range_type) TYPE_FIELD_BITPOS (range_type, 2) + +/* Whether we should use TYPE_FIELD_DWARF_BLOCK (and not TYPE_FIELD_BITPOS). */ +#define TYPE_RANGE_BOUND_IS_DWARF_BLOCK(range_type, fieldno) \ + (TYPE_FIELD_LOC_KIND (range_type, fieldno) == FIELD_LOC_KIND_DWARF_BLOCK) +#define TYPE_RANGE_BOUND_SET_DWARF_BLOCK(range_type, fieldno) \ + (TYPE_FIELD_LOC_KIND (range_type, fieldno) = FIELD_LOC_KIND_DWARF_BLOCK) +#define TYPE_ARRAY_BOUND_IS_DWARF_BLOCK(array_type, fieldno) \ + TYPE_RANGE_BOUND_IS_DWARF_BLOCK (TYPE_INDEX_TYPE (array_type), fieldno) + +/* Unbound arrays, such as GCC array[]; at end of struct. */ +#define TYPE_RANGE_LOWER_BOUND_IS_UNDEFINED(rangetype) \ + TYPE_FIELD_ARTIFICIAL((rangetype),0) +#define TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED(rangetype) \ + TYPE_FIELD_ARTIFICIAL((rangetype),1) #define TYPE_ARRAY_LOWER_BOUND_IS_UNDEFINED(arraytype) \ - (TYPE_FIELD_ARTIFICIAL(TYPE_INDEX_TYPE((arraytype)),0)) - -#define TYPE_ARRAY_UPPER_BOUND_VALUE(arraytype) \ - (TYPE_HIGH_BOUND(TYPE_INDEX_TYPE((arraytype)))) + TYPE_RANGE_LOWER_BOUND_IS_UNDEFINED (TYPE_INDEX_TYPE (arraytype)) +#define TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED(arraytype) \ + TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (TYPE_INDEX_TYPE (arraytype)) #define TYPE_ARRAY_LOWER_BOUND_VALUE(arraytype) \ - (TYPE_LOW_BOUND(TYPE_INDEX_TYPE((arraytype)))) + TYPE_LOW_BOUND (TYPE_INDEX_TYPE (arraytype)) +#define TYPE_ARRAY_UPPER_BOUND_VALUE(arraytype) \ + TYPE_HIGH_BOUND (TYPE_INDEX_TYPE (arraytype)) +/* TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype)) with a fallback to the + element size if no specific stride value is known. */ +#define TYPE_ARRAY_BYTE_STRIDE_VALUE(arraytype) \ + (TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype)) == 0 \ + ? TYPE_LENGTH (TYPE_TARGET_TYPE (arraytype)) \ + : TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype))) /* C++ */ @@ -1078,6 +1156,16 @@ extern struct type *builtin_type_error; (TYPE_UNSIGNED(t) ? UMIN_OF_SIZE(TYPE_LENGTH(t)) \ : MIN_OF_SIZE(TYPE_LENGTH(t))) +/* Virtual OBJFILE used for builtin types. */ +#define OBJFILE_INTERNAL ((struct objfile *) 1L) + +/* Virtual OBJFILE used for types allocated by malloc. FIXME: Currently + backward compatible with the old NULL value; fix then also init_type. */ +#define OBJFILE_MALLOC ((struct objfile *) 0L) + +#define OBJFILE_IS_VIRTUAL(objfile) ((objfile) == OBJFILE_INTERNAL \ + || (objfile) == OBJFILE_MALLOC) + /* Allocate space for storing data associated with a particular type. We ensure that the space is allocated using the same mechanism that was used to allocate the space for the type structure itself. I.E. @@ -1087,18 +1175,18 @@ extern struct type *builtin_type_error; builtin types), then the data space will be allocated with xmalloc, the same as for the type structure. */ -#define TYPE_ALLOC(t,size) \ - (TYPE_OBJFILE (t) != NULL \ - ? obstack_alloc (&TYPE_OBJFILE (t) -> objfile_obstack, size) \ - : xmalloc (size)) +#define TYPE_ALLOC(t,size) \ + (OBJFILE_IS_VIRTUAL (TYPE_OBJFILE (t)) \ + ? xmalloc (size) \ + : obstack_alloc (&TYPE_OBJFILE (t) -> objfile_obstack, size)) -#define TYPE_ZALLOC(t,size) \ - (TYPE_OBJFILE (t) != NULL \ - ? memset (obstack_alloc (&TYPE_OBJFILE (t)->objfile_obstack, size), \ - 0, size) \ - : xzalloc (size)) +#define TYPE_ZALLOC(t,size) \ + (OBJFILE_IS_VIRTUAL (TYPE_OBJFILE (t)) \ + ? xzalloc (size) \ + : memset (obstack_alloc (&TYPE_OBJFILE (t)->objfile_obstack, size), \ + 0, size)) -extern struct type *alloc_type (struct objfile *); +extern struct type *alloc_type (struct objfile *, struct type *); extern struct type *init_type (enum type_code, int, int, char *, struct objfile *); @@ -1172,6 +1260,18 @@ extern struct type *create_range_type (struct type *, struct type *, int, extern struct type *create_array_type (struct type *, struct type *, struct type *); +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 *); extern struct type *create_set_type (struct type *, struct type *); @@ -1263,10 +1363,15 @@ extern void maintenance_print_type (char *, int); extern htab_t create_copied_types_hash (struct objfile *objfile); -extern struct type *copy_type_recursive (struct objfile *objfile, - struct type *type, +extern struct type *copy_type_recursive (struct type *type, htab_t copied_types); extern struct type *copy_type (const struct type *type); +extern void type_incref (struct type *type); + +extern void type_decref (struct type *type); + +extern void free_all_types (void); + #endif /* GDBTYPES_H */ diff --git a/gdb/gnu-v2-abi.c b/gdb/gnu-v2-abi.c index 7cacac1..a456228 100644 --- a/gdb/gnu-v2-abi.c +++ b/gdb/gnu-v2-abi.c @@ -242,7 +242,7 @@ gnuv2_value_rtti_type (struct value *v, int *full, int *top, int *using_enc) we'd waste a bunch of time figuring out we already know the type. Besides, we don't care about the type, just the actual pointer */ - if (VALUE_ADDRESS (value_field (v, known_type_vptr_fieldno)) == 0) + if (value_address (value_field (v, known_type_vptr_fieldno)) == 0) return NULL; vtbl = value_as_address (value_field (v, known_type_vptr_fieldno)); diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index 3a52df3..6cdf716 100644 --- a/gdb/gnu-v3-abi.c +++ b/gdb/gnu-v3-abi.c @@ -269,8 +269,7 @@ gnuv3_rtti_type (struct value *value, /* Find the linker symbol for this vtable. */ vtable_symbol - = lookup_minimal_symbol_by_pc (VALUE_ADDRESS (vtable) - + value_offset (vtable) + = lookup_minimal_symbol_by_pc (value_address (vtable) + value_embedded_offset (vtable)); if (! vtable_symbol) return NULL; @@ -487,10 +486,8 @@ gnuv3_find_method_in (struct type *domain, CORE_ADDR voffset, LONGEST adjustment) { int i; - const char *physname; /* Search this class first. */ - physname = NULL; if (adjustment == 0) { int len; @@ -615,13 +612,15 @@ gnuv3_print_method_ptr (const gdb_byte *contents, { char *demangled_name = cplus_demangle (physname, DMGL_ANSI | DMGL_PARAMS); - if (demangled_name != NULL) + fprintf_filtered (stream, "&virtual "); + if (demangled_name == NULL) + fputs_filtered (physname, stream); + else { - fprintf_filtered (stream, "&virtual "); fputs_filtered (demangled_name, stream); xfree (demangled_name); - return; } + return; } } diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c index 2366474..f83de32 100644 --- a/gdb/i386-linux-nat.c +++ b/gdb/i386-linux-nat.c @@ -751,7 +751,13 @@ i386_linux_resume (struct target_ops *ops, { int pid = PIDGET (ptid); - int request = PTRACE_CONT; + int request; + + if (target_passed_by_entrypoint () > 0 + && catch_syscall_enabled () > 0) + request = PTRACE_SYSCALL; + else + request = PTRACE_CONT; if (step) { diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c index 1a2e4f0..973eced 100644 --- a/gdb/i386-linux-tdep.c +++ b/gdb/i386-linux-tdep.c @@ -37,6 +37,10 @@ #include "symtab.h" #include "arch-utils.h" #include "regset.h" +#include "linux-tdep.h" + +/* The syscall's XML filename for i386. */ +#define XML_SYSCALL_FILENAME_I386 "syscalls/i386-linux.xml" /* Supported register note sections. */ static struct core_regset_section i386_linux_regset_sections[] = @@ -349,6 +353,26 @@ i386_linux_write_pc (struct regcache *regcache, CORE_ADDR pc) } +static LONGEST +i386_linux_get_syscall_number (struct gdbarch *gdbarch, + ptid_t ptid) +{ + struct regcache *regcache = get_thread_regcache (ptid); + /* The content of a register. */ + gdb_byte buf[4]; + /* The result. */ + LONGEST ret; + + /* Getting the system call number from the register. + When dealing with x86 architecture, this information + is stored at %eax register. */ + regcache_cooked_read (regcache, I386_LINUX_ORIG_EAX_REGNUM, buf); + + ret = extract_signed_integer (buf, 4); + + return ret; +} + /* The register sets used in GNU/Linux ELF core-dumps are identical to the register sets in `struct user' that are used for a.out core-dumps. These are also used by ptrace(2). The corresponding @@ -419,6 +443,9 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + /* Initializing common functions. */ + linux_tdep_init (gdbarch); + /* GNU/Linux uses ELF. */ i386_elf_init_abi (info, gdbarch); @@ -472,6 +499,11 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) displaced_step_at_entry_point); set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); + + /* Functions for 'catch syscall'. */ + set_gdbarch_xml_syscall_filename (gdbarch, XML_SYSCALL_FILENAME_I386); + set_gdbarch_get_syscall_number (gdbarch, + i386_linux_get_syscall_number); } /* Provide a prototype to silence -Wmissing-prototypes. */ diff --git a/gdb/inf-child.c b/gdb/inf-child.c index 38311f1..fc968cf 100644 --- a/gdb/inf-child.c +++ b/gdb/inf-child.c @@ -148,6 +148,15 @@ inf_child_remove_exec_catchpoint (int pid) } static int +inf_child_set_syscall_catchpoint (int pid, int needed, int any_count, + int table_size, int *table) +{ + /* This version of Unix doesn't support notification of syscall + events. */ + return 0; +} + +static int inf_child_can_run (void) { return 1; @@ -190,6 +199,7 @@ inf_child_target (void) t->to_follow_fork = inf_child_follow_fork; t->to_insert_exec_catchpoint = inf_child_insert_exec_catchpoint; t->to_remove_exec_catchpoint = inf_child_remove_exec_catchpoint; + t->to_set_syscall_catchpoint = inf_child_set_syscall_catchpoint; t->to_can_run = inf_child_can_run; t->to_pid_to_exec_file = inf_child_pid_to_exec_file; t->to_stratum = process_stratum; diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c index f40b6b7..ff429c4 100644 --- a/gdb/inf-ptrace.c +++ b/gdb/inf-ptrace.c @@ -356,13 +356,19 @@ inf_ptrace_resume (struct target_ops *ops, ptid_t ptid, int step, enum target_signal signal) { pid_t pid = ptid_get_pid (ptid); - int request = PT_CONTINUE; + int request; if (pid == -1) /* Resume all threads. Traditionally ptrace() only supports single-threaded processes, so simply resume the inferior. */ pid = ptid_get_pid (inferior_ptid); + if (target_passed_by_entrypoint () > 0 + && catch_syscall_enabled () > 0) + request = PT_SYSCALL; + else + request = PT_CONTINUE; + if (step) { /* If this system does not support PT_STEP, a higher level diff --git a/gdb/infcall.c b/gdb/infcall.c index d6da8b2..80168b3 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -98,6 +98,28 @@ Unwinding of stack if a signal is received while in a call dummy is %s.\n"), value); } +/* This boolean tells what gdb should do if a std::terminate call is + made while in a function called from gdb (call dummy). + As the confines of a single dummy stack prohibit out-of-frame + handlers from handling a raised exception, and as out-of-frame + handlers are common in C++, this can lead to no handler being found + by the unwinder, and a std::terminate call. This is a false positive. + If set, gdb unwinds the stack and restores the context to what it + was before the call. + + The default is to unwind the frame if a std::terminate call is made.. */ + +static int unwind_on_terminating_exception_p = 1; +static void +show_unwind_on_terminating_exception_p (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) + +{ + fprintf_filtered (file, _("\ +Unwind stack if a C++ exception is unhandled while in a call dummy is %s.\n"), + value); +} /* Perform the standard coercions that are specified for arguments to be passed to C or Ada functions. @@ -217,7 +239,7 @@ find_function_addr (struct value *function, struct type **retval_type) /* Determine address to call. */ if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD) { - funaddr = VALUE_ADDRESS (function); + funaddr = value_address (function); value_type = TYPE_TARGET_TYPE (ftype); } else if (code == TYPE_CODE_PTR) @@ -419,6 +441,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) struct cleanup *args_cleanup; struct frame_info *frame; struct gdbarch *gdbarch; + struct breakpoint *terminate_bp = 0; + struct minimal_symbol *tm; ptid_t call_thread_ptid; struct gdb_exception e; const char *name; @@ -718,6 +742,29 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) bpt = set_momentary_breakpoint (sal, dummy_id, bp_call_dummy); bpt->disposition = disp_del; } + + /* Create a breakpoint in std::terminate. + If a C++ exception is raised in the dummy-frame, and the + exception handler is (normally, and expected to be) out-of-frame, + the default C++ handler will (wrongly) be called in an inferior + function call. This is wrong, as an exception can be normally + and legally handled out-of-frame. The confines of the dummy frame + prevent the unwinder from finding the correct handler (or any + handler, unless it is in-frame). The default handler calls + std::terminate. This will kill the inferior. Assert that + terminate should never be called in an inferior function + call. Place a momentary breakpoint in the std::terminate function + and if triggered in the call, rewind */ + if (unwind_on_terminating_exception_p) + { + tm = lookup_minimal_symbol ("std::terminate()", NULL, NULL); + if (tm != NULL) + { + terminate_bp = set_momentary_breakpoint_at_pc + (SYMBOL_VALUE_ADDRESS (tm), bp_breakpoint); + make_cleanup_delete_breakpoint (terminate_bp); + } + } /* Everything's ready, push all the info needed to restore the caller (and identify the dummy-frame) onto the dummy-frame @@ -828,6 +875,16 @@ When the function is done executing, GDB will silently stop."), name); } + if (! target_has_execution) + { + /* If we try to restore the inferior status (via the cleanup), + we'll crash as the inferior is no longer running. */ + discard_cleanups (inf_status_cleanup); + discard_inferior_status (inf_status); + error (_("\ +The program being debugged exited while in a function called from GDB.")); + } + if (stopped_by_random_signal || !stop_stack_dummy) { const char *name = get_function_name (funaddr, @@ -884,6 +941,38 @@ When the function is done executing, GDB will silently stop."), if (!stop_stack_dummy) { + + /* Check if unwind on terminating exception behaviour is on */ + if (unwind_on_terminating_exception_p) + { + /* Check that the breakpoint is our special std::terminate + breakpoint. If it is, we do not want to kill the inferior + in an inferior function call. Rewind, and warn the user */ + + if ((terminate_bp != NULL) && + (inferior_thread()->stop_bpstat->breakpoint_at->address + == terminate_bp->loc->address)) + + + { + + /* We must get back to the frame we were before the + dummy call. */ + dummy_frame_pop (dummy_id); + + /* We also need to restore inferior status to that before the + dummy call. */ + restore_inferior_status (inf_status); + + error (_("\ +The program being debugged entered a std::terminate call which would\n\ +have terminated the program being debugged. GDB has restored the\n\ +context to what it was before the call\n\ +To change this behaviour use \"set unwind-on-terminating-exception off\"\n\ +Evaluation of the expression containing the function (%s) will be abandoned."), + name); + } + } /* We hit a breakpoint inside the FUNCTION. Keep the dummy frame, the user may want to examine its state. Discard inferior status, we're not at the same point @@ -992,4 +1081,19 @@ The default is to stop in the frame where the signal was received."), NULL, show_unwind_on_signal_p, &setlist, &showlist); + + add_setshow_boolean_cmd ("unwind-on-terminating-exception", no_class, + &unwind_on_terminating_exception_p, _("\ +Set unwinding of stack if a std::terminate() call originates from\n\ +the default C++ exception handler."), _("\ +Show unwinding of stack if a std::terminate() call originates from\n\ +the default C++ exception handler."), _("\ +The unwind on terminating exception flag lets the user determine\n\ +what gdb should do if a std::terminate() call is made from the\n\ +default exception handler.\n\ +The default is to unwind the frame."), + NULL, + show_unwind_on_terminating_exception_p, + &setlist, &showlist); + } diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 0a17dab..d48f4b1 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -466,6 +466,11 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main) init_wait_for_inferior (); clear_breakpoint_hit_counts (); + /* If we already caught a syscall catchpoint, then reset its + syscall_number information because we are starting all over + again. */ + clear_syscall_catchpoints_info (); + /* Clean up any leftovers from other runs. Some other things from this function should probably be moved into target_pre_inferior. */ target_pre_inferior (from_tty); diff --git a/gdb/infrun.c b/gdb/infrun.c index ee5f987..2f627ea 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1046,7 +1046,7 @@ a command like `return' or `jump' to continue execution.")); } } - /* If there were any forks/vforks/execs that were caught and are + /* If there were any forks/vforks/execs/syscalls that were caught and are now to be followed, then do so. */ switch (pending_follow.kind) { @@ -1069,6 +1069,11 @@ a command like `return' or `jump' to continue execution.")); pending_follow.kind = TARGET_WAITKIND_SPURIOUS; break; + case TARGET_WAITKIND_SYSCALL_ENTRY: + case TARGET_WAITKIND_SYSCALL_RETURN: + pending_follow.kind = TARGET_WAITKIND_SPURIOUS; + break; + default: break; } @@ -1509,7 +1514,7 @@ init_wait_for_inferior (void) breakpoint_init_inferior (inf_starting); - /* The first resume is not following a fork/vfork/exec. */ + /* The first resume is not following a fork/vfork/exec/syscall. */ pending_follow.kind = TARGET_WAITKIND_SPURIOUS; /* I.e., none. */ clear_proceed_status (); @@ -2155,6 +2160,50 @@ ensure_not_running (void) error_is_running (); } +/* Auxiliary function that handles syscall entry/return events. + It returns 1 if the inferior should keep going (and GDB + should ignore the event), or 0 if the event deserves to be + processed. */ +static int +deal_with_syscall_event (struct execution_control_state *ecs) +{ + int syscall_number = gdbarch_get_syscall_number (current_gdbarch, + ecs->ptid); + if (catch_syscall_enabled () > 0 + && catching_syscall_number (syscall_number) > 0) + { + ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP; + pending_follow.kind = ecs->ws.kind; + + if (!ptid_equal (ecs->ptid, inferior_ptid)) + { + context_switch (ecs->ptid); + reinit_frame_cache (); + } + + stop_pc = read_pc (); + + ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); + + ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat); + + /* If no catchpoint triggered for this, then keep going. */ + if (ecs->random_signal) + { + ecs->event_thread->stop_signal = TARGET_SIGNAL_0; + keep_going (ecs); + return 1; + } + return 0; + } + else + { + resume (0, TARGET_SIGNAL_0); + prepare_to_wait (ecs); + return 1; + } +} + /* Given an execution control state that has been freshly filled in by an event from the inferior, figure out what it means and take appropriate action. */ @@ -2449,9 +2498,11 @@ handle_inferior_event (struct execution_control_state *ecs) case TARGET_WAITKIND_SYSCALL_ENTRY: if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n"); - resume (0, TARGET_SIGNAL_0); - prepare_to_wait (ecs); - return; + /* Getting the current syscall number */ + if (deal_with_syscall_event (ecs) != 0) + return; + goto process_event_stop_test; + break; /* Before examining the threads further, step this thread to get it entirely out of the syscall. (We get notice of the @@ -2461,9 +2512,10 @@ handle_inferior_event (struct execution_control_state *ecs) case TARGET_WAITKIND_SYSCALL_RETURN: if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n"); - target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); - prepare_to_wait (ecs); - return; + if (deal_with_syscall_event (ecs) != 0) + return; + goto process_event_stop_test; + break; case TARGET_WAITKIND_STOPPED: if (debug_infrun) @@ -5166,6 +5218,25 @@ inferior_has_execd (ptid_t pid, char **execd_pathname) return 1; } +int +inferior_has_called_syscall (ptid_t pid, int *syscall_number) +{ + struct target_waitstatus last; + ptid_t last_ptid; + + get_last_target_status (&last_ptid, &last); + + if (last.kind != TARGET_WAITKIND_SYSCALL_ENTRY && + last.kind != TARGET_WAITKIND_SYSCALL_RETURN) + return 0; + + if (!ptid_equal (last_ptid, pid)) + return 0; + + *syscall_number = last.value.syscall_number; + return 1; +} + /* Oft used ptids */ ptid_t null_ptid; ptid_t minus_one_ptid; diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c index b702ebf..a211adf 100644 --- a/gdb/jv-lang.c +++ b/gdb/jv-lang.c @@ -61,7 +61,8 @@ static char *get_java_utf8_name (struct obstack *obstack, struct value *name); static int java_class_is_primitive (struct value *clas); static struct value *java_value_string (char *ptr, int len); -static void java_emit_char (int c, struct ui_file * stream, int quoter); +static void java_emit_char (int c, struct type *type, + struct ui_file * stream, int quoter); static char *java_class_name_from_physname (const char *physname); @@ -210,8 +211,7 @@ get_java_utf8_name (struct obstack *obstack, struct value *name) CORE_ADDR data_addr; temp = value_struct_elt (&temp, NULL, "length", NULL, "structure"); name_length = (int) value_as_long (temp); - data_addr = VALUE_ADDRESS (temp) + value_offset (temp) - + TYPE_LENGTH (value_type (temp)); + data_addr = value_address (temp) + TYPE_LENGTH (value_type (temp)); chrs = obstack_alloc (obstack, name_length + 1); chrs[name_length] = '\0'; read_memory (data_addr, (gdb_byte *) chrs, name_length); @@ -266,7 +266,7 @@ type_from_class (struct value *clas) return NULL; clas = value_ind (clas); } - addr = VALUE_ADDRESS (clas) + value_offset (clas); + addr = value_address (clas); #if 0 get_java_class_symtab (); @@ -302,7 +302,7 @@ type_from_class (struct value *clas) if (type != NULL) return type; - type = alloc_type (objfile); + type = alloc_type (objfile, NULL); TYPE_CODE (type) = TYPE_CODE_STRUCT; INIT_CPLUS_SPECIFIC (type); @@ -422,7 +422,7 @@ java_link_class_type (struct type *type, struct value *clas) fields = NULL; nfields--; /* First set up dummy "class" field. */ SET_FIELD_PHYSADDR (TYPE_FIELD (type, nfields), - VALUE_ADDRESS (clas) + value_offset (clas)); + value_address (clas)); TYPE_FIELD_NAME (type, nfields) = "class"; TYPE_FIELD_TYPE (type, nfields) = value_type (clas); SET_TYPE_FIELD_PRIVATE (type, nfields); @@ -439,7 +439,9 @@ java_link_class_type (struct type *type, struct value *clas) } else { /* Re-use field value for next field. */ - VALUE_ADDRESS (field) += TYPE_LENGTH (value_type (field)); + CORE_ADDR addr + = value_address (field) + TYPE_LENGTH (value_type (field)); + set_value_address (field, addr); set_value_lazy (field, 1); } temp = field; @@ -509,7 +511,9 @@ java_link_class_type (struct type *type, struct value *clas) } else { /* Re-use method value for next method. */ - VALUE_ADDRESS (method) += TYPE_LENGTH (value_type (method)); + CORE_ADDR addr + = value_address (method) + TYPE_LENGTH (value_type (method)); + set_value_address (method, addr); set_value_lazy (method, 1); } @@ -796,7 +800,7 @@ java_value_string (char *ptr, int len) characters and strings is language specific. */ static void -java_emit_char (int c, struct ui_file *stream, int quoter) +java_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) { switch (c) { diff --git a/gdb/jv-valprint.c b/gdb/jv-valprint.c index d3606fd..cdcb440 100644 --- a/gdb/jv-valprint.c +++ b/gdb/jv-valprint.c @@ -45,7 +45,7 @@ java_value_print (struct value *val, struct ui_file *stream, struct value_print_options opts; type = value_type (val); - address = VALUE_ADDRESS (val) + value_offset (val); + address = value_address (val); if (is_object_type (type)) { @@ -143,8 +143,8 @@ java_value_print (struct value *val, struct ui_file *stream, struct value *v = allocate_value (el_type); struct value *next_v = allocate_value (el_type); - VALUE_ADDRESS (v) = address + JAVA_OBJECT_SIZE + 4; - VALUE_ADDRESS (next_v) = VALUE_ADDRESS (v); + set_value_address (v, address + JAVA_OBJECT_SIZE + 4); + set_value_address (next_v, value_raw_address (v)); while (i < length && things_printed < options->print_max) { @@ -230,7 +230,7 @@ java_value_print (struct value *val, struct ui_file *stream, value_free_to_mark (mark); /* Release unnecessary values */ - val_print_string (data + boffset, count, 2, stream, options); + val_print_string (java_char_type, data + boffset, count, stream, options); return 0; } @@ -520,7 +520,7 @@ java_val_print (struct type *type, const gdb_byte *valaddr, || (TYPE_CODE (type) == TYPE_CODE_INT && TYPE_LENGTH (type) == 2 && strcmp (TYPE_NAME (type), "char") == 0)) - LA_PRINT_CHAR ((int) unpack_long (type, valaddr), stream); + LA_PRINT_CHAR ((int) unpack_long (type, valaddr), type, stream); else val_print_type_code_int (type, valaddr, stream); break; diff --git a/gdb/language.c b/gdb/language.c index 3c37a64..6209d7f 100644 --- a/gdb/language.c +++ b/gdb/language.c @@ -65,9 +65,11 @@ static void set_check (char *, int); static void set_type_range_case (void); -static void unk_lang_emit_char (int c, struct ui_file *stream, int quoter); +static void unk_lang_emit_char (int c, struct type *type, + struct ui_file *stream, int quoter); -static void unk_lang_printchar (int c, struct ui_file *stream); +static void unk_lang_printchar (int c, struct type *type, + struct ui_file *stream); static void unk_lang_print_type (struct type *, char *, struct ui_file *, int, int); @@ -1065,20 +1067,22 @@ unk_lang_error (char *msg) } static void -unk_lang_emit_char (int c, struct ui_file *stream, int quoter) +unk_lang_emit_char (int c, struct type *type, struct ui_file *stream, + int quoter) { error (_("internal error - unimplemented function unk_lang_emit_char called.")); } static void -unk_lang_printchar (int c, struct ui_file *stream) +unk_lang_printchar (int c, struct type *type, struct ui_file *stream) { error (_("internal error - unimplemented function unk_lang_printchar called.")); } static void -unk_lang_printstr (struct ui_file *stream, const gdb_byte *string, - unsigned int length, int width, int force_ellipses, +unk_lang_printstr (struct ui_file *stream, struct type *type, + const gdb_byte *string, unsigned int length, + int force_ellipses, const struct value_print_options *options) { error (_("internal error - unimplemented function unk_lang_printstr called.")); diff --git a/gdb/language.h b/gdb/language.h index 85826fd..e5f80ab 100644 --- a/gdb/language.h +++ b/gdb/language.h @@ -186,14 +186,15 @@ struct language_defn void (*la_post_parser) (struct expression ** expp, int void_context_p); - void (*la_printchar) (int ch, struct ui_file * stream); + void (*la_printchar) (int ch, struct type *chtype, struct ui_file * stream); - void (*la_printstr) (struct ui_file * stream, const gdb_byte *string, - unsigned int length, int width, + void (*la_printstr) (struct ui_file * stream, struct type *elttype, + const gdb_byte *string, unsigned int length, int force_ellipses, const struct value_print_options *); - void (*la_emitchar) (int ch, struct ui_file * stream, int quoter); + void (*la_emitchar) (int ch, struct type *chtype, + struct ui_file * stream, int quoter); /* Print a type using syntax appropriate for this language. */ @@ -381,13 +382,13 @@ extern enum language set_language (enum language); #define LA_VALUE_PRINT(val,stream,options) \ (current_language->la_value_print(val,stream,options)) -#define LA_PRINT_CHAR(ch, stream) \ - (current_language->la_printchar(ch, stream)) -#define LA_PRINT_STRING(stream, string, length, width, force_ellipses,options) \ - (current_language->la_printstr(stream, string, length, width, \ +#define LA_PRINT_CHAR(ch, type, stream) \ + (current_language->la_printchar(ch, type, stream)) +#define LA_PRINT_STRING(stream, elttype, string, length, force_ellipses,options) \ + (current_language->la_printstr(stream, elttype, string, length, \ force_ellipses,options)) -#define LA_EMIT_CHAR(ch, stream, quoter) \ - (current_language->la_emitchar(ch, stream, quoter)) +#define LA_EMIT_CHAR(ch, type, stream, quoter) \ + (current_language->la_emitchar(ch, type, stream, quoter)) #define LA_GET_STRING(value, buffer, length, encoding) \ (current_language->la_get_string(value, buffer, length, encoding)) diff --git a/gdb/linespec.c b/gdb/linespec.c index 6579d42..b3ae6c0 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -842,13 +842,33 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab, } else if (paren_pointer != NULL) { - p = paren_pointer + 1; + /* We need to deal with method and function overloads + with no parameters. Gdb and gcc (and who knows about other + compilers) are very inconsistent with the keyword "void". + Canonicalizing C++ types is insufficient in this case, since + we still need to enforce the presence (or lack thereof) of + "void". For simplicity, omit the keyword "void" if present. */ + if (strncmp (paren_pointer - 5, "(void)", 6) == 0) + { + char *a, *b; + a = paren_pointer - 4; + b = paren_pointer; + while ((*(a++) = *(b++)) != '\0') ; + *a = '\0'; + p = paren_pointer - 3; + } + else + p = paren_pointer + 1; } else { p = skip_quoted (*argptr); } + /* Make sure we keep important kewords like "const" */ + if (strncmp (p, " const", 6) == 0) + p += 6; + copy = (char *) alloca (p - *argptr + 1); memcpy (copy, *argptr, p - *argptr); copy[p - *argptr] = '\0'; diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 12b786e..e30bf9a 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -61,6 +61,10 @@ # endif #endif /* HAVE_PERSONALITY */ +/* To be used when one needs to know wether a + WSTOPSIG (status) is a syscall */ +#define TRAP_IS_SYSCALL (SIGTRAP | 0x80) + /* This comment documents high-level logic of this file. Waiting for events in sync mode @@ -281,17 +285,29 @@ struct simple_pid_list *stopped_pids; static int linux_supports_tracefork_flag = -1; +/* This variable is a tri-state flag: -1 for unknown, 0 if PTRACE_O_TRACESYSGOOD + can not be used, 1 if it can. */ + +static int linux_supports_tracesysgood_flag = -1; + /* If we have PTRACE_O_TRACEFORK, this flag indicates whether we also have PTRACE_O_TRACEVFORKDONE. */ static int linux_supports_tracevforkdone_flag = -1; +/* If the inferior have passed through its entrypoint (AT_ENTRY), + then this flag is set to 1. Otherwise, its value is 0. */ +static int linux_passed_by_entrypoint_flag = 0; + /* Async mode support */ /* Zero if the async mode, although enabled, is masked, which means linux_nat_wait should behave as if async mode was off. */ static int linux_nat_async_mask_value = 1; +/* Stores the current used ptrace() options. */ +static int current_ptrace_options = 0; + /* The read/write ends of the pipe registered as waitable file in the event loop. */ static int linux_nat_event_pipe[2] = { -1, -1 }; @@ -636,6 +652,41 @@ linux_test_for_tracefork (int original_pid) linux_nat_async_events (async_events_original_state); } +/* Determine if PTRACE_O_TRACESYSGOOD can be used to follow syscalls. + + We try to enable syscall tracing on ORIGINAL_PID. If this fails, + we know that the feature is not available. This may change the tracing + options for ORIGINAL_PID, but we'll be setting them shortly anyway. */ + +static void +linux_test_for_tracesysgood (int original_pid) +{ + int ret; + enum sigchld_state async_events_original_state; + + async_events_original_state = linux_nat_async_events (sigchld_sync); + + linux_supports_tracesysgood_flag = 0; + + ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACESYSGOOD); + if (ret != 0) + return; + + linux_supports_tracesysgood_flag = 1; + linux_nat_async_events (async_events_original_state); +} + +/* Determine wether we support PTRACE_O_TRACESYSGOOD option available. + This function also sets linux_supports_tracesysgood_flag. */ + +static int +linux_supports_tracesysgood (int pid) +{ + if (linux_supports_tracesysgood_flag == -1) + linux_test_for_tracesysgood (pid); + return linux_supports_tracesysgood_flag; +} + /* Return non-zero iff we have tracefork functionality available. This function also sets linux_supports_tracefork_flag. */ @@ -655,12 +706,34 @@ linux_supports_tracevforkdone (int pid) return linux_supports_tracevforkdone_flag; } +static void +linux_enable_tracesysgood (ptid_t ptid) +{ + int pid = ptid_get_lwp (ptid); + + if (pid == 0) + pid = ptid_get_pid (ptid); + + if (linux_supports_tracesysgood (pid) == 0) + return; + + current_ptrace_options |= PTRACE_O_TRACESYSGOOD; + linux_passed_by_entrypoint_flag = 1; + + ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options); +} + +static int +linux_passed_by_entrypoint (void) +{ + return linux_passed_by_entrypoint_flag; +} + void linux_enable_event_reporting (ptid_t ptid) { int pid = ptid_get_lwp (ptid); - int options; if (pid == 0) pid = ptid_get_pid (ptid); @@ -668,15 +741,16 @@ linux_enable_event_reporting (ptid_t ptid) if (! linux_supports_tracefork (pid)) return; - options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC - | PTRACE_O_TRACECLONE; + current_ptrace_options |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK + | PTRACE_O_TRACEEXEC | PTRACE_O_TRACECLONE; + if (linux_supports_tracevforkdone (pid)) - options |= PTRACE_O_TRACEVFORKDONE; + current_ptrace_options |= PTRACE_O_TRACEVFORKDONE; /* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to support read-only process state. */ - ptrace (PTRACE_SETOPTIONS, pid, 0, options); + ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options); } static void @@ -684,6 +758,7 @@ linux_child_post_attach (int pid) { linux_enable_event_reporting (pid_to_ptid (pid)); check_for_thread_db (); + linux_enable_tracesysgood (pid_to_ptid (pid)); } static void @@ -691,6 +766,7 @@ linux_child_post_startup_inferior (ptid_t ptid) { linux_enable_event_reporting (ptid); check_for_thread_db (); + linux_enable_tracesysgood (ptid); } static int @@ -931,6 +1007,16 @@ linux_child_insert_exec_catchpoint (int pid) error (_("Your system does not support exec catchpoints.")); } +static int +linux_child_set_syscall_catchpoint (int pid, int needed, int any_count, + int table_size, int *table) +{ + if (! linux_supports_tracesysgood (pid)) + error (_("Your system does not support syscall catchpoints.")); + /* We ignore the arguments. */ + return 0; +} + /* On GNU/Linux there are no real LWP's. The closest thing to LWP's are processes sharing the same VM space. A multi-threaded process is basically a group of such processes. However, such a grouping @@ -1352,6 +1438,9 @@ linux_nat_create_inferior (struct target_ops *ops, int personality_orig = 0, personality_set = 0; #endif /* HAVE_PERSONALITY */ + /* We are sarting, so we still have not passed through our entrypoint. */ + linux_passed_by_entrypoint_flag = 0; + /* The fork_child mechanism is synchronous and calls target_wait, so we have to mask the async mode. */ @@ -1996,6 +2085,26 @@ linux_handle_extended_wait (struct lwp_info *lp, int status, return 0; } + /* Used for 'catch syscall' feature. */ + if (WSTOPSIG (status) == TRAP_IS_SYSCALL) + { + if (catch_syscall_enabled () == 0) + ourstatus->kind = TARGET_WAITKIND_IGNORE; + else + { + struct regcache *regcache = get_thread_regcache (lp->ptid); + struct gdbarch *gdbarch = get_regcache_arch (regcache); + + ourstatus->kind = + (lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY) ? + TARGET_WAITKIND_SYSCALL_RETURN : TARGET_WAITKIND_SYSCALL_ENTRY; + lp->syscall_state = ourstatus->kind; + ourstatus->value.syscall_number = + (int) gdbarch_get_syscall_number (gdbarch, lp->ptid); + } + return 0; + } + internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event); } @@ -2606,11 +2715,16 @@ linux_nat_filter_event (int lwpid, int status, int options) } /* Save the trap's siginfo in case we need it later. */ - if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP) + if (WIFSTOPPED (status) + && (WSTOPSIG (status) == SIGTRAP || WSTOPSIG (status) == TRAP_IS_SYSCALL)) save_siginfo (lp); - /* Handle GNU/Linux's extended waitstatus for trace events. */ - if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) + /* Handle GNU/Linux's extended waitstatus for trace events. + It is necessary to check if WSTOPSIG is signaling a that + the inferior is entering/exiting a system call. */ + if (WIFSTOPPED (status) + && ((WSTOPSIG (status) == TRAP_IS_SYSCALL) + || (WSTOPSIG (status) == SIGTRAP && status >> 16 != 0))) { if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, @@ -4262,12 +4376,14 @@ linux_target_install_ops (struct target_ops *t) t->to_insert_fork_catchpoint = linux_child_insert_fork_catchpoint; t->to_insert_vfork_catchpoint = linux_child_insert_vfork_catchpoint; t->to_insert_exec_catchpoint = linux_child_insert_exec_catchpoint; + t->to_set_syscall_catchpoint = linux_child_set_syscall_catchpoint; t->to_pid_to_exec_file = linux_child_pid_to_exec_file; t->to_post_startup_inferior = linux_child_post_startup_inferior; t->to_post_attach = linux_child_post_attach; t->to_follow_fork = linux_child_follow_fork; t->to_find_memory_regions = linux_nat_find_memory_regions; t->to_make_corefile_notes = linux_nat_make_corefile_notes; + t->to_passed_by_entrypoint = linux_passed_by_entrypoint; super_xfer_partial = t->to_xfer_partial; t->to_xfer_partial = linux_xfer_partial; diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h index fec5139..36d2439 100644 --- a/gdb/linux-nat.h +++ b/gdb/linux-nat.h @@ -70,6 +70,13 @@ struct lwp_info or to a local variable in lin_lwp_wait. */ struct target_waitstatus waitstatus; + /* Signal wether we are in a SYSCALL_ENTRY or + in a SYSCALL_RETURN event. + Values: + - TARGET_WAITKIND_SYSCALL_ENTRY + - TARGET_WAITKIND_SYSCALL_RETURN */ + int syscall_state; + /* Next LWP in list. */ struct lwp_info *next; }; diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index e18e134..d44b505 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -20,6 +20,8 @@ #include "defs.h" #include "gdbtypes.h" #include "linux-tdep.h" +#include "xml-syscall.h" +#include "target.h" /* This function is suitable for architectures that don't extend/override the standard siginfo structure. */ @@ -137,3 +139,81 @@ linux_get_siginfo_type (struct gdbarch *gdbarch) return siginfo_type; } + +/* Structure used to store information about the available syscalls in + the system. */ +static const struct syscalls_info *sysinfo = NULL; + +/* A flag to tell if we already initialized the structure above. */ +static int have_initialized_sysinfo = 0; + +/* The filename of the syscall's XML. */ +static const char *xml_syscall_file = NULL; + +/* Initializes the syscalls_info structure according to the + architecture. */ +static void +init_sysinfo (struct gdbarch *gdbarch) +{ + /* Did we already try to initialize the structure? */ + if (have_initialized_sysinfo) + return; + + if (xml_syscall_file == NULL) + xml_syscall_file = gdbarch_xml_syscall_filename (gdbarch); + + sysinfo = xml_init_syscalls_info (xml_syscall_file); + + have_initialized_sysinfo = 1; + + if (sysinfo == NULL) + { + if (xml_syscall_file) + /* The initialization failed. Let's show a warning + message to the user (just this time) and leave. */ + warning (_("Could not load the syscall XML file '%s'.\n\ +GDB will not be able to display syscall names."), xml_syscall_file); + else + /* There's no file to open. Let's warn the user. */ + warning (_("There is no XML file to open.\n\ +GDB will not be able to display syscall names.")); + } +} + +static void +linux_get_syscall_by_number (struct gdbarch *gdbarch, + int syscall_number, + struct syscall *s) +{ + init_sysinfo (gdbarch); + + s->number = syscall_number; + s->name = xml_get_syscall_name (sysinfo, syscall_number); +} + +static void +linux_get_syscall_by_name (struct gdbarch *gdbarch, + const char *syscall_name, + struct syscall *s) +{ + init_sysinfo (gdbarch); + + s->number = xml_get_syscall_number (sysinfo, syscall_name); + s->name = syscall_name; +} + +static const char ** +linux_get_syscall_names (struct gdbarch *gdbarch) +{ + init_sysinfo (gdbarch); + + return xml_list_of_syscalls (sysinfo); +} + +void +linux_tdep_init (struct gdbarch *gdbarch) +{ + set_gdbarch_get_syscall_by_number (gdbarch, linux_get_syscall_by_number); + set_gdbarch_get_syscall_by_name (gdbarch, linux_get_syscall_by_name); + set_gdbarch_get_syscall_names (gdbarch, linux_get_syscall_names); +} diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h index 50af511..1e1e541 100644 --- a/gdb/linux-tdep.h +++ b/gdb/linux-tdep.h @@ -22,4 +22,6 @@ struct type *linux_get_siginfo_type (struct gdbarch *); +extern void linux_tdep_init (struct gdbarch *gdbarch); + #endif /* linux-tdep.h */ diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c index 9e4bb1b..9ca3ae1 100644 --- a/gdb/m2-lang.c +++ b/gdb/m2-lang.c @@ -29,8 +29,8 @@ #include "valprint.h" extern void _initialize_m2_language (void); -static void m2_printchar (int, struct ui_file *); -static void m2_emit_char (int, struct ui_file *, int); +static void m2_printchar (int, struct type *, struct ui_file *); +static void m2_emit_char (int, struct type *, struct ui_file *, int); /* Print the character C on STREAM as part of the contents of a literal string whose delimiter is QUOTER. Note that that format for printing @@ -39,7 +39,7 @@ static void m2_emit_char (int, struct ui_file *, int); be replaced with a true Modula version. */ static void -m2_emit_char (int c, struct ui_file *stream, int quoter) +m2_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) { c &= 0xFF; /* Avoid sign bit follies */ @@ -88,10 +88,10 @@ m2_emit_char (int c, struct ui_file *stream, int quoter) be replaced with a true Modula version. */ static void -m2_printchar (int c, struct ui_file *stream) +m2_printchar (int c, struct type *type, struct ui_file *stream) { fputs_filtered ("'", stream); - LA_EMIT_CHAR (c, stream, '\''); + LA_EMIT_CHAR (c, type, stream, '\''); fputs_filtered ("'", stream); } @@ -103,14 +103,15 @@ m2_printchar (int c, struct ui_file *stream) be replaced with a true Modula version. */ static void -m2_printstr (struct ui_file *stream, const gdb_byte *string, - unsigned int length, int width, int force_ellipses, +m2_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string, + unsigned int length, int force_ellipses, const struct value_print_options *options) { unsigned int i; unsigned int things_printed = 0; int in_quotes = 0; int need_comma = 0; + int width = TYPE_LENGTH (type); if (length == 0) { @@ -152,7 +153,7 @@ m2_printstr (struct ui_file *stream, const gdb_byte *string, fputs_filtered ("\", ", stream); in_quotes = 0; } - m2_printchar (string[i], stream); + m2_printchar (string[i], type, stream); fprintf_filtered (stream, " ", reps); i = rep1 - 1; things_printed += options->repeat_count_threshold; @@ -168,7 +169,7 @@ m2_printstr (struct ui_file *stream, const gdb_byte *string, fputs_filtered ("\"", stream); in_quotes = 1; } - LA_EMIT_CHAR (string[i], stream, '"'); + LA_EMIT_CHAR (string[i], type, stream, '"'); ++things_printed; } } diff --git a/gdb/m2-valprint.c b/gdb/m2-valprint.c index 71c410c..41fb8fe 100644 --- a/gdb/m2-valprint.c +++ b/gdb/m2-valprint.c @@ -237,7 +237,8 @@ print_unpacked_pointer (struct type *type, && TYPE_CODE (elttype) == TYPE_CODE_INT && (options->format == 0 || options->format == 's') && addr != 0) - return val_print_string (addr, -1, TYPE_LENGTH (elttype), stream, options); + return val_print_string (TYPE_TARGET_TYPE (type), addr, -1, + stream, options); return 0; } @@ -294,7 +295,7 @@ m2_print_array_contents (struct type *type, const gdb_byte *valaddr, || ((current_language->la_language == language_m2) && (TYPE_CODE (type) == TYPE_CODE_CHAR))) && (options->format == 0 || options->format == 's')) - val_print_string (address, len+1, eltlen, stream, options); + val_print_string (type, address, len+1, stream, options); else { fprintf_filtered (stream, "{"); @@ -359,7 +360,8 @@ m2_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, len = temp_len; } - LA_PRINT_STRING (stream, valaddr + embedded_offset, len, 1, 0, + LA_PRINT_STRING (stream, TYPE_TARGET_TYPE (type), + valaddr + embedded_offset, len, 0, options); i = len; } @@ -547,7 +549,7 @@ m2_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, else fprintf_filtered (stream, "%d", (int) val); fputs_filtered (" ", stream); - LA_PRINT_CHAR ((unsigned char) val, stream); + LA_PRINT_CHAR ((unsigned char) val, type, stream); } break; diff --git a/gdb/m32r-tdep.c b/gdb/m32r-tdep.c index 5f4b9a6..eccfe31 100644 --- a/gdb/m32r-tdep.c +++ b/gdb/m32r-tdep.c @@ -713,7 +713,7 @@ m32r_push_dummy_call (struct gdbarch *gdbarch, struct value *function, if (len > 8 && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)) { - store_unsigned_integer (valbuf, 4, VALUE_ADDRESS (args[argnum])); + store_unsigned_integer (valbuf, 4, value_address (args[argnum])); typecode = TYPE_CODE_PTR; len = 4; val = valbuf; diff --git a/gdb/macroexp.c b/gdb/macroexp.c index f0a8c1f..752a939 100644 --- a/gdb/macroexp.c +++ b/gdb/macroexp.c @@ -23,6 +23,7 @@ #include "macrotab.h" #include "macroexp.h" #include "gdb_assert.h" +#include "c-lang.h" @@ -320,14 +321,17 @@ get_character_constant (struct macro_buffer *tok, char *p, char *end) way GDB's C/C++ lexer does. So we call parse_escape in utils.c to handle escape sequences. */ if ((p + 1 <= end && *p == '\'') - || (p + 2 <= end && p[0] == 'L' && p[1] == '\'')) + || (p + 2 <= end + && (p[0] == 'L' || p[0] == 'u' || p[0] == 'U') + && p[1] == '\'')) { char *tok_start = p; char *body_start; + int char_count = 0; if (*p == '\'') p++; - else if (*p == 'L') + else if (*p == 'L' || *p == 'u' || *p == 'U') p += 2; else gdb_assert (0); @@ -339,7 +343,7 @@ get_character_constant (struct macro_buffer *tok, char *p, char *end) error (_("Unmatched single quote.")); else if (*p == '\'') { - if (p == body_start) + if (!char_count) error (_("A character constant must contain at least one " "character.")); p++; @@ -348,10 +352,13 @@ get_character_constant (struct macro_buffer *tok, char *p, char *end) else if (*p == '\\') { p++; - parse_escape (&p); + char_count += c_parse_escape (&p, NULL); } else - p++; + { + p++; + char_count++; + } } set_token (tok, tok_start, p); @@ -370,16 +377,16 @@ static int get_string_literal (struct macro_buffer *tok, char *p, char *end) { if ((p + 1 <= end - && *p == '\"') + && *p == '"') || (p + 2 <= end - && p[0] == 'L' - && p[1] == '\"')) + && (p[0] == 'L' || p[0] == 'u' || p[0] == 'U') + && p[1] == '"')) { char *tok_start = p; - if (*p == '\"') + if (*p == '"') p++; - else if (*p == 'L') + else if (*p == 'L' || *p == 'u' || *p == 'U') p += 2; else gdb_assert (0); @@ -388,7 +395,7 @@ get_string_literal (struct macro_buffer *tok, char *p, char *end) { if (p >= end) error (_("Unterminated string in expression.")); - else if (*p == '\"') + else if (*p == '"') { p++; break; @@ -399,7 +406,7 @@ get_string_literal (struct macro_buffer *tok, char *p, char *end) else if (*p == '\\') { p++; - parse_escape (&p); + c_parse_escape (&p, NULL); } else p++; diff --git a/gdb/main.c b/gdb/main.c index 5d4640b..6f9e61b 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -40,6 +40,8 @@ #include "interps.h" #include "main.h" +#include "python/python.h" + /* If nonzero, display time usage both at startup and for each command. */ int display_time; @@ -62,6 +64,9 @@ int dbx_commands = 0; /* System root path, used to find libraries etc. */ char *gdb_sysroot = 0; +/* GDB datadir, used to store data files. */ +char *gdb_datadir = 0; + struct ui_file *gdb_stdout; struct ui_file *gdb_stderr; struct ui_file *gdb_stdlog; @@ -211,6 +216,8 @@ captured_main (void *data) char *cdarg = NULL; char *ttyarg = NULL; + int python_script = 0; + /* These are static so that we can take their address in an initializer. */ static int print_help; static int print_version; @@ -357,6 +364,40 @@ captured_main (void *data) } } +#ifdef GDB_DATADIR_RELOCATABLE + gdb_datadir = make_relative_prefix (argv[0], BINDIR, GDB_DATADIR); + if (gdb_datadir) + { + struct stat s; + int res = 0; + + if (stat (gdb_datadir, &s) == 0) + if (S_ISDIR (s.st_mode)) + res = 1; + + if (res == 0) + { + xfree (gdb_datadir); + gdb_datadir = xstrdup (GDB_DATADIR); + } + } + else + gdb_datadir = xstrdup (GDB_DATADIR); +#else + gdb_datadir = xstrdup (GDB_DATADIR); +#endif /* GDB_DATADIR_RELOCATABLE */ + + /* Canonicalize the GDB's datadir path. */ + if (*gdb_datadir) + { + char *canon_debug = lrealpath (gdb_datadir); + if (canon_debug) + { + xfree (gdb_datadir); + gdb_datadir = canon_debug; + } + } + get_init_files (&system_gdbinit, &home_gdbinit, &local_gdbinit); /* There will always be an interpreter. Either the one passed into @@ -441,10 +482,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; @@ -462,6 +507,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; @@ -638,7 +686,31 @@ extern int gdbtk_test (char *); use_windows = 0; } - if (set_args) + if (python_script) + { + /* The first argument is a python script to evaluate, and + subsequent arguments are passed to the script for + processing there. */ + if (optind >= argc) + { + fprintf_unfiltered (gdb_stderr, + _("%s: Python script file name required\n"), + argv[0]); + exit (1); + } + + /* FIXME: should handle inferior I/O intelligently here. + E.g., should be possible to run gdb in pipeline and have + Python (and gdb) output go to stderr or file; and if a + prompt is needed, open the tty. */ + quiet = 1; + /* FIXME: should read .gdbinit if, and only if, a prompt is + requested by the script. Though... maybe this is not + ideal? */ + /* FIXME: likewise, reading in history. */ + inhibit_gdbinit = 1; + } + else if (set_args) { /* The remaining options are the command-line options for the inferior. The first one is the sym/exec file, and the rest @@ -866,7 +938,8 @@ Can't attach to process and specify a core file at the same time.")); xfree (cmdarg); /* Read in the old history after all the command files have been read. */ - init_history (); + if (!python_script) + init_history (); if (batch) { @@ -895,13 +968,25 @@ Can't attach to process and specify a core file at the same time.")); #endif } - /* NOTE: cagney/1999-11-07: There is probably no reason for not - moving this loop and the code found in captured_command_loop() - into the command_loop() proper. The main thing holding back that - change - SET_TOP_LEVEL() - has been eliminated. */ - while (1) +#if HAVE_PYTHON + if (python_script) { - catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL); + extern int pagination_enabled; + pagination_enabled = 0; + run_python_script (argc - optind, &argv[optind]); + return 1; + } + else +#endif + { + /* NOTE: cagney/1999-11-07: There is probably no reason for not + moving this loop and the code found in captured_command_loop() + into the command_loop() proper. The main thing holding back that + change - SET_TOP_LEVEL() - has been eliminated. */ + while (1) + { + catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL); + } } /* No exit -- exit is through quit_command. */ } @@ -933,7 +1018,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 (_("\ @@ -971,7 +1061,13 @@ Options:\n\n\ --nw Do not use a window interface.\n\ --nx Do not read "), stream); fputs_unfiltered (gdbinit, stream); - fputs_unfiltered (_(" file.\n\ + fputs_unfiltered (_(" file.\n"), stream); +#if HAVE_PYTHON + fputs_unfiltered (_("\ + --python, -P Following argument is Python script file; remaining\n\ + arguments are passed to script.\n"), stream); +#endif + fputs_unfiltered (_("\ --quiet Do not print version number on startup.\n\ --readnow Fully read symbol files on first access.\n\ "), stream); diff --git a/gdb/maint.c b/gdb/maint.c index 56cafe9..1b57ff5 100644 --- a/gdb/maint.c +++ b/gdb/maint.c @@ -906,4 +906,12 @@ When enabled GDB is profiled."), show_maintenance_profile_p, &maintenance_set_cmdlist, &maintenance_show_cmdlist); + add_setshow_filename_cmd ("gdb_datadir", class_maintenance, + &gdb_datadir, _("Set GDB's datadir path."), + _("Show GDB's datadir path."), + _("\ +When set, GDB uses the specified path to search for data files."), + NULL, NULL, + &maintenance_set_cmdlist, + &maintenance_show_cmdlist); } diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c index 7cbcc59..e507c3b 100644 --- a/gdb/mdebugread.c +++ b/gdb/mdebugread.c @@ -4696,7 +4696,7 @@ new_type (char *name) { struct type *t; - t = alloc_type (current_objfile); + t = alloc_type (current_objfile, NULL); TYPE_NAME (t) = name; TYPE_CPLUS_SPECIFIC (t) = (struct cplus_struct_type *) &cplus_struct_default; return t; diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c index 143074b..0f4efba 100644 --- a/gdb/mi/mi-cmd-var.c +++ b/gdb/mi/mi-cmd-var.c @@ -249,6 +249,41 @@ mi_cmd_var_set_format (char *command, char **argv, int argc) } void +mi_cmd_var_set_visualizer (char *command, char **argv, int argc) +{ + struct varobj *var; + + if (argc != 2) + error ("Usage: NAME VISUALIZER_FUNCTION."); + + var = varobj_get_handle (argv[0]); + + if (var == NULL) + error ("Variable object not found"); + + varobj_set_visualizer (var, argv[1]); +} + +void +mi_cmd_var_set_child_range (char *command, char **argv, int argc) +{ + struct varobj *var; + int from, to; + + if (argc != 3) + error (_("-var-set-child-range: NAME FROM TO")); + + var = varobj_get_handle (argv[0]); + if (var == NULL) + error (_("Variable object not found")); + + from = atoi (argv[1]); + to = atoi (argv[2]); + + varobj_set_child_range (var, from, to); +} + +void mi_cmd_var_set_frozen (char *command, char **argv, int argc) { struct varobj *var; @@ -369,6 +404,8 @@ mi_cmd_var_list_children (char *command, char **argv, int argc) int numchild; enum print_values print_values; int ix; + int from, to; + char *display_hint; if (argc != 1 && argc != 2) error (_("mi_cmd_var_list_children: Usage: [PRINT_VALUES] NAME")); @@ -388,14 +425,22 @@ mi_cmd_var_list_children (char *command, char **argv, int argc) else print_values = PRINT_NO_VALUES; - if (VEC_length (varobj_p, children) == 0) + varobj_get_child_range (var, children, &from, &to); + if (from >= to) return; + display_hint = varobj_get_display_hint (var); + if (display_hint) + { + ui_out_field_string (uiout, "displayhint", display_hint); + xfree (display_hint); + } + if (mi_version (uiout) == 1) cleanup_children = make_cleanup_ui_out_tuple_begin_end (uiout, "children"); else cleanup_children = make_cleanup_ui_out_list_begin_end (uiout, "children"); - for (ix = 0; VEC_iterate (varobj_p, children, ix, child); ++ix) + for (ix = from; ix < to && VEC_iterate (varobj_p, children, ix, child); ++ix) { struct cleanup *cleanup_child; cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, "child"); @@ -662,6 +707,8 @@ varobj_update_one (struct varobj *var, enum print_values print_values, for (i = 0; VEC_iterate (varobj_update_result, changes, i, r); ++i) { + char *display_hint; + if (mi_version (uiout) > 1) cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); ui_out_field_string (uiout, "name", varobj_get_objname (r->varobj)); @@ -695,6 +742,36 @@ varobj_update_one (struct varobj *var, enum print_values print_values, ui_out_field_int (uiout, "new_num_children", varobj_get_num_children (r->varobj)); } + + display_hint = varobj_get_display_hint (var); + if (display_hint) + { + ui_out_field_string (uiout, "displayhint", display_hint); + xfree (display_hint); + } + + if (r->children_changed) + { + int ix, from, to; + struct varobj *child; + struct cleanup *cleanup = + make_cleanup_ui_out_list_begin_end (uiout, "children"); + + VEC (varobj_p)* children = varobj_list_children (r->varobj); + varobj_get_child_range (r->varobj, children, &from, &to); + + for (ix = from; + ix < to && VEC_iterate (varobj_p, children, ix, child); + ++ix) + { + struct cleanup *cleanup_child; + cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); + print_varobj (child, print_values, 1 /* print expression */); + do_cleanups (cleanup_child); + } + + do_cleanups (cleanup); + } if (mi_version (uiout) > 1) do_cleanups (cleanup); diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c index 2610b6a..f31233b 100644 --- a/gdb/mi/mi-cmds.c +++ b/gdb/mi/mi-cmds.c @@ -160,7 +160,9 @@ struct mi_cmd mi_cmds[] = { "var-info-num-children", { NULL, 0 }, mi_cmd_var_info_num_children}, { "var-info-type", { NULL, 0 }, mi_cmd_var_info_type}, { "var-list-children", { NULL, 0 }, mi_cmd_var_list_children}, + { "var-set-child-range", { NULL, 0 }, mi_cmd_var_set_child_range }, { "var-set-format", { NULL, 0 }, mi_cmd_var_set_format}, + { "var-set-visualizer", { NULL, 0 }, mi_cmd_var_set_visualizer}, { "var-set-frozen", { NULL, 0 }, mi_cmd_var_set_frozen}, { "var-show-attributes", { NULL, 0 }, mi_cmd_var_show_attributes}, { "var-show-format", { NULL, 0 }, mi_cmd_var_show_format}, diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h index 39f16fb..291a07f 100644 --- a/gdb/mi/mi-cmds.h +++ b/gdb/mi/mi-cmds.h @@ -92,7 +92,9 @@ extern mi_cmd_argv_ftype mi_cmd_var_info_num_children; extern mi_cmd_argv_ftype mi_cmd_var_info_type; extern mi_cmd_argv_ftype mi_cmd_var_list_children; extern mi_cmd_argv_ftype mi_cmd_var_set_format; +extern mi_cmd_argv_ftype mi_cmd_var_set_child_range; extern mi_cmd_argv_ftype mi_cmd_var_set_frozen; +extern mi_cmd_argv_ftype mi_cmd_var_set_visualizer; extern mi_cmd_argv_ftype mi_cmd_var_show_attributes; extern mi_cmd_argv_ftype mi_cmd_var_show_format; extern mi_cmd_argv_ftype mi_cmd_var_update; diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index b905a9e..eaa5f12 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -777,7 +777,7 @@ mi_cmd_data_evaluate_expression (char *command, char **argv, int argc) get_user_print_options (&opts); opts.deref_ref = 0; val_print (value_type (val), value_contents (val), - value_embedded_offset (val), VALUE_ADDRESS (val), + value_embedded_offset (val), value_address (val), stb->stream, 0, &opts, current_language); ui_out_field_stream (uiout, "value", stb); @@ -1101,6 +1101,10 @@ mi_cmd_list_features (char *command, char **argv, int argc) ui_out_field_string (uiout, NULL, "frozen-varobjs"); ui_out_field_string (uiout, NULL, "pending-breakpoints"); ui_out_field_string (uiout, NULL, "thread-info"); + +#if HAVE_PYTHON + ui_out_field_string (uiout, NULL, "python"); +#endif do_cleanups (cleanup); return; @@ -1317,6 +1321,7 @@ mi_cmd_execute (struct mi_parse *parse) struct cleanup *cleanup; int i; free_all_values (); + free_all_types (); current_token = xstrdup (parse->token); cleanup = make_cleanup (free_current_contents, ¤t_token); diff --git a/gdb/minsyms.c b/gdb/minsyms.c index bf776b3..e4b0f31 100644 --- a/gdb/minsyms.c +++ b/gdb/minsyms.c @@ -48,6 +48,8 @@ #include "value.h" #include "cp-abi.h" #include "target.h" +#include "cp-support.h" +#include "language.h" /* Accumulate the minimal symbols for each objfile in bunches of BUNCH_SIZE. At the end, copy them all into one newly allocated location on an objfile's @@ -187,6 +189,9 @@ lookup_minimal_symbol (const char *name, const char *sfile, unsigned int hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE; unsigned int dem_hash = msymbol_hash_iw (name) % MINIMAL_SYMBOL_HASH_SIZE; + int needtofreename = 0; + const char *modified_name; + if (sfile != NULL) { char *p = strrchr (sfile, '/'); @@ -194,6 +199,18 @@ lookup_minimal_symbol (const char *name, const char *sfile, sfile = p + 1; } + /* For C++, canonicalize the input name. */ + modified_name = name; + if (current_language->la_language == language_cplus) + { + char *cname = cp_canonicalize_string (name); + if (cname) + { + modified_name = cname; + needtofreename = 1; + } + } + for (objfile = object_files; objfile != NULL && found_symbol == NULL; objfile = objfile->next) @@ -218,9 +235,16 @@ lookup_minimal_symbol (const char *name, const char *sfile, int match; if (pass == 1) - match = strcmp (SYMBOL_LINKAGE_NAME (msymbol), name) == 0; + { + match = strcmp (SYMBOL_LINKAGE_NAME (msymbol), + modified_name) == 0; + } else - match = SYMBOL_MATCHES_SEARCH_NAME (msymbol, name); + { + match = SYMBOL_MATCHES_SEARCH_NAME (msymbol, + modified_name); + } + if (match) { switch (MSYMBOL_TYPE (msymbol)) @@ -259,6 +283,10 @@ lookup_minimal_symbol (const char *name, const char *sfile, } } } + + if (needtofreename) + xfree ((void *) modified_name); + /* External symbols are best. */ if (found_symbol) return found_symbol; diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 6c8c4c0..7d283a4 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -2757,7 +2757,7 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, if (len > regsize && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)) { - store_unsigned_integer (valbuf, regsize, VALUE_ADDRESS (arg)); + store_unsigned_integer (valbuf, regsize, value_address (arg)); typecode = TYPE_CODE_PTR; len = regsize; val = valbuf; diff --git a/gdb/mipsread.c b/gdb/mipsread.c index a84003f..924c1c5 100644 --- a/gdb/mipsread.c +++ b/gdb/mipsread.c @@ -394,6 +394,7 @@ static struct sym_fns ecoff_sym_fns = mipscoff_new_init, /* sym_new_init: init anything gbl to entire symtab */ mipscoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ mipscoff_symfile_read, /* sym_read: read a symbol file into symtab */ + NULL, /* sym_read_psymbols */ mipscoff_symfile_finish, /* sym_finish: finished with file, cleanup */ default_symfile_offsets, /* sym_offsets: dummy FIXME til implem sym reloc */ default_symfile_segments, /* sym_segments: Get segment information from diff --git a/gdb/mn10300-tdep.c b/gdb/mn10300-tdep.c index f0cea27..02be43a 100644 --- a/gdb/mn10300-tdep.c +++ b/gdb/mn10300-tdep.c @@ -1027,7 +1027,7 @@ mn10300_push_dummy_call (struct gdbarch *gdbarch, /* Change to pointer-to-type. */ arg_len = push_size; store_unsigned_integer (valbuf, push_size, - VALUE_ADDRESS (*args)); + value_address (*args)); val = &valbuf[0]; } else diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c index a6c74a3..9b8d801 100644 --- a/gdb/objc-lang.c +++ b/gdb/objc-lang.c @@ -280,7 +280,7 @@ objc_demangle (const char *mangled, int options) for printing characters and strings is language specific. */ static void -objc_emit_char (int c, struct ui_file *stream, int quoter) +objc_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) { c &= 0xFF; /* Avoid sign bit follies. */ @@ -326,10 +326,10 @@ objc_emit_char (int c, struct ui_file *stream, int quoter) } static void -objc_printchar (int c, struct ui_file *stream) +objc_printchar (int c, struct type *type, struct ui_file *stream) { fputs_filtered ("'", stream); - objc_emit_char (c, stream, '\''); + objc_emit_char (c, type, stream, '\''); fputs_filtered ("'", stream); } @@ -340,14 +340,16 @@ objc_printchar (int c, struct ui_file *stream) FORCE_ELLIPSES. */ static void -objc_printstr (struct ui_file *stream, const gdb_byte *string, - unsigned int length, int width, int force_ellipses, +objc_printstr (struct ui_file *stream, struct type *type, + const gdb_byte *string, unsigned int length, + int force_ellipses, const struct value_print_options *options) { unsigned int i; unsigned int things_printed = 0; int in_quotes = 0; int need_comma = 0; + int width = TYPE_LENGTH (type); /* If the string was not truncated due to `set print elements', and the last byte of it is a null, we don't print that, in @@ -395,7 +397,7 @@ objc_printstr (struct ui_file *stream, const gdb_byte *string, fputs_filtered ("\", ", stream); in_quotes = 0; } - objc_printchar (string[i], stream); + objc_printchar (string[i], type, stream); fprintf_filtered (stream, " ", reps); i = rep1 - 1; things_printed += options->repeat_count_threshold; @@ -411,7 +413,7 @@ objc_printstr (struct ui_file *stream, const gdb_byte *string, fputs_filtered ("\"", stream); in_quotes = 1; } - objc_emit_char (string[i], stream, '"'); + objc_emit_char (string[i], type, stream, '"'); ++things_printed; } } diff --git a/gdb/objfiles.c b/gdb/objfiles.c index bc77de8..079ebcf 100644 --- a/gdb/objfiles.c +++ b/gdb/objfiles.c @@ -691,6 +691,20 @@ have_partial_symbols (void) return 1; } } + + /* Try again, after reading partial symbols. We do this in two + passes because objfiles are always added to the head of the list, + and there might be a later objfile for which we've already read + partial symbols. */ + ALL_OBJFILES (ofp) + { + require_partial_symbols (ofp); + if (ofp->psymtabs != NULL) + { + return 1; + } + } + return 0; } diff --git a/gdb/objfiles.h b/gdb/objfiles.h index 60d3143..b6fdd92 100644 --- a/gdb/objfiles.h +++ b/gdb/objfiles.h @@ -212,6 +212,11 @@ struct objfile struct partial_symtab *psymtabs; + /* An address map that can be used to quickly determine if an + address comes from this objfile. This can be NULL. */ + + struct addrmap *quick_addrmap; + /* Map addresses to the entries of PSYMTABS. It would be more efficient to have a map per the whole process but ADDRMAP cannot selectively remove its items during FREE_OBJFILE. This mapping is already present even for @@ -420,6 +425,15 @@ struct objfile #define OBJF_KEEPBFD (1 << 4) /* Do not delete bfd */ +/* Set if we have tried to read partial symtabs for this objfile. + This is used to allow lazy reading of partial symtabs. */ + +#define OBJF_SYMTABS_READ (1 << 6) + +/* This flag is set for the main objfile. */ + +#define OBJF_MAIN (1 << 7) + /* The object file that the main symbol table was loaded from (e.g. the argument to the "symbol-file" or "file" command). */ @@ -556,6 +570,13 @@ extern void *objfile_data (struct objfile *objfile, ALL_OBJFILES (objfile) \ ALL_OBJFILE_PSYMTABS (objfile, p) +/* Like ALL_PSYMTABS, but ensure that partial symbols have been read + before examining the objfile. */ + +#define ALL_PSYMTABS_REQUIRED(objfile, p) \ + ALL_OBJFILES (objfile) \ + ALL_OBJFILE_PSYMTABS (require_partial_symbols (objfile), p) + /* Traverse all minimal symbols in all objfiles. */ #define ALL_MSYMBOLS(objfile, m) \ diff --git a/gdb/p-lang.c b/gdb/p-lang.c index 41da3e0..e743a6f 100644 --- a/gdb/p-lang.c +++ b/gdb/p-lang.c @@ -97,7 +97,8 @@ pascal_main_name (void) but this does not happen for Free Pascal nor for GPC. */ int is_pascal_string_type (struct type *type,int *length_pos, - int *length_size, int *string_pos, int *char_size, + int *length_size, int *string_pos, + struct type **char_type, char **arrayname) { if (TYPE_CODE (type) == TYPE_CODE_STRUCT) @@ -114,8 +115,8 @@ is_pascal_string_type (struct type *type,int *length_pos, *length_size = TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)); if (string_pos) *string_pos = TYPE_FIELD_BITPOS (type, 1) / TARGET_CHAR_BIT; - if (char_size) - *char_size = 1; + if (char_type) + *char_type = TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, 1)); if (arrayname) *arrayname = TYPE_FIELDS (type)[1].name; return 2; @@ -126,7 +127,6 @@ is_pascal_string_type (struct type *type,int *length_pos, && strcmp (TYPE_FIELDS (type)[0].name, "Capacity") == 0 && strcmp (TYPE_FIELDS (type)[1].name, "length") == 0) { - struct type *char_type; if (length_pos) *length_pos = TYPE_FIELD_BITPOS (type, 1) / TARGET_CHAR_BIT; if (length_size) @@ -134,13 +134,12 @@ is_pascal_string_type (struct type *type,int *length_pos, if (string_pos) *string_pos = TYPE_FIELD_BITPOS (type, 2) / TARGET_CHAR_BIT; /* FIXME: how can I detect wide chars in GPC ?? */ - char_type = TYPE_FIELD_TYPE (type,2); - if (char_size && TYPE_CODE (char_type) == TYPE_CODE_ARRAY) + if (char_type) { - *char_size = TYPE_LENGTH (TYPE_TARGET_TYPE (char_type)); + *char_type = TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, 2)); + if (TYPE_CODE (*char_type) == TYPE_CODE_ARRAY) + *char_type = TYPE_TARGET_TYPE (*char_type); } - else if (char_size) - *char_size = 1; if (arrayname) *arrayname = TYPE_FIELDS (type)[2].name; return 3; @@ -182,14 +181,15 @@ pascal_one_char (int c, struct ui_file *stream, int *in_quotes) } } -static void pascal_emit_char (int c, struct ui_file *stream, int quoter); +static void pascal_emit_char (int c, struct type *type, + struct ui_file *stream, int quoter); /* Print the character C on STREAM as part of the contents of a literal string whose delimiter is QUOTER. Note that that format for printing characters and strings is language specific. */ static void -pascal_emit_char (int c, struct ui_file *stream, int quoter) +pascal_emit_char (int c, struct type *type, struct ui_file *stream, int quoter) { int in_quotes = 0; pascal_one_char (c, stream, &in_quotes); @@ -198,7 +198,7 @@ pascal_emit_char (int c, struct ui_file *stream, int quoter) } void -pascal_printchar (int c, struct ui_file *stream) +pascal_printchar (int c, struct type *type, struct ui_file *stream) { int in_quotes = 0; pascal_one_char (c, stream, &in_quotes); @@ -212,14 +212,16 @@ pascal_printchar (int c, struct ui_file *stream) had to stop before printing LENGTH characters, or if FORCE_ELLIPSES. */ void -pascal_printstr (struct ui_file *stream, const gdb_byte *string, - unsigned int length, int width, int force_ellipses, +pascal_printstr (struct ui_file *stream, struct type *type, + const gdb_byte *string, unsigned int length, + int force_ellipses, const struct value_print_options *options) { unsigned int i; unsigned int things_printed = 0; int in_quotes = 0; int need_comma = 0; + int width = TYPE_LENGTH (type); /* If the string was not truncated due to `set print elements', and the last byte of it is a null, we don't print that, in traditional C @@ -273,7 +275,7 @@ pascal_printstr (struct ui_file *stream, const gdb_byte *string, fputs_filtered ("', ", stream); in_quotes = 0; } - pascal_printchar (current_char, stream); + pascal_printchar (current_char, type, stream); fprintf_filtered (stream, " ", reps); i = rep1 - 1; things_printed += options->repeat_count_threshold; diff --git a/gdb/p-lang.h b/gdb/p-lang.h index 09a4569..2b2eb2d 100644 --- a/gdb/p-lang.h +++ b/gdb/p-lang.h @@ -48,12 +48,13 @@ extern void pascal_type_print_method_args (char *, char *, /* These are in p-lang.c: */ extern int - is_pascal_string_type (struct type *, int *, int *, int *, int *, char **); + is_pascal_string_type (struct type *, int *, int *, int *, + struct type **, char **); -extern void pascal_printchar (int, struct ui_file *); +extern void pascal_printchar (int, struct type *, struct ui_file *); -extern void pascal_printstr (struct ui_file *, const gdb_byte *, - unsigned int, int, int, +extern void pascal_printstr (struct ui_file *, struct type *, const gdb_byte *, + unsigned int, int, const struct value_print_options *); extern struct type **const (pascal_builtin_types[]); diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c index 27ae619..29f0e6d 100644 --- a/gdb/p-valprint.c +++ b/gdb/p-valprint.c @@ -61,7 +61,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, struct type *elttype; unsigned eltlen; int length_pos, length_size, string_pos; - int char_size; + struct type *char_type; LONGEST val; CORE_ADDR addr; @@ -100,8 +100,9 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, len = temp_len; } - LA_PRINT_STRING (stream, valaddr + embedded_offset, len, - eltlen, 0, options); + LA_PRINT_STRING (stream, TYPE_TARGET_TYPE (type), + valaddr + embedded_offset, len, 0, + options); i = len; } else @@ -175,8 +176,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, && addr != 0) { /* no wide string yet */ - i = val_print_string (addr, -1, TYPE_LENGTH (elttype), stream, - options); + i = val_print_string (elttype, addr, -1, stream, options); } /* also for pointers to pascal strings */ /* Note: this is Free Pascal specific: @@ -184,7 +184,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, Pascal strings are mapped to records with lowercase names PM */ if (is_pascal_string_type (elttype, &length_pos, &length_size, - &string_pos, &char_size, NULL) + &string_pos, &char_type, NULL) && addr != 0) { ULONGEST string_length; @@ -193,7 +193,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, read_memory (addr + length_pos, buffer, length_size); string_length = extract_unsigned_integer (buffer, length_size); xfree (buffer); - i = val_print_string (addr + string_pos, string_length, char_size, stream, options); + i = val_print_string (char_type ,addr + string_pos, string_length, stream, options); } else if (pascal_object_is_vtbl_member (type)) { @@ -298,10 +298,10 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, else { if (is_pascal_string_type (type, &length_pos, &length_size, - &string_pos, &char_size, NULL)) + &string_pos, &char_type, NULL)) { len = extract_unsigned_integer (valaddr + embedded_offset + length_pos, length_size); - LA_PRINT_STRING (stream, valaddr + embedded_offset + string_pos, len, char_size, 0, options); + LA_PRINT_STRING (stream, char_type, valaddr + embedded_offset + string_pos, len, 0, options); } else pascal_object_print_value_fields (type, valaddr + embedded_offset, address, stream, @@ -426,7 +426,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, else fprintf_filtered (stream, "%d", (int) val); fputs_filtered (" ", stream); - LA_PRINT_CHAR ((unsigned char) val, stream); + LA_PRINT_CHAR ((unsigned char) val, type, stream); } break; @@ -931,7 +931,7 @@ pascal_object_print_static_field (struct value *val, if (TYPE_CODE (type) == TYPE_CODE_STRUCT) { - CORE_ADDR *first_dont_print; + CORE_ADDR *first_dont_print, addr; int i; first_dont_print @@ -941,7 +941,7 @@ pascal_object_print_static_field (struct value *val, while (--i >= 0) { - if (VALUE_ADDRESS (val) == first_dont_print[i]) + if (value_address (val) == first_dont_print[i]) { fputs_filtered ("", stream); @@ -949,11 +949,12 @@ pascal_object_print_static_field (struct value *val, } } - obstack_grow (&dont_print_statmem_obstack, (char *) &VALUE_ADDRESS (val), + addr = value_address (val); + obstack_grow (&dont_print_statmem_obstack, (char *) &addr, sizeof (CORE_ADDR)); CHECK_TYPEDEF (type); - pascal_object_print_value_fields (type, value_contents (val), VALUE_ADDRESS (val), + pascal_object_print_value_fields (type, value_contents (val), value_address (val), stream, recurse, options, NULL, 1); return; } diff --git a/gdb/parse.c b/gdb/parse.c index eee1f8e..66aaf6a 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -306,7 +306,7 @@ write_exp_elt_intern (struct internalvar *expelt) strings with embedded null bytes, as is required for some languages. Don't be fooled by the fact that the string is null byte terminated, - this is strictly for the convenience of debugging gdb itself. Gdb + this is strictly for the convenience of debugging gdb itself. Gdb does not depend up the string being null terminated, since the actual length is recorded in expression elements at each end of the string. The null byte is taken into consideration when computing how @@ -352,6 +352,65 @@ write_exp_string (struct stoken str) write_exp_elt_longcst ((LONGEST) len); } +/* Add a vector of string constants to the end of the expression. + + This adds an OP_STRING operation, but encodes the contents + differently from write_exp_string. The language is expected to + handle evaluation of this expression itself. + + After the usual OP_STRING header, TYPE is written into the + expression as a long constant. The interpretation of this field is + up to the language evaluator. + + Next, each string in VEC is written. The length is written as a + long constant, followed by the contents of the string. */ + +void +write_exp_string_vector (int type, struct stoken_vector *vec) +{ + int i, n_slots, len; + + /* Compute the size. We compute the size in number of slots to + avoid issues with string padding. */ + n_slots = 0; + for (i = 0; i < vec->len; ++i) + { + /* One slot for the length of this element, plus the number of + slots needed for this string. */ + n_slots += 1 + BYTES_TO_EXP_ELEM (vec->tokens[i].length); + } + + /* One more slot for the type of the string. */ + ++n_slots; + + /* Now compute a phony string length. */ + len = EXP_ELEM_TO_BYTES (n_slots) - 1; + + n_slots += 4; + if ((expout_ptr + n_slots) >= expout_size) + { + expout_size = max (expout_size * 2, expout_ptr + n_slots + 10); + expout = (struct expression *) + xrealloc ((char *) expout, (sizeof (struct expression) + + EXP_ELEM_TO_BYTES (expout_size))); + } + + write_exp_elt_opcode (OP_STRING); + write_exp_elt_longcst (len); + write_exp_elt_longcst (type); + + for (i = 0; i < vec->len; ++i) + { + write_exp_elt_longcst (vec->tokens[i].length); + memcpy (&expout->elts[expout_ptr], vec->tokens[i].ptr, + vec->tokens[i].length); + expout_ptr += BYTES_TO_EXP_ELEM (vec->tokens[i].length); + } + + write_exp_elt_longcst (len); + write_exp_elt_opcode (OP_STRING); +} + /* Add a bitstring constant to the end of the expression. Bitstring constants are stored by first writing an expression element @@ -777,6 +836,15 @@ operator_length_standard (struct expression *expr, int endpos, args = 1 + longest_to_int (expr->elts[endpos - 2].longconst); break; + case TYPE_INSTANCE: + oplen = 4 + longest_to_int (expr->elts[endpos - 2].longconst); + args = 1; + break; + + case TYPE_INSTANCE_LOOKUP: + oplen = 3; + break; + case OP_OBJC_MSGCALL: /* Objective C message (method) call */ oplen = 4; args = 1 + longest_to_int (expr->elts[endpos - 2].longconst); diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h index 2c4b755..cbda9c3 100644 --- a/gdb/parser-defs.h +++ b/gdb/parser-defs.h @@ -69,6 +69,22 @@ struct stoken int length; }; +struct typed_stoken + { + /* A language-specific type field. */ + int type; + /* Pointer to first byte of char-string or first bit of bit-string */ + char *ptr; + /* Length of string in bytes for char-string or bits for bit-string */ + int length; + }; + +struct stoken_vector + { + int len; + struct typed_stoken *tokens; + }; + struct ttype { struct stoken stoken; @@ -130,6 +146,8 @@ extern void write_exp_elt_intern (struct internalvar *); extern void write_exp_string (struct stoken); +void write_exp_string_vector (int type, struct stoken_vector *vec); + extern void write_exp_bitstring (struct stoken); extern void write_exp_elt_block (struct block *); diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index d08d4fc..c2bbdf9 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -38,6 +38,7 @@ #include "trad-frame.h" #include "frame-unwind.h" #include "tramp-frame.h" +#include "linux-tdep.h" #include "features/rs6000/powerpc-32l.c" #include "features/rs6000/powerpc-altivec32l.c" @@ -53,6 +54,9 @@ #include "features/rs6000/powerpc-isa205-vsx64l.c" #include "features/rs6000/powerpc-e500l.c" +/* The syscall's XML filename for PPC and PPC64. */ +#define XML_SYSCALL_FILENAME_PPC "syscalls/ppc-linux.xml" +#define XML_SYSCALL_FILENAME_PPC64 "syscalls/ppc64-linux.xml" /* ppc_linux_memory_remove_breakpoints attempts to remove a breakpoint in much the same fashion as memory_remove_breakpoint in mem-break.c, @@ -1009,6 +1013,38 @@ ppc_linux_trap_reg_p (struct gdbarch *gdbarch) && register_size (gdbarch, PPC_TRAP_REGNUM) > 0; } +/* Return the current system call's number present in the + r0 register. When the function fails, it returns -1. */ +static LONGEST +ppc_linux_get_syscall_number (struct gdbarch *gdbarch, + ptid_t ptid) +{ + struct regcache *regcache = get_thread_regcache (ptid); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct cleanup *cleanbuf; + /* The content of a register */ + gdb_byte *buf; + /* The result */ + LONGEST ret; + + /* Make sure we're in a 32- or 64-bit machine */ + gdb_assert (tdep->wordsize == 4 || tdep->wordsize == 8); + + buf = (gdb_byte *) xmalloc (tdep->wordsize * sizeof (gdb_byte)); + + cleanbuf = make_cleanup (xfree, buf); + + /* Getting the system call number from the register. + When dealing with PowerPC architecture, this information + is stored at 0th register. */ + regcache_cooked_read (regcache, tdep->ppc_gp0_regnum, buf); + + ret = extract_signed_integer (buf, tdep->wordsize); + do_cleanups (cleanbuf); + + return ret; +} + static void ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc) { @@ -1069,6 +1105,9 @@ ppc_linux_init_abi (struct gdbarch_info info, struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info; + /* Initializing common methods. */ + linux_tdep_init (gdbarch); + /* PPC GNU/Linux uses either 64-bit or 128-bit long doubles; where 128-bit, they are IBM long double, not IEEE quad long double as in the System V ABI PowerPC Processor Supplement. We can safely @@ -1080,6 +1119,9 @@ ppc_linux_init_abi (struct gdbarch_info info, /* Handle inferior calls during interrupted system calls. */ set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc); + /* Get the syscall number from the arch's register. */ + set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number); + if (tdep->wordsize == 4) { /* Until November 2001, gcc did not comply with the 32 bit SysV @@ -1099,6 +1141,9 @@ ppc_linux_init_abi (struct gdbarch_info info, set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_ilp32_fetch_link_map_offsets); + /* Setting the correct XML syscall filename. */ + set_gdbarch_xml_syscall_filename (gdbarch, XML_SYSCALL_FILENAME_PPC); + /* Trampolines. */ tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sigaction_tramp_frame); tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sighandler_tramp_frame); @@ -1116,6 +1161,9 @@ ppc_linux_init_abi (struct gdbarch_info info, set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_lp64_fetch_link_map_offsets); + /* Setting the correct XML syscall filename. */ + set_gdbarch_xml_syscall_filename (gdbarch, XML_SYSCALL_FILENAME_PPC64); + /* Trampolines. */ tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sigaction_tramp_frame); tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sighandler_tramp_frame); diff --git a/gdb/printcmd.c b/gdb/printcmd.c index 375f82e..8c3f476 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -43,6 +43,7 @@ #include "disasm.h" #include "dfp.h" #include "valprint.h" +#include "charset.h" #ifdef TUI #include "tui/tui.h" /* For tui_active et.al. */ @@ -62,11 +63,15 @@ struct format_data int count; char format; char size; + + /* True if the value should be printed raw -- that is, bypassing + python-based formatters. */ + unsigned char raw; }; /* Last specified output format. */ -static char last_format = 'x'; +static char last_format = 0; /* Last specified examination size. 'b', 'h', 'w' or `q'. */ @@ -175,6 +180,7 @@ decode_format (char **string_ptr, int oformat, int osize) val.format = '?'; val.size = '?'; val.count = 1; + val.raw = 0; if (*p >= '0' && *p <= '9') val.count = atoi (p); @@ -187,6 +193,11 @@ decode_format (char **string_ptr, int oformat, int osize) { if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g') val.size = *p++; + else if (*p == 'r') + { + val.raw = 1; + p++; + } else if (*p >= 'a' && *p <= 'z') val.format = *p++; else @@ -264,24 +275,27 @@ print_formatted (struct value *val, int size, int len = TYPE_LENGTH (type); if (VALUE_LVAL (val) == lval_memory) - next_address = VALUE_ADDRESS (val) + len; + next_address = value_address (val) + len; if (size) { switch (options->format) { case 's': - /* FIXME: Need to handle wchar_t's here... */ - next_address = VALUE_ADDRESS (val) - + val_print_string (VALUE_ADDRESS (val), -1, 1, stream, - options); + { + struct type *elttype = value_type (val); + next_address = (value_address (val) + + val_print_string (elttype, + value_address (val), -1, + stream, options)); + } return; case 'i': /* We often wrap here if there are long symbolic names. */ wrap_here (" "); - next_address = (VALUE_ADDRESS (val) - + gdb_print_insn (VALUE_ADDRESS (val), stream, + next_address = (value_address (val) + + gdb_print_insn (value_address (val), stream, &branch_delay_insns)); return; } @@ -369,7 +383,7 @@ print_scalar_formatted (const void *valaddr, struct type *type, print_hex_chars (stream, valaddr, len, byte_order); return; case 'c': - print_char_chars (stream, valaddr, len, byte_order); + print_char_chars (stream, type, valaddr, len, byte_order); return; default: break; @@ -865,6 +879,7 @@ print_command_1 (char *exp, int inspect, int voidprint) fmt.count = 1; fmt.format = 0; fmt.size = 0; + fmt.raw = 0; } if (exp && *exp) @@ -878,6 +893,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)) { @@ -900,6 +920,7 @@ print_command_1 (char *exp, int inspect, int voidprint) get_formatted_print_options (&opts, format); opts.inspect_it = inspect; + opts.raw = fmt.raw; print_formatted (val, fmt.size, &opts, gdb_stdout); printf_filtered ("\n"); @@ -950,6 +971,7 @@ output_command (char *exp, int from_tty) struct value_print_options opts; fmt.size = 0; + fmt.raw = 0; if (exp && *exp == '/') { @@ -967,6 +989,7 @@ output_command (char *exp, int from_tty) annotate_value_begin (value_type (val)); get_formatted_print_options (&opts, format); + opts.raw = fmt.raw; print_formatted (val, fmt.size, &opts, gdb_stdout); annotate_value_end (); @@ -1287,9 +1310,10 @@ x_command (char *exp, int from_tty) struct cleanup *old_chain; struct value *val; - fmt.format = last_format; + fmt.format = last_format ? last_format : 'x'; fmt.size = last_size; fmt.count = 1; + fmt.raw = 0; if (exp && *exp == '/') { @@ -1316,7 +1340,7 @@ x_command (char *exp, int from_tty) if (/* last_format == 'i' && */ TYPE_CODE (value_type (val)) == TYPE_CODE_FUNC && VALUE_LVAL (val) == lval_memory) - next_address = VALUE_ADDRESS (val); + next_address = value_address (val); else next_address = value_as_address (val); do_cleanups (old_chain); @@ -1393,6 +1417,7 @@ display_command (char *exp, int from_tty) fmt.format = 0; fmt.size = 0; fmt.count = 0; + fmt.raw = 0; } innermost_block = 0; @@ -1585,6 +1610,7 @@ do_one_display (struct display *d) annotate_display_expression (); get_formatted_print_options (&opts, d->format.format); + opts.raw = d->format.raw; print_formatted (evaluate_expression (d->exp), d->format.size, &opts, gdb_stdout); printf_filtered ("\n"); @@ -1865,7 +1891,8 @@ printf_command (char *arg, int from_tty) enum argclass { - int_arg, long_arg, long_long_arg, ptr_arg, string_arg, + int_arg, long_arg, long_long_arg, ptr_arg, + string_arg, wide_string_arg, wide_char_arg, double_arg, long_double_arg, decfloat_arg }; enum argclass *argclass; @@ -1997,8 +2024,8 @@ printf_command (char *arg, int from_tty) break; case 'c': - this_argclass = int_arg; - if (lcount || seen_h || seen_big_l) + this_argclass = lcount == 0 ? int_arg : wide_char_arg; + if (lcount > 1 || seen_h || seen_big_l) bad = 1; if (seen_prec || seen_zero || seen_space || seen_plus) bad = 1; @@ -2013,8 +2040,8 @@ printf_command (char *arg, int from_tty) break; case 's': - this_argclass = string_arg; - if (lcount || seen_h || seen_big_l) + this_argclass = lcount == 0 ? string_arg : wide_string_arg; + if (lcount > 1 || seen_h || seen_big_l) bad = 1; if (seen_zero || seen_space || seen_plus) bad = 1; @@ -2066,6 +2093,15 @@ printf_command (char *arg, int from_tty) last_arg[length_before_ll + lcount]; current_substring += length_before_ll + 4; } + else if (this_argclass == wide_string_arg + || this_argclass == wide_char_arg) + { + /* Convert %ls or %lc to %s. */ + int length_before_ls = f - last_arg - 2; + strncpy (current_substring, last_arg, length_before_ls); + strcpy (current_substring + length_before_ls, "s"); + current_substring += length_before_ls + 2; + } else { strncpy (current_substring, last_arg, f - last_arg); @@ -2130,6 +2166,76 @@ printf_command (char *arg, int from_tty) printf_filtered (current_substring, (char *) str); } break; + case wide_string_arg: + { + gdb_byte *str; + CORE_ADDR tem; + int j; + struct type *wctype = lookup_typename ("wchar_t", NULL, 0); + int wcwidth = TYPE_LENGTH (wctype); + gdb_byte *buf = alloca (wcwidth); + struct obstack output; + struct cleanup *inner_cleanup; + + tem = value_as_address (val_args[i]); + + /* This is a %s argument. Find the length of the string. */ + for (j = 0;; j += wcwidth) + { + QUIT; + read_memory (tem + j, buf, wcwidth); + if (extract_unsigned_integer (buf, wcwidth) == 0) + break; + } + + /* Copy the string contents into a string inside GDB. */ + str = (gdb_byte *) alloca (j + wcwidth); + if (j != 0) + read_memory (tem, str, j); + memset (&str[j], 0, wcwidth); + + obstack_init (&output); + inner_cleanup = make_cleanup_obstack_free (&output); + + convert_between_encodings (target_wide_charset (), + host_charset (), + str, j, wcwidth, + &output, translit_char); + obstack_grow_str0 (&output, ""); + + printf_filtered (current_substring, obstack_base (&output)); + do_cleanups (inner_cleanup); + } + break; + case wide_char_arg: + { + struct type *wctype = lookup_typename ("wchar_t", NULL, 0); + struct type *valtype; + struct obstack output; + struct cleanup *inner_cleanup; + const gdb_byte *bytes; + + valtype = value_type (val_args[i]); + if (TYPE_LENGTH (valtype) != TYPE_LENGTH (wctype) + || TYPE_CODE (valtype) != TYPE_CODE_INT) + error (_("expected wchar_t argument for %%lc")); + + bytes = value_contents (val_args[i]); + + obstack_init (&output); + inner_cleanup = make_cleanup_obstack_free (&output); + + convert_between_encodings (target_wide_charset (), + host_charset (), + bytes, TYPE_LENGTH (valtype), + TYPE_LENGTH (valtype), + &output, translit_char); + obstack_grow_str0 (&output, ""); + + printf_filtered (current_substring, obstack_base (&output)); + do_cleanups (inner_cleanup); + } + break; case double_arg: { struct type *type = value_type (val_args[i]); diff --git a/gdb/python/lib/gdb/FrameIterator.py b/gdb/python/lib/gdb/FrameIterator.py new file mode 100644 index 0000000..87fb074 --- /dev/null +++ b/gdb/python/lib/gdb/FrameIterator.py @@ -0,0 +1,33 @@ +# Iterator over frames. + +# 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 . + +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 == None: + raise StopIteration + self.frame = result.older () + return result diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py new file mode 100644 index 0000000..b375c68 --- /dev/null +++ b/gdb/python/lib/gdb/__init__.py @@ -0,0 +1,19 @@ +# Startup code. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Load the require command by default. +import gdb.command.require diff --git a/gdb/python/lib/gdb/backtrace.py b/gdb/python/lib/gdb/backtrace.py new file mode 100644 index 0000000..2baab5f --- /dev/null +++ b/gdb/python/lib/gdb/backtrace.py @@ -0,0 +1,42 @@ +# Filtering backtrace. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb +import itertools + +# Our only exports. +__all__ = ['push_frame_filter', 'create_frame_filter'] + +frame_filter = None + +def push_frame_filter (constructor): + """Register a new backtrace filter class with the 'backtrace' command. +The filter will be passed an iterator as an argument. The iterator +will return gdb.Frame-like objects. The filter should in turn act as +an iterator returning such objects.""" + global frame_filter + if frame_filter == None: + frame_filter = constructor + else: + frame_filter = lambda iterator: constructor (frame_filter (iterator)) + +def create_frame_filter (iter): + global frame_filter + if frame_filter is None: + return iter + return frame_filter (iter) + diff --git a/gdb/python/lib/gdb/command/__init__.py b/gdb/python/lib/gdb/command/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/gdb/python/lib/gdb/command/__init__.py @@ -0,0 +1 @@ + diff --git a/gdb/python/lib/gdb/command/alias.py b/gdb/python/lib/gdb/command/alias.py new file mode 100644 index 0000000..96b6618 --- /dev/null +++ b/gdb/python/lib/gdb/command/alias.py @@ -0,0 +1,59 @@ +# Alias command. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb + +class AliasImplementation (gdb.Command): + def __init__ (self, name, real, doc): + # Have to set __doc__ before the super init call. + # It would be nice if gdb's help looked up __doc__ dynamically. + self.__doc__ = doc + # Note: no good way to complete :( + super (AliasImplementation, self).__init__ (name, gdb.COMMAND_NONE) + self.real = real + + def invoke(self, arg, from_tty): + gdb.execute (self.real + ' ' + arg, from_tty) + +class AliasCommand (gdb.Command): + """Alias one command to another. +In the simplest form, the first word is the name of the alias, and +the remaining words are the the expansion. +An '=' by itself can be used to define a multi-word alias; words +before the '=' are the name of the new command.""" + + def __init__ (self): + # Completion is not quite right here. + super (AliasCommand, self).__init__ ("alias", gdb.COMMAND_NONE, + gdb.COMPLETE_COMMAND) + + def invoke (self, arg, from_tty): + self.dont_repeat () + # Without some form of quoting we can't alias a multi-word + # command to another command. + args = arg.split() + try: + start = args.index ('=') + end = start + 1 + except ValueError: + start = 1 + end = 1 + target = " ".join(args[end:]) + AliasImplementation (" ".join (args[0:start]), target, + "This command is an alias for '%s'." % target) + +AliasCommand() diff --git a/gdb/python/lib/gdb/command/backtrace.py b/gdb/python/lib/gdb/command/backtrace.py new file mode 100644 index 0000000..f07696e --- /dev/null +++ b/gdb/python/lib/gdb/command/backtrace.py @@ -0,0 +1,197 @@ +# New backtrace command. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb +import gdb.backtrace +import itertools +from gdb.FrameIterator import FrameIterator +import sys + +class FrameWrapper: + def __init__ (self, frame): + self.frame = frame; + + def write_symbol (self, stream, sym, block): + if len (sym.linkage_name): + nsym, is_field_of_this = gdb.lookup_symbol (sym.linkage_name, block) + if nsym.addr_class != gdb.SYMBOL_LOC_REGISTER: + sym = nsym + + stream.write (sym.print_name + "=") + try: + val = self.frame.read_var (sym) + if val != None: + val = str (val) + # FIXME: would be nice to have a more precise exception here. + except RuntimeError, text: + val = text + if val == None: + stream.write ("???") + else: + stream.write (str (val)) + + def print_frame_locals (self, stream, func): + if not func: + return + + first = True + block = func.value + + for sym in block: + if sym.is_argument: + continue; + + self.write_symbol (stream, sym, block) + stream.write ('\n') + + def print_frame_args (self, stream, func): + if not func: + return + + first = True + block = func.value + + for sym in block: + if not sym.is_argument: + continue; + + if not first: + stream.write (", ") + + self.write_symbol (stream, sym, block) + first = False + + # FIXME: this should probably just be a method on gdb.Frame. + # But then we need stream wrappers. + def describe (self, stream, full): + if self.frame.type () == gdb.DUMMY_FRAME: + stream.write (" \n") + elif self.frame.type () == gdb.SIGTRAMP_FRAME: + stream.write (" \n") + else: + sal = self.frame.find_sal () + pc = self.frame.pc () + name = self.frame.name () + if not name: + name = "??" + if pc != sal.pc or not sal.symtab: + stream.write (" 0x%08x in" % pc) + stream.write (" " + name + " (") + + func = gdb.find_pc_function (self.frame.addr_in_block ()) + self.print_frame_args (stream, func) + + stream.write (")") + + if sal.symtab and sal.symtab.filename: + stream.write (" at " + sal.symtab.filename) + stream.write (":" + str (sal.line)) + + if not self.frame.name () or (not sal.symtab or not sal.symtab.filename): + lib = gdb.solib_address (pc) + if lib: + stream.write (" from " + lib) + + stream.write ("\n") + + if full: + self.print_frame_locals (stream, func) + + def __getattr__ (self, name): + return getattr (self.frame, name) + +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 + iter = itertools.imap (FrameWrapper, + FrameIterator (gdb.newest_frame ())) + if filter: + iter = gdb.backtrace.create_frame_filter (iter) + + # Now wrap in an iterator that numbers the frames. + iter = itertools.izip (itertools.count (0), iter) + + # Reverse if the user wanted that. + if self.reverse.value: + iter = self.reverse_iter (iter) + + # Extract sub-range user wants. + if count < 0: + iter = self.final_n (iter, count) + elif count > 0: + iter = itertools.islice (iter, 0, count) + + for pair in iter: + sys.stdout.write ("#%-2d" % pair[0]) + pair[1].describe (sys.stdout, full) + +FilteringBacktrace() diff --git a/gdb/python/lib/gdb/command/ignore_errors.py b/gdb/python/lib/gdb/command/ignore_errors.py new file mode 100644 index 0000000..6fa48ff --- /dev/null +++ b/gdb/python/lib/gdb/command/ignore_errors.py @@ -0,0 +1,37 @@ +# Ignore errors in user commands. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb + +class IgnoreErrorsCommand (gdb.Command): + """Execute a single command, ignoring all errors. +Only one-line commands are supported. +This is primarily useful in scripts.""" + + def __init__ (self): + super (IgnoreErrorsCommand, self).__init__ ("ignore-errors", + gdb.COMMAND_OBSCURE, + # FIXME... + gdb.COMPLETE_COMMAND) + + def invoke (self, arg, from_tty): + try: + gdb.execute (arg, from_tty) + except: + pass + +IgnoreErrorsCommand () diff --git a/gdb/python/lib/gdb/command/pahole.py b/gdb/python/lib/gdb/command/pahole.py new file mode 100644 index 0000000..569b816 --- /dev/null +++ b/gdb/python/lib/gdb/command/pahole.py @@ -0,0 +1,81 @@ +# pahole command for gdb + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb + +class 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) + + @staticmethod + def strip (type): + while type.code () == gdb.TYPE_CODE_TYPEDEF: + type = type.target () + return type + + 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 = self.strip (field.type) + + 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.Type (arg) + type = self.strip (type) + if type.code () != gdb.TYPE_CODE_STRUCT: + raise TypeError, '%s is not a struct type' % arg + print ' ' * 14, + self.pahole (type, 0, '') + +Pahole() diff --git a/gdb/python/lib/gdb/command/require.py b/gdb/python/lib/gdb/command/require.py new file mode 100644 index 0000000..1fbc1e8 --- /dev/null +++ b/gdb/python/lib/gdb/command/require.py @@ -0,0 +1,57 @@ +# Demand-loading commands. + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb +import os + +class RequireCommand (gdb.Command): + """Prefix command for requiring features.""" + + def __init__ (self): + super (RequireCommand, self).__init__ ("require", + gdb.COMMAND_SUPPORT, + gdb.COMPLETE_NONE, + True) + +class RequireSubcommand (gdb.Command): + """Demand-load a command by name.""" + + def __init__ (self, name): + self.__doc__ = "Demand-load a %s by name." % name + super (RequireSubcommand, self).__init__ ("require %s" % name, + gdb.COMMAND_SUPPORT) + self.name = name + + def invoke (self, arg, from_tty): + for cmd in arg.split(): + exec ('import gdb.' + self.name + '.' + cmd, globals ()) + + def complete (self, text, word): + dir = gdb.pythondir + '/gdb/' + self.name + result = [] + for file in os.listdir(dir): + if not file.startswith (word) or not file.endswith ('.py'): + continue + feature = file[0:-3] + if feature == 'require' or feature == '__init__': + continue + result.append (feature) + return result + +RequireCommand() +RequireSubcommand("command") +RequireSubcommand("function") diff --git a/gdb/python/lib/gdb/command/save_breakpoints.py b/gdb/python/lib/gdb/command/save_breakpoints.py new file mode 100644 index 0000000..90e07db --- /dev/null +++ b/gdb/python/lib/gdb/command/save_breakpoints.py @@ -0,0 +1,65 @@ +# Save breakpoints. + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import with_statement +import gdb + +class SavePrefixCommand (gdb.Command): + "Prefix command for saving things." + + def __init__ (self): + super (SavePrefixCommand, self).__init__ ("save", + gdb.COMMAND_SUPPORT, + gdb.COMPLETE_NONE, True) + +class SaveBreakpointsCommand (gdb.Command): + """Save the current breakpoints to a file. +This command takes a single argument, a file name. +The breakpoints can be restored using the 'source' command.""" + + def __init__ (self): + super (SaveBreakpointsCommand, self).__init__ ("save breakpoints", + gdb.COMMAND_SUPPORT, + gdb.COMPLETE_FILENAME) + + def invoke (self, arg, from_tty): + self.dont_repeat () + bps = gdb.breakpoints () + if bps is None: + raise RuntimeError, 'No breakpoints to save' + with open (arg.strip (), 'w') as f: + for bp in bps: + print >> f, "break", bp.location, + if bp.thread is not None: + print >> f, " thread", bp.thread, + if bp.condition is not None: + print >> f, " if", bp.condition, + print >> f + if not bp.enabled: + print >> f, "disable %d" % bp.number + # Note: we don't save the ignore count; there doesn't + # seem to be much point. + commands = bp.commands + if commands is not None: + print >> f, "commands" + # Note that COMMANDS has a trailing newline. + print >> f, commands, + print >> f, "end" + print >> f + +SavePrefixCommand () +SaveBreakpointsCommand () diff --git a/gdb/python/lib/gdb/function/__init__.py b/gdb/python/lib/gdb/function/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/gdb/python/lib/gdb/function/__init__.py @@ -0,0 +1 @@ + diff --git a/gdb/python/lib/gdb/function/caller_is.py b/gdb/python/lib/gdb/function/caller_is.py new file mode 100644 index 0000000..2b9c5c7 --- /dev/null +++ b/gdb/python/lib/gdb/function/caller_is.py @@ -0,0 +1,58 @@ +# Caller-is functions. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb +import re + +class CallerIs (gdb.Function): + """Return True if the calling function's name is equal to a string. +This function takes one or two arguments. +The first argument is the name of a function; if the calling function's +name is equal to this argument, this function returns True. +The optional second argument tells this function how many stack frames +to traverse to find the calling function. The default is 1.""" + + def __init__ (self): + super (CallerIs, self).__init__ ("caller_is") + + def invoke (self, name, nframes = 1): + frame = gdb.selected_frame () + while nframes > 0: + frame = frame.older () + nframes = nframes - 1 + return frame.name () == name.string () + +class CallerMatches (gdb.Function): + """Return True if the calling function's name matches a string. +This function takes one or two arguments. +The first argument is a regular expression; if the calling function's +name is matched by this argument, this function returns True. +The optional second argument tells this function how many stack frames +to traverse to find the calling function. The default is 1.""" + + def __init__ (self): + super (CallerMatches, self).__init__ ("caller_matches") + + def invoke (self, name, nframes = 1): + frame = gdb.selected_frame () + while nframes > 0: + frame = frame.older () + nframes = nframes - 1 + return re.match (name.string (), frame.name ()) is not None + +CallerIs() +CallerMatches() diff --git a/gdb/python/lib/gdb/function/in_scope.py b/gdb/python/lib/gdb/function/in_scope.py new file mode 100644 index 0000000..debb3bb --- /dev/null +++ b/gdb/python/lib/gdb/function/in_scope.py @@ -0,0 +1,47 @@ +# In-scope function. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb + +class InScope (gdb.Function): + """Return True if all the given variables or macros are in scope. +Takes one argument for each variable name to be checked.""" + + def __init__ (self): + super (InScope, self).__init__ ("in_scope") + + def invoke (self, *vars): + if len (vars) == 0: + raise TypeError, "in_scope takes at least one argument" + + # gdb.Value isn't hashable so it can't be put in a map. + # Convert to string first. + wanted = set (map (lambda x: x.string (), vars)) + found = set () + block = gdb.selected_frame ().block () + while block: + for sym in block: + if (sym.is_argument or sym.is_constant + or sym.is_function or sym.is_variable): + if sym.name in wanted: + found.add (sym.name) + + block = block.superblock + + return wanted == found + +InScope () diff --git a/gdb/python/lib/gdb/libstdcxx/__init__.py b/gdb/python/lib/gdb/libstdcxx/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/gdb/python/lib/gdb/libstdcxx/__init__.py @@ -0,0 +1 @@ + diff --git a/gdb/python/lib/gdb/libstdcxx/v6/__init__.py b/gdb/python/lib/gdb/libstdcxx/v6/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/gdb/python/lib/gdb/libstdcxx/v6/__init__.py @@ -0,0 +1 @@ + diff --git a/gdb/python/lib/gdb/libstdcxx/v6/hook.in b/gdb/python/lib/gdb/libstdcxx/v6/hook.in new file mode 100644 index 0000000..fe7c072 --- /dev/null +++ b/gdb/python/lib/gdb/libstdcxx/v6/hook.in @@ -0,0 +1,27 @@ +# -*- python -*- +# Copyright (C) 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import sys +import gdb + +# Update module path. +dir = '@dir@' +if not dir in sys.path: + sys.path.insert(0, dir) + +# Load the pretty-printers. +from libstdcxx.v6.printers import register_libstdcxx_printers +register_libstdcxx_printers (gdb.current_objfile ()) diff --git a/gdb/python/lib/gdb/libstdcxx/v6/printers.py b/gdb/python/lib/gdb/libstdcxx/v6/printers.py new file mode 100644 index 0000000..ccef97d --- /dev/null +++ b/gdb/python/lib/gdb/libstdcxx/v6/printers.py @@ -0,0 +1,646 @@ +# Pretty-printers for libstc++. + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb +import itertools +import re + +class StdPointerPrinter: + "Print a smart pointer of some kind" + + def __init__ (self, typename, val): + self.typename = typename + self.val = val + + def to_string (self): + return '%s (count %d) %s' % (self.typename, + self.val['_M_refcount']['_M_pi']['_M_use_count'], + self.val['_M_ptr']) + +class UniquePointerPrinter: + "Print a unique_ptr" + + def __init__ (self, val): + self.val = val + + def to_string (self): + return self.val['_M_t'] + +class StdListPrinter: + "Print a std::list" + + class _iterator: + def __init__(self, nodetype, head): + self.nodetype = nodetype + self.base = head['_M_next'] + self.head = head.address() + self.count = 0 + + def __iter__(self): + return self + + def next(self): + if self.base == self.head: + raise StopIteration + elt = self.base.cast(self.nodetype).dereference() + self.base = elt['_M_next'] + count = self.count + self.count = self.count + 1 + return ('[%d]' % count, elt['_M_data']) + + def __init__(self, val): + self.val = val + + def children(self): + itype = self.val.type().template_argument(0) + nodetype = gdb.Type('std::_List_node<%s>' % itype).pointer() + return self._iterator(nodetype, self.val['_M_impl']['_M_node']) + + def to_string(self): + if self.val['_M_impl']['_M_node'].address() == self.val['_M_impl']['_M_node']['_M_next']: + return 'empty std::list' + return 'std::list' + +class StdListIteratorPrinter: + "Print std::list::iterator" + + def __init__(self, val): + self.val = val + + def to_string(self): + itype = self.val.type().template_argument(0) + nodetype = gdb.Type('std::_List_node<%s>' % itype).pointer() + return self.val['_M_node'].cast(nodetype).dereference()['_M_data'] + +class StdSlistPrinter: + "Print a __gnu_cxx::slist" + + class _iterator: + def __init__(self, nodetype, head): + self.nodetype = nodetype + self.base = head['_M_head']['_M_next'] + self.count = 0 + + def __iter__(self): + return self + + def next(self): + if self.base == 0: + raise StopIteration + elt = self.base.cast(self.nodetype).dereference() + self.base = elt['_M_next'] + count = self.count + self.count = self.count + 1 + return ('[%d]' % count, elt['_M_data']) + + def __init__(self, val): + self.val = val + + def children(self): + itype = self.val.type().template_argument(0) + nodetype = gdb.Type('__gnu_cxx::_Slist_node<%s>' % itype).pointer() + return self._iterator(nodetype, self.val) + + def to_string(self): + if self.val['_M_head']['_M_next'] == 0: + return 'empty __gnu_cxx::slist' + return '__gnu_cxx::slist' + +class StdSlistIteratorPrinter: + "Print __gnu_cxx::slist::iterator" + + def __init__(self, val): + self.val = val + + def to_string(self): + itype = self.val.type().template_argument(0) + nodetype = gdb.Type('__gnu_cxx::_Slist_node<%s>' % itype).pointer() + return self.val['_M_node'].cast(nodetype).dereference()['_M_data'] + +class StdVectorPrinter: + "Print a std::vector" + + class _iterator: + def __init__ (self, start, finish): + self.item = start + self.finish = finish + self.count = 0 + + def __iter__(self): + return self + + def next(self): + if self.item == self.finish: + raise StopIteration + count = self.count + self.count = self.count + 1 + elt = self.item.dereference() + self.item = self.item + 1 + return ('[%d]' % count, elt) + + def __init__(self, val): + self.val = val + + def children(self): + return self._iterator(self.val['_M_impl']['_M_start'], + self.val['_M_impl']['_M_finish']) + + def to_string(self): + start = self.val['_M_impl']['_M_start'] + finish = self.val['_M_impl']['_M_finish'] + end = self.val['_M_impl']['_M_end_of_storage'] + return ('std::vector of length %d, capacity %d' + % (int (finish - start), int (end - start))) + + def display_hint(self): + return 'array' + +class StdVectorIteratorPrinter: + "Print std::vector::iterator" + + def __init__(self, val): + self.val = val + + def to_string(self): + return self.val['_M_current'].dereference() + +class StdStackOrQueuePrinter: + "Print a std::stack or std::queue" + + def __init__ (self, typename, val): + self.typename = typename + self.visualizer = gdb.default_visualizer(val['c']) + + def children (self): + return self.visualizer.children() + + def to_string (self): + return '%s wrapping: %s' % (self.typename, + self.visualizer.to_string()) + + def display_hint (self): + if hasattr (self.visualizer, 'display_hint'): + return self.visualizer.display_hint () + return None + +class RbtreeIterator: + def __init__(self, rbtree): + self.size = rbtree['_M_t']['_M_impl']['_M_node_count'] + self.node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left'] + self.count = 0 + + def __iter__(self): + return self + + def __len__(self): + return int (self.size) + + def next(self): + if self.count == self.size: + raise StopIteration + result = self.node + self.count = self.count + 1 + if self.count < self.size: + # Compute the next node. + node = self.node + if node.dereference()['_M_right']: + node = node.dereference()['_M_right'] + while node.dereference()['_M_left']: + node = node.dereference()['_M_left'] + else: + parent = node.dereference()['_M_parent'] + while node == parent.dereference()['_M_right']: + node = parent + parent = parent.dereference()['_M_parent'] + if node.dereference()['_M_right'] != parent: + node = parent + self.node = node + return result + +# This is a pretty printer for std::_Rb_tree_iterator (which is +# std::map::iterator), and has nothing to do with the RbtreeIterator +# class above. +class StdRbtreeIteratorPrinter: + "Print std::map::iterator" + + def __init__ (self, val): + self.val = val + + def to_string (self): + valuetype = self.val.type().template_argument(0) + nodetype = gdb.Type('std::_Rb_tree_node < %s >' % valuetype) + nodetype = nodetype.pointer() + return self.val.cast(nodetype).dereference()['_M_value_field'] + + +class StdMapPrinter: + "Print a std::map or std::multimap" + + # Turn an RbtreeIterator into a pretty-print iterator. + class _iter: + def __init__(self, rbiter, type): + self.rbiter = rbiter + self.count = 0 + self.type = type + + def __iter__(self): + return self + + def next(self): + if self.count % 2 == 0: + n = self.rbiter.next() + n = n.cast(self.type).dereference()['_M_value_field'] + self.pair = n + item = n['first'] + else: + item = self.pair['second'] + result = ('[%d]' % self.count, item) + self.count = self.count + 1 + return result + + def __init__ (self, typename, val): + self.typename = typename + self.val = val + self.iter = RbtreeIterator (val) + + def to_string (self): + return '%s with %d elements' % (self.typename, len (self.iter)) + + def children (self): + keytype = self.val.type().template_argument(0).const() + valuetype = self.val.type().template_argument(1) + nodetype = gdb.Type('std::_Rb_tree_node< std::pair< %s, %s > >' % (keytype, valuetype)) + nodetype = nodetype.pointer() + return self._iter (self.iter, nodetype) + + def display_hint (self): + return 'map' + +class StdSetPrinter: + "Print a std::set or std::multiset" + + # Turn an RbtreeIterator into a pretty-print iterator. + class _iter: + def __init__(self, rbiter, type): + self.rbiter = rbiter + self.count = 0 + self.type = type + + def __iter__(self): + return self + + def next(self): + item = self.rbiter.next() + item = item.cast(self.type).dereference()['_M_value_field'] + # FIXME: this is weird ... what to do? + # Maybe a 'set' display hint? + result = ('[%d]' % self.count, item) + self.count = self.count + 1 + return result + + def __init__ (self, typename, val): + self.typename = typename + self.val = val + self.iter = RbtreeIterator (val) + + def to_string (self): + return '%s with %d elements' % (self.typename, len (self.iter)) + + def children (self): + keytype = self.val.type().template_argument(0) + nodetype = gdb.Type('std::_Rb_tree_node< %s >' % keytype).pointer() + return self._iter (self.iter, nodetype) + +class StdBitsetPrinter: + "Print a std::bitset" + + def __init__(self, val): + self.val = val + + def to_string (self): + # If template_argument handled values, we could print the + # size. Or we could use a regexp on the type. + return 'std::bitset' + + def children (self): + words = self.val['_M_w'] + wtype = words.type() + + # The _M_w member can be either an unsigned long, or an + # array. This depends on the template specialization used. + # If it is a single long, convert to a single element list. + if wtype.code () == gdb.TYPE_CODE_ARRAY: + tsize = wtype.target ().sizeof () + else: + words = [words] + tsize = wtype.sizeof () + + nwords = wtype.sizeof() / tsize + result = [] + byte = 0 + while byte < nwords: + w = words[byte] + bit = 0 + while w != 0: + if (w & 1) != 0: + # Another spot where we could use 'set'? + result.append(('[%d]' % (byte * tsize * 8 + bit), 1)) + bit = bit + 1 + w = w >> 1 + byte = byte + 1 + return result + +class StdDequePrinter: + "Print a std::deque" + + class _iter: + def __init__(self, node, start, end, last, buffer_size): + self.node = node + self.p = start + self.end = end + self.last = last + self.buffer_size = buffer_size + self.count = 0 + + def __iter__(self): + return self + + def next(self): + if self.p == self.last: + raise StopIteration + + result = ('[%d]' % self.count, self.p.dereference()) + self.count = self.count + 1 + + # Advance the 'cur' pointer. + self.p = self.p + 1 + if self.p == self.end: + # If we got to the end of this bucket, move to the + # next bucket. + self.node = self.node + 1 + self.p = self.node[0] + self.end = self.p + self.buffer_size + + return result + + def __init__(self, val): + self.val = val + self.elttype = val.type().template_argument(0) + size = self.elttype.sizeof () + if size < 512: + self.buffer_size = int (512 / size) + else: + self.buffer_size = 1 + + def to_string(self): + start = self.val['_M_impl']['_M_start'] + end = self.val['_M_impl']['_M_finish'] + + delta_n = end['_M_node'] - start['_M_node'] - 1 + delta_s = start['_M_last'] - start['_M_cur'] + delta_e = end['_M_cur'] - end['_M_first'] + + size = self.buffer_size * delta_n + delta_s + delta_e + + return 'std::deque with %d elements' % long (size) + + def children(self): + start = self.val['_M_impl']['_M_start'] + end = self.val['_M_impl']['_M_finish'] + return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'], + end['_M_cur'], self.buffer_size) + + def display_hint (self): + return 'array' + +class StdDequeIteratorPrinter: + "Print std::deque::iterator" + + def __init__(self, val): + self.val = val + + def to_string(self): + return self.val['_M_cur'].dereference() + +class WideEncoding (gdb.Parameter): + """The target wide character set is the encoding used for wchar_t.""" + + set_doc = "Set the target wide character set." + show_doc = "Show the target wide character set." + + # FIXME: needs a complete method -- but does Parameter support it? + def __init__ (self): + super (WideEncoding, self).__init__ ("target-wide-charset", + gdb.COMMAND_SUPPORT, + gdb.PARAM_STRING) + # I think this is ok for most glibc locales. + self.value = 'UTF-32' + +target_wide_charset = WideEncoding() + +class StdStringPrinter: + "Print a std::basic_string of some kind" + + def __init__(self, encoding, val): + self.encoding = encoding + self.val = val + + def to_string(self): + # Look up the target encoding as late as possible. + encoding = self.encoding + if encoding is None: + encoding = gdb.parameter('target-charset') + elif isinstance(encoding, WideEncoding): + encoding = encoding.value + return self.val['_M_dataplus']['_M_p'].string(encoding) + + def display_hint (self): + return 'string' + +class Tr1HashtableIterator: + def __init__ (self, hash): + self.count = 0 + self.n_buckets = hash['_M_element_count'] + if self.n_buckets == 0: + self.node = False + else: + self.bucket = hash['_M_buckets'] + self.node = self.bucket[0] + self.update () + + def __iter__ (self): + return self + + def update (self): + # If we advanced off the end of the chain, move to the next + # bucket. + while self.node == 0: + self.bucket = self.bucket + 1 + self.node = self.bucket[0] + + # If we advanced off the end of the bucket array, then + # we're done. + if self.count == self.n_buckets: + self.node = False + else: + self.count = self.count + 1 + + def next (self): + if not self.node: + raise StopIteration + result = self.node.dereference()['_M_v'] + self.node = self.node.dereference()['_M_next'] + self.update () + return result + +class Tr1UnorderedSetPrinter: + "Print a tr1::unordered_set" + + def __init__ (self, typename, val): + self.typename = typename + self.val = val + + def to_string (self): + return '%s with %d elements' % (self.typename, self.val['_M_element_count']) + + @staticmethod + def format_count (i): + return '[%d]' % i + + def children (self): + counter = itertools.imap (self.format_count, itertools.count()) + return itertools.izip (counter, Tr1HashtableIterator (self.val)) + +class Tr1UnorderedMapPrinter: + "Print a tr1::unordered_map" + + def __init__ (self, typename, val): + self.typename = typename + self.val = val + + def to_string (self): + return '%s with %d elements' % (self.typename, self.val['_M_element_count']) + + @staticmethod + def flatten (list): + for elt in list: + for i in elt: + yield i + + @staticmethod + def format_one (elt): + return (elt['first'], elt['second']) + + @staticmethod + def format_count (i): + return '[%d]' % i + + def children (self): + counter = itertools.imap (self.format_count, itertools.count()) + # Map over the hash table and flatten the result. + data = self.flatten (itertools.imap (self.format_one, Tr1HashtableIterator (self.val))) + # Zip the two iterators together. + return itertools.izip (counter, data) + + def display_hint (self): + return 'map' + +def register_libstdcxx_printers (obj): + "Register libstdc++ pretty-printers with objfile Obj." + + if obj == None: + obj = gdb + + obj.pretty_printers.append (lookup_function) + +def lookup_function (val): + "Look-up and return a pretty-printer that can print val." + + # Get the type. + type = val.type (); + + # If it points to a reference, get the reference. + if type.code () == gdb.TYPE_CODE_REF: + type = type.target () + + # Get the unqualified type, stripped of typedefs. + type = type.unqualified ().strip_typedefs () + + # Get the type name. + typename = type.tag () + if typename == None: + return None + + # Iterate over local dictionary of types to determine + # if a printer is registered for that type. Return an + # instantiation of the printer if found. + for function in pretty_printers_dict: + if function.search (typename): + return pretty_printers_dict[function] (val) + + # Cannot find a pretty printer. Return None. + return None + +def build_libstdcxx_dictionary (): + # libstdc++ objects requiring pretty-printing. + # In order from: + # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html + pretty_printers_dict[re.compile('^std::basic_string$')] = lambda val: StdStringPrinter(None, val) + pretty_printers_dict[re.compile('^std::basic_string$')] = lambda val: StdStringPrinter(target_wide_charset, val) + pretty_printers_dict[re.compile('^std::basic_string$')] = lambda val: StdStringPrinter('UTF-16', val) + pretty_printers_dict[re.compile('^std::basic_string$')] = lambda val: StdStringPrinter('UTF-32', val) + pretty_printers_dict[re.compile('^std::bitset<.*>$')] = StdBitsetPrinter + pretty_printers_dict[re.compile('^std::deque<.*>$')] = StdDequePrinter + pretty_printers_dict[re.compile('^std::list<.*>$')] = StdListPrinter + pretty_printers_dict[re.compile('^std::map<.*>$')] = lambda val: StdMapPrinter("std::map", val) + pretty_printers_dict[re.compile('^std::multimap<.*>$')] = lambda val: StdMapPrinter("std::multimap", val) + pretty_printers_dict[re.compile('^std::multiset<.*>$')] = lambda val: StdSetPrinter("std::multiset", val) + pretty_printers_dict[re.compile('^std::priority_queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::priority_queue", val) + pretty_printers_dict[re.compile('^std::queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::queue", val) + pretty_printers_dict[re.compile('^std::set<.*>$')] = lambda val: StdSetPrinter("std::set", val) + pretty_printers_dict[re.compile('^std::stack<.*>$')] = lambda val: StdStackOrQueuePrinter("std::stack", val) + pretty_printers_dict[re.compile('^std::unique_ptr<.*>$')] = UniquePointerPrinter + pretty_printers_dict[re.compile('^std::vector<.*>$')] = StdVectorPrinter + + # These are the C++0x printers. They also exist in the standard namespace. + # For array - the default GDB pretty-printer seems reasonable. + pretty_printers_dict[re.compile('^std::(tr1::)?shared_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::shared_ptr', val) + pretty_printers_dict[re.compile('^std::(tr1::)?weak_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::weak_ptr', val) + pretty_printers_dict[re.compile('^std::(tr1::)?unordered_map<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_map', val) + pretty_printers_dict[re.compile('^std::(tr1::)?unordered_set<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_set', val) + pretty_printers_dict[re.compile('^std::(tr1::)?unordered_multimap<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_multimap', val) + pretty_printers_dict[re.compile('^std::(tr1::)?unordered_multiset<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_multiset', val) + + + # Extensions to std, tr1 pretty-printers. + pretty_printers_dict[re.compile('^__gnu_cxx::slist<.*>$')] = StdSlistPrinter + + if True: + # These shouldn't be necessary, if GDB "print *i" worked. + # But it often doesn't, so here they are. + pretty_printers_dict[re.compile('^std::_List_iterator<.*>$')] = lambda val: StdListIteratorPrinter(val) + pretty_printers_dict[re.compile('^std::_List_const_iterator<.*>$')] = lambda val: StdListIteratorPrinter(val) + pretty_printers_dict[re.compile('^std::_Rb_tree_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val) + pretty_printers_dict[re.compile('^std::_Rb_tree_const_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val) + pretty_printers_dict[re.compile('^std::_Deque_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val) + pretty_printers_dict[re.compile('^std::_Deque_const_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val) + pretty_printers_dict[re.compile('^__gnu_cxx::__normal_iterator<.*>$')] = lambda val: StdVectorIteratorPrinter(val) + pretty_printers_dict[re.compile('^__gnu_cxx::_Slist_iterator<.*>$')] = lambda val: StdSlistIteratorPrinter(val) + +pretty_printers_dict = {} + +build_libstdcxx_dictionary () diff --git a/gdb/python/python-block.c b/gdb/python/python-block.c new file mode 100644 index 0000000..8019e9d --- /dev/null +++ b/gdb/python/python-block.c @@ -0,0 +1,265 @@ +/* Python interface to blocks. + + Copyright (C) 2008 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "block.h" +#include "dictionary.h" +#include "symtab.h" +#include "python-internal.h" + +typedef struct { + PyObject_HEAD + struct block *block; +} block_object; + +typedef struct { + PyObject_HEAD + struct dictionary *dict; + struct dict_iterator iter; + int initialized_p; +} block_syms_iterator_object; + +static PyTypeObject block_syms_iterator_object_type; + +static PyObject * +blpy_iter (PyObject *self) +{ + block_syms_iterator_object *block_iter_obj; + + block_iter_obj = PyObject_New (block_syms_iterator_object, + &block_syms_iterator_object_type); + if (block_iter_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, + "Could not allocate iterator object."); + return NULL; + } + + block_iter_obj->dict = BLOCK_DICT (((block_object *) self)->block); + block_iter_obj->initialized_p = 0; + + return (PyObject *) block_iter_obj; +} + +static PyObject * +blpy_get_start (PyObject *self, void *closure) +{ + block_object *self_block = (block_object *) self; + + return PyLong_FromUnsignedLongLong (BLOCK_START (self_block->block)); +} + +static PyObject * +blpy_get_end (PyObject *self, void *closure) +{ + block_object *self_block = (block_object *) self; + + return PyLong_FromUnsignedLongLong (BLOCK_END (self_block->block)); +} + +static PyObject * +blpy_get_function (PyObject *self, void *closure) +{ + block_object *self_block = (block_object *) self; + struct symbol *sym; + + sym = BLOCK_FUNCTION (self_block->block); + if (sym) + return symbol_to_symbol_object (sym); + + Py_RETURN_NONE; +} + +static PyObject * +blpy_get_superblock (PyObject *self, void *closure) +{ + block_object *self_block = (block_object *) self; + struct block *block; + + block = BLOCK_SUPERBLOCK (self_block->block); + if (block) + return block_to_block_object (block); + + Py_RETURN_NONE; +} + +PyObject * +block_to_block_object (struct block *block) +{ + block_object *block_obj; + + block_obj = PyObject_New (block_object, &block_object_type); + if (block_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate block object."); + return NULL; + } + + block_obj->block = block; + + return (PyObject *) block_obj; +} + +struct block * +block_object_to_block (PyObject *obj) +{ + if (! PyObject_TypeCheck (obj, &block_object_type)) + return NULL; + return ((block_object *) obj)->block; +} + +static PyObject * +blpy_block_syms_iter (PyObject *self) +{ + return self; +} + +static PyObject * +blpy_block_syms_iternext (PyObject *self) +{ + block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self; + struct symbol *sym; + + if (!iter_obj->initialized_p) + { + sym = dict_iterator_first (iter_obj->dict, &(iter_obj->iter)); + iter_obj->initialized_p = 1; + } + else + sym = dict_iterator_next (&(iter_obj->iter)); + + return (sym == NULL)? NULL : symbol_to_symbol_object (sym); +} + +/* Return the innermost lexical block containing the specified pc value, + or 0 if there is none. */ + +PyObject * +gdbpy_block_for_pc (PyObject *self, PyObject *args) +{ + unsigned PY_LONG_LONG pc; + struct block *block; + PyObject *sym_obj; + + if (!PyArg_ParseTuple (args, "K", &pc)) + return NULL; + + block = block_for_pc (pc); + if (block) + return block_to_block_object (block); + + Py_RETURN_NONE; +} + +void +gdbpy_initialize_blocks (void) +{ + block_object_type.tp_new = PyType_GenericNew; + if (PyType_Ready (&block_object_type) < 0) + return; + + block_syms_iterator_object_type.tp_new = PyType_GenericNew; + if (PyType_Ready (&block_syms_iterator_object_type) < 0) + return; + + Py_INCREF (&block_object_type); + PyModule_AddObject (gdb_module, "Block", (PyObject *) &block_object_type); + + Py_INCREF (&block_syms_iterator_object_type); + PyModule_AddObject (gdb_module, "BlockIterator", + (PyObject *) &block_syms_iterator_object_type); +} + + + +static PyGetSetDef block_object_getset[] = { + { "start", blpy_get_start, NULL, "Start address of the block.", NULL }, + { "end", blpy_get_end, NULL, "End address of the block.", NULL }, + { "function", blpy_get_function, NULL, + "Symbol that names the block, or None.", NULL }, + { "superblock", blpy_get_superblock, NULL, + "Block containing the block, or None.", NULL }, + { NULL } /* Sentinel */ +}; + +PyTypeObject block_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Block", /*tp_name*/ + sizeof (block_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ + "GDB block object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + blpy_iter, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + block_object_getset /* tp_getset */ +}; + +static PyTypeObject block_syms_iterator_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.BlockIterator", /*tp_name*/ + sizeof (block_syms_iterator_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ + "GDB block syms iterator object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + blpy_block_syms_iter, /* tp_iter */ + blpy_block_syms_iternext, /* tp_iternext */ + 0 /* tp_methods */ +}; diff --git a/gdb/python/python-breakpoint.c b/gdb/python/python-breakpoint.c new file mode 100644 index 0000000..ec80419 --- /dev/null +++ b/gdb/python/python-breakpoint.c @@ -0,0 +1,665 @@ +/* Python interface to breakpoints + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "value.h" +#include "exceptions.h" +#include "python-internal.h" +#include "charset.h" +#include "breakpoint.h" +#include "gdbcmd.h" +#include "gdbthread.h" +#include "observer.h" + + +/* From breakpoint.c. */ +extern struct breakpoint *breakpoint_chain; + + +typedef struct breakpoint_object breakpoint_object; + +static PyTypeObject breakpoint_object_type; + +/* A dynamically allocated vector of breakpoint objects. Each + breakpoint has a number. A breakpoint is valid if its slot in this + vector is non-null. When a breakpoint is deleted, we drop our + reference to it and zero its slot; this is how we let the Python + object have a lifetime which is independent from that of the gdb + breakpoint. */ +static breakpoint_object **bppy_breakpoints; + +/* Number of slots in bppy_breakpoints. */ +static int bppy_slots; + +/* Number of live breakpoints. */ +static int bppy_live; + +/* Variables used to pass information between the Breakpoint + constructor and the breakpoint-created hook function. */ +static breakpoint_object *bppy_pending_object; + +struct breakpoint_object +{ + PyObject_HEAD + + /* The breakpoint number according to gdb. */ + int number; + + /* The gdb breakpoint object, or NULL if the breakpoint has been + deleted. */ + struct breakpoint *bp; +}; + +/* Evaluate to true if the breakpoint NUM is valid, false otherwise. */ +#define BPPY_VALID_P(Num) \ + ((Num) >= 0 \ + && (Num) < bppy_slots \ + && bppy_breakpoints[Num] != NULL) + +/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python + exception if it is invalid. */ +#define BPPY_REQUIRE_VALID(Breakpoint) \ + do { \ + if (! BPPY_VALID_P ((Breakpoint)->number)) \ + return PyErr_Format (PyExc_RuntimeError, "breakpoint %d is invalid", \ + (Breakpoint)->number); \ + } while (0) + +/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python + exception if it is invalid. This macro is for use in setter functions. */ +#define BPPY_SET_REQUIRE_VALID(Breakpoint) \ + do { \ + if (! BPPY_VALID_P ((Breakpoint)->number)) \ + { \ + PyErr_Format (PyExc_RuntimeError, "breakpoint %d is invalid", \ + (Breakpoint)->number); \ + return -1; \ + } \ + } while (0) + +/* Python function which checks the validity of a breakpoint object. */ +static PyObject * +bppy_is_valid (PyObject *self, PyObject *args) +{ + if (((breakpoint_object *) self)->bp) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +/* Python function to test whether or not the breakpoint is enabled. */ +static PyObject * +bppy_get_enabled (PyObject *self, void *closure) +{ + if (! ((breakpoint_object *) self)->bp) + Py_RETURN_FALSE; + /* Not clear what we really want here. */ + if (((breakpoint_object *) self)->bp->enable_state == bp_enabled) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +/* Python function to test whether or not the breakpoint is silent. */ +static PyObject * +bppy_get_silent (PyObject *self, void *closure) +{ + BPPY_REQUIRE_VALID ((breakpoint_object *) self); + if (((breakpoint_object *) self)->bp->silent) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +/* Python function to set the enabled state of a breakpoint. */ +static int +bppy_set_enabled (PyObject *self, PyObject *newvalue, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + int cmp; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, "cannot delete `enabled' attribute"); + return -1; + } + else if (! PyBool_Check (newvalue)) + { + PyErr_SetString (PyExc_TypeError, + "the value of `enabled' must be a boolean"); + return -1; + } + + cmp = PyObject_IsTrue (newvalue); + if (cmp < 0) + return -1; + else if (cmp == 1) + enable_breakpoint (self_bp->bp); + else + disable_breakpoint (self_bp->bp); + return 0; +} + +/* Python function to set the 'silent' state of a breakpoint. */ +static int +bppy_set_silent (PyObject *self, PyObject *newvalue, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + int cmp; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, "cannot delete `silent' attribute"); + return -1; + } + else if (! PyBool_Check (newvalue)) + { + PyErr_SetString (PyExc_TypeError, + "the value of `silent' must be a boolean"); + return -1; + } + + cmp = PyObject_IsTrue (newvalue); + if (cmp < 0) + return -1; + else + self_bp->bp->silent = cmp; + + return 0; +} + +/* Python function to set the thread of a breakpoint. */ +static int +bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + int id; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, "cannot delete `thread' attribute"); + return -1; + } + else if (PyInt_Check (newvalue)) + { + id = (int) PyInt_AsLong (newvalue); + if (! valid_thread_id (id)) + { + PyErr_SetString (PyExc_RuntimeError, "invalid thread id"); + return -1; + } + } + else if (newvalue == Py_None) + id = -1; + else + { + PyErr_SetString (PyExc_TypeError, + "the value of `thread' must be an integer or None"); + return -1; + } + + self_bp->bp->thread = id; + + return 0; +} + +/* Python function to set the ignore count of a breakpoint. */ +static int +bppy_set_ignore_count (PyObject *self, PyObject *newvalue, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + long value; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, + "cannot delete `ignore_count' attribute"); + return -1; + } + else if (! PyInt_Check (newvalue)) + { + PyErr_SetString (PyExc_TypeError, + "the value of `ignore_count' must be an integer"); + return -1; + } + + value = PyInt_AsLong (newvalue); + if (value < 0) + value = 0; + set_ignore_count (self_bp->number, (int) value, 0); + + return 0; +} + +/* Python function to set the hit count of a breakpoint. */ +static int +bppy_set_hit_count (PyObject *self, PyObject *newvalue, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, "cannot delete `hit_count' attribute"); + return -1; + } + else if (! PyInt_Check (newvalue) || PyInt_AsLong (newvalue) != 0) + { + PyErr_SetString (PyExc_AttributeError, + "the value of `hit_count' must be zero"); + return -1; + } + + self_bp->bp->hit_count = 0; + + return 0; +} + +/* Python function to get the location of a breakpoint. */ +static PyObject * +bppy_get_location (PyObject *self, void *closure) +{ + char *str; + + BPPY_REQUIRE_VALID ((breakpoint_object *) self); + str = ((breakpoint_object *) self)->bp->addr_string; + /* FIXME: watchpoints? tracepoints? */ + if (! str) + str = ""; + return PyString_Decode (str, strlen (str), host_charset (), NULL); +} + +/* Python function to get the condition expression of a breakpoint. */ +static PyObject * +bppy_get_condition (PyObject *self, void *closure) +{ + char *str; + BPPY_REQUIRE_VALID ((breakpoint_object *) self); + + str = ((breakpoint_object *) self)->bp->cond_string; + if (! str) + Py_RETURN_NONE; + return PyString_Decode (str, strlen (str), host_charset (), NULL); +} + +static int +bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure) +{ + char *exp; + breakpoint_object *self_bp = (breakpoint_object *) self; + volatile struct gdb_exception except; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, "cannot delete `condition' attribute"); + return -1; + } + else if (newvalue == Py_None) + exp = ""; + else + { + exp = python_string_to_host_string (newvalue); + if (exp == NULL) + return -1; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + set_breakpoint_condition (self_bp->bp, exp, 0); + } + GDB_PY_SET_HANDLE_EXCEPTION (except); + + return 0; +} + +/* Python function to get the commands attached to a breakpoint. */ +static PyObject * +bppy_get_commands (PyObject *self, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + long length; + volatile struct gdb_exception except; + struct ui_file *string_file; + struct cleanup *chain; + PyObject *result; + char *cmdstr; + + BPPY_REQUIRE_VALID (self_bp); + + if (! self_bp->bp->commands) + Py_RETURN_NONE; + + string_file = mem_fileopen (); + chain = make_cleanup_ui_file_delete (string_file); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + /* FIXME: this can fail. Maybe we need to be making a new + ui_out object here? */ + ui_out_redirect (uiout, string_file); + print_command_lines (uiout, self_bp->bp->commands, 0); + ui_out_redirect (uiout, NULL); + } + cmdstr = ui_file_xstrdup (string_file, &length); + GDB_PY_HANDLE_EXCEPTION (except); + + result = PyString_Decode (cmdstr, strlen (cmdstr), host_charset (), NULL); + do_cleanups (chain); + xfree (cmdstr); + return result; +} + +/* Python function to get the breakpoint's number. */ +static PyObject * +bppy_get_number (PyObject *self, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + + return PyInt_FromLong (self_bp->number); +} + +/* Python function to get the breakpoint's thread ID. */ +static PyObject * +bppy_get_thread (PyObject *self, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + + if (self_bp->bp->thread == -1) + Py_RETURN_NONE; + + return PyInt_FromLong (self_bp->bp->thread); +} + +/* Python function to get the breakpoint's hit count. */ +static PyObject * +bppy_get_hit_count (PyObject *self, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + + return PyInt_FromLong (self_bp->bp->hit_count); +} + +/* Python function to get the breakpoint's ignore count. */ +static PyObject * +bppy_get_ignore_count (PyObject *self, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + + return PyInt_FromLong (self_bp->bp->ignore_count); +} + +/* Python function to create a new breakpoint. */ +static PyObject * +bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) +{ + PyObject *result; + char *spec; + volatile struct gdb_exception except; + + /* FIXME: allow condition, thread, temporary, ... ? */ + if (! PyArg_ParseTuple (args, "s", &spec)) + return NULL; + result = subtype->tp_alloc (subtype, 0); + if (! result) + return NULL; + bppy_pending_object = (breakpoint_object *) result; + bppy_pending_object->number = -1; + bppy_pending_object->bp = NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + set_breakpoint (spec, NULL, 0, 0, -1, 0, AUTO_BOOLEAN_TRUE, + 1 /*enabled*/); + } + if (except.reason < 0) + { + subtype->tp_free (result); + return PyErr_Format (except.reason == RETURN_QUIT + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, + "%s", except.message); + } + + BPPY_REQUIRE_VALID ((breakpoint_object *) result); + return result; +} + + + +/* Static function to return a tuple holding all breakpoints. */ + +PyObject * +gdbpy_breakpoints (PyObject *self, PyObject *args) +{ + PyObject *result; + + if (bppy_live == 0) + Py_RETURN_NONE; + + result = PyTuple_New (bppy_live); + if (result) + { + int i, out = 0; + for (i = 0; out < bppy_live; ++i) + { + if (! bppy_breakpoints[i]) + continue; + Py_INCREF (bppy_breakpoints[i]); + PyTuple_SetItem (result, out, (PyObject *) bppy_breakpoints[i]); + ++out; + } + } + return result; +} + + + +/* Event callback functions. */ + +/* Callback that is used when a breakpoint is created. This function + will create a new Python breakpoint object. */ +static void +gdbpy_breakpoint_created (int num) +{ + breakpoint_object *newbp; + struct breakpoint *bp; + PyGILState_STATE state; + + if (num < 0) + return; + + for (bp = breakpoint_chain; bp; bp = bp->next) + if (bp->number == num) + break; + if (! bp) + return; + + if (num >= bppy_slots) + { + int old = bppy_slots; + bppy_slots = bppy_slots * 2 + 10; + bppy_breakpoints + = (breakpoint_object **) xrealloc (bppy_breakpoints, + (bppy_slots + * sizeof (breakpoint_object *))); + memset (&bppy_breakpoints[old], 0, + (bppy_slots - old) * sizeof (PyObject *)); + } + + ++bppy_live; + + state = PyGILState_Ensure (); + + if (bppy_pending_object) + { + newbp = bppy_pending_object; + bppy_pending_object = NULL; + } + else + newbp = PyObject_New (breakpoint_object, &breakpoint_object_type); + if (newbp) + { + PyObject *hookfn; + + newbp->number = num; + newbp->bp = bp; + bppy_breakpoints[num] = newbp; + + hookfn = gdbpy_get_hook_function ("new_breakpoint"); + if (hookfn) + { + PyObject *result; + result = PyObject_CallFunctionObjArgs (hookfn, newbp, NULL); + if (result) + { + Py_DECREF (result); + } + Py_DECREF (hookfn); + } + } + + /* Just ignore errors here. */ + PyErr_Clear (); + + PyGILState_Release (state); +} + +/* Callback that is used when a breakpoint is deleted. This will + invalidate the corresponding Python object. */ +static void +gdbpy_breakpoint_deleted (int num) +{ + PyGILState_STATE state; + + state = PyGILState_Ensure (); + if (BPPY_VALID_P (num)) + { + bppy_breakpoints[num]->bp = NULL; + Py_DECREF (bppy_breakpoints[num]); + bppy_breakpoints[num] = NULL; + --bppy_live; + } + PyGILState_Release (state); +} + + + +/* Initialize the Python breakpoint code. */ +void +gdbpy_initialize_breakpoints (void) +{ + breakpoint_object_type.tp_new = bppy_new; + if (PyType_Ready (&breakpoint_object_type) < 0) + return; + + Py_INCREF (&breakpoint_object_type); + PyModule_AddObject (gdb_module, "Breakpoint", + (PyObject *) &breakpoint_object_type); + + observer_attach_breakpoint_created (gdbpy_breakpoint_created); + observer_attach_breakpoint_deleted (gdbpy_breakpoint_deleted); +} + + + +static PyGetSetDef breakpoint_object_getset[] = { + { "enabled", bppy_get_enabled, bppy_set_enabled, + "Boolean telling whether the breakpoint is enabled.", NULL }, + { "silent", bppy_get_silent, bppy_set_silent, + "Boolean telling whether the breakpoint is silent.", NULL }, + { "thread", bppy_get_thread, bppy_set_thread, + "Thread ID for the breakpoint.\n\ +If the value is a thread ID (integer), then this is a thread-specific breakpoint.\n\ +If the value is None, then this breakpoint not thread-specific.\n\ +No other type of value can be used.", NULL }, + { "ignore_count", bppy_get_ignore_count, bppy_set_ignore_count, + "Number of times this breakpoint should be automatically continued.", + NULL }, + { "number", bppy_get_number, NULL, + "Breakpoint's number assigned by GDB.", NULL }, + { "hit_count", bppy_get_hit_count, bppy_set_hit_count, + "Number of times the breakpoint has been hit.\n\ +Can be set to zero to clear the count. No other value is valid\n\ +when setting this property.", NULL }, + { "location", bppy_get_location, NULL, + "Location of the breakpoint, as specified by the user.", NULL}, + { "condition", bppy_get_condition, bppy_set_condition, + "Condition of the breakpoint, as specified by the user,\ +or None if no condition set."}, + { "commands", bppy_get_commands, NULL, + "Commands of the breakpoint, as specified by the user."}, + { NULL } /* Sentinel. */ +}; + +static PyMethodDef breakpoint_object_methods[] = +{ + { "is_valid", bppy_is_valid, METH_NOARGS, + "Return true if this breakpoint is valid, false if not." }, + { NULL } /* Sentinel. */ +}; + +static PyTypeObject breakpoint_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Breakpoint", /*tp_name*/ + sizeof (breakpoint_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB breakpoint object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + breakpoint_object_methods, /* tp_methods */ + 0, /* tp_members */ + breakpoint_object_getset /* tp_getset */ +}; diff --git a/gdb/python/python-cmd.c b/gdb/python/python-cmd.c index 36cde34..e6e3ac0 100644 --- a/gdb/python/python-cmd.c +++ b/gdb/python/python-cmd.c @@ -47,8 +47,7 @@ static struct cmdpy_completer completers[] = #define N_COMPLETERS (sizeof (completers) / sizeof (completers[0])) -/* A gdb command. For the time being only ordinary commands (not - set/show commands) are allowed. */ +/* A gdb command. */ struct cmdpy_object { PyObject_HEAD @@ -68,7 +67,6 @@ typedef struct cmdpy_object cmdpy_object; static PyTypeObject cmdpy_object_type; - /* Constants used by this module. */ static PyObject *invoke_cst; static PyObject *complete_cst; @@ -265,10 +263,13 @@ cmdpy_completer (struct cmd_list_element *command, char *text, char *word) *BASE_LIST is set to the final prefix command's list of *sub-commands. + START_LIST is the list in which the search starts. + This function returns the xmalloc()d name of the new command. On error sets the Python error and returns NULL. */ -static char * -parse_command_name (char *text, struct cmd_list_element ***base_list) +char * +gdbpy_parse_command_name (char *text, struct cmd_list_element ***base_list, + struct cmd_list_element **start_list) { struct cmd_list_element *elt; int len = strlen (text); @@ -301,7 +302,7 @@ parse_command_name (char *text, struct cmd_list_element ***base_list) ; if (i < 0) { - *base_list = &cmdlist; + *base_list = start_list; return result; } @@ -310,7 +311,7 @@ parse_command_name (char *text, struct cmd_list_element ***base_list) prefix_text[i + 1] = '\0'; text = prefix_text; - elt = lookup_cmd_1 (&text, cmdlist, NULL, 1); + elt = lookup_cmd_1 (&text, *start_list, NULL, 1); if (!elt || elt == (struct cmd_list_element *) -1) { PyErr_Format (PyExc_RuntimeError, _("could not find command prefix %s"), @@ -336,16 +337,16 @@ parse_command_name (char *text, struct cmd_list_element ***base_list) /* Object initializer; sets up gdb-side structures for command. - Use: __init__(NAME, CMDCLASS, [COMPLETERCLASS, [PREFIX]]). + Use: __init__(NAME, COMMAND_CLASS, [COMPLETER_CLASS, [PREFIX]]). NAME is the name of the command. It may consist of multiple words, in which case the final word is the name of the new command, and earlier words must be prefix commands. - CMDCLASS is the kind of command. It should be one of the COMMAND_* + COMMAND_CLASS is the kind of command. It should be one of the COMMAND_* constants defined in the gdb module. - COMPLETERCLASS is the kind of completer. If not given, the + COMPLETER_CLASS is the kind of completer. If not given, the "complete" method will be used. Otherwise, it should be one of the COMPLETE_* constants defined in the gdb module. @@ -356,7 +357,7 @@ parse_command_name (char *text, struct cmd_list_element ***base_list) */ static int -cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds) +cmdpy_init (PyObject *self, PyObject *args, PyObject *kw) { cmdpy_object *obj = (cmdpy_object *) self; char *name; @@ -366,6 +367,8 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds) volatile struct gdb_exception except; struct cmd_list_element **cmd_list; char *cmd_name, *pfx_name; + static char *keywords[] = { "name", "command_class", "completer_class", + "prefix", NULL }; PyObject *is_prefix = NULL; int cmp; @@ -378,7 +381,7 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds) return -1; } - if (! PyArg_ParseTuple (args, "si|iO", &name, &cmdtype, + if (! PyArg_ParseTupleAndKeywords (args, kw, "si|iO", keywords, &name, &cmdtype, &completetype, &is_prefix)) return -1; @@ -399,7 +402,7 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds) return -1; } - cmd_name = parse_command_name (name, &cmd_list); + cmd_name = gdbpy_parse_command_name (name, &cmd_list, &cmdlist); if (! cmd_name) return -1; diff --git a/gdb/python/python-frame.c b/gdb/python/python-frame.c new file mode 100644 index 0000000..c257ac3 --- /dev/null +++ b/gdb/python/python-frame.c @@ -0,0 +1,686 @@ +/* Python interface to stack frames + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "charset.h" +#include "block.h" +#include "frame.h" +#include "exceptions.h" +#include "symtab.h" +#include "stack.h" +#include "value.h" +#include "python-internal.h" + +typedef struct { + PyObject_HEAD + struct frame_id frame_id; + struct gdbarch *gdbarch; + + /* Marks that the FRAME_ID member actually holds the ID of the frame next + to this, and not this frames' ID itself. This is a hack to permit Python + frame objects which represent invalid frames (i.e., the last frame_info + in a corrupt stack). The problem arises from the fact that this code + relies on FRAME_ID to uniquely identify a frame, which is not always true + for the last "frame" in a corrupt stack (it can have a null ID, or the same + ID as the previous frame). Whenever get_prev_frame returns NULL, we + record the frame_id of the next frame and set FRAME_ID_IS_NEXT to 1. */ + int frame_id_is_next; +} frame_object; + +/* Require a valid frame. This must be called inside a TRY_CATCH, or + another context in which a gdb exception is allowed. */ +#define FRAPY_REQUIRE_VALID(frame_obj, frame) \ + do { \ + frame = frame_object_to_frame_info (frame_obj); \ + if (frame == NULL) \ + error ("Frame is invalid."); \ + } while (0) + +static PyTypeObject frame_object_type; + +/* Returns the frame_info object corresponding to the given Python Frame + object. If the frame doesn't exist anymore (the frame id doesn't + correspond to any frame in the inferior), returns NULL. */ + +static struct frame_info * +frame_object_to_frame_info (frame_object *frame_obj) +{ + struct frame_info *frame; + + frame = frame_find_by_id (frame_obj->frame_id); + if (frame == NULL) + return NULL; + + if (frame_obj->frame_id_is_next) + frame = get_prev_frame (frame); + + return frame; +} + +/* Called by the Python interpreter to obtain string representation + of the object. */ + +static PyObject * +frapy_str (PyObject *self) +{ + char *s; + long len; + PyObject *result; + struct ui_file *strfile; + + strfile = mem_fileopen (); + fprint_frame_id (strfile, ((frame_object *) self)->frame_id); + s = ui_file_xstrdup (strfile, &len); + result = PyString_FromString (s); + xfree (s); + + return result; +} + +/* Implementation of gdb.Frame.is_valid (self) -> Boolean. + Returns True if the frame corresponding to the frame_id of this + object still exists in the inferior. */ + +static PyObject * +frapy_is_valid (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + + frame = frame_object_to_frame_info ((frame_object *) self); + if (frame == NULL) + Py_RETURN_FALSE; + + Py_RETURN_TRUE; +} + +/* Implementation of gdb.Frame.equals (self, other) -> Boolean. */ + +static PyObject * +frapy_equal_p (PyObject *self, PyObject *args) +{ + int equalp = 0; /* Initialize to appease gcc warning. */ + frame_object *self_frame = (frame_object *) self; + frame_object *other; + volatile struct gdb_exception except; + + if (!PyArg_ParseTuple (args, "O!", &frame_object_type, &other)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + equalp = frame_id_eq (self_frame->frame_id, other->frame_id); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (equalp) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + +/* Implementation of gdb.Frame.name (self) -> String. + Returns the name of the function corresponding to this frame. */ + +static PyObject * +frapy_name (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + char *name; + enum language lang; + PyObject *result; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + find_frame_funname (frame, &name, &lang); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (name) + result = target_string_to_unicode (name, strlen (name)); + else + { + result = Py_None; + Py_INCREF (Py_None); + } + + return result; +} + +/* Implementation of gdb.Frame.type (self) -> Integer. + Returns the frame type, namely one of the gdb.*_FRAME constants. */ + +static PyObject * +frapy_type (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + enum frame_type type = NORMAL_FRAME;/* Initialize to appease gcc warning. */ + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + type = get_frame_type (frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyInt_FromLong (type); +} + +/* Implementation of gdb.Frame.unwind_stop_reason (self) -> Integer. + Returns one of the gdb.FRAME_UNWIND_* constants. */ + +static PyObject * +frapy_unwind_stop_reason (PyObject *self, PyObject *args) +{ + struct frame_info *frame = NULL; /* Initialize to appease gcc warning. */ + volatile struct gdb_exception except; + enum unwind_stop_reason stop_reason; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + stop_reason = get_frame_unwind_stop_reason (frame); + + return PyInt_FromLong (stop_reason); +} + +/* Implementation of gdb.Frame.pc (self) -> Long. + Returns the frame's resume address. */ + +static PyObject * +frapy_pc (PyObject *self, PyObject *args) +{ + CORE_ADDR pc = 0; /* Initialize to appease gcc warning. */ + struct frame_info *frame; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + pc = get_frame_pc (frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyLong_FromUnsignedLongLong (pc); +} + +/* Implementation of gdb.Frame.block (self) -> gdb.Block. + Returns the frame's code block. */ + +static PyObject * +frapy_block (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + struct block *block = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + block = block_for_pc (get_frame_address_in_block (frame)); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (block) + return block_to_block_object (block); + + Py_RETURN_NONE; +} + + +/* Implementation of gdb.Frame.addr_in_block (self) -> Long. + Returns an address which falls within the frame's code block. */ + +static PyObject * +frapy_addr_in_block (PyObject *self, PyObject *args) +{ + CORE_ADDR pc = 0; /* Initialize to appease gcc warning. */ + struct frame_info *frame; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + pc = get_frame_address_in_block (frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyLong_FromUnsignedLongLong (pc); +} + +/* Convert a frame_info struct to a Python Frame object. + Sets a Python exception and returns NULL on error. */ + +static frame_object * +frame_info_to_frame_object (struct frame_info *frame) +{ + frame_object *frame_obj; + + frame_obj = PyObject_New (frame_object, &frame_object_type); + if (frame_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate frame object."); + return NULL; + } + + /* Try to get the previous frame, to determine if this is the last frame + in a corrupt stack. If so, we need to store the frame_id of the next + frame and not of this one (which is possibly invalid). */ + if (get_prev_frame (frame) == NULL + && get_frame_unwind_stop_reason (frame) != UNWIND_NO_REASON + && get_next_frame (frame) != NULL) + { + frame_obj->frame_id = get_frame_id (get_next_frame (frame)); + frame_obj->frame_id_is_next = 1; + } + else + { + frame_obj->frame_id = get_frame_id (frame); + frame_obj->frame_id_is_next = 0; + } + + frame_obj->gdbarch = get_frame_arch (frame); + + return frame_obj; +} + +/* Implementation of gdb.Frame.older (self) -> gdb.Frame. + Returns the frame immediately older (outer) to this frame, or None if + there isn't one. */ + +static PyObject * +frapy_older (PyObject *self, PyObject *args) +{ + struct frame_info *frame, *prev; + volatile struct gdb_exception except; + PyObject *prev_obj = NULL; /* Initialize to appease gcc warning. */ + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + prev = get_prev_frame (frame); + if (prev) + prev_obj = (PyObject *) frame_info_to_frame_object (prev); + else + { + Py_INCREF (Py_None); + prev_obj = Py_None; + } + } + GDB_PY_HANDLE_EXCEPTION (except); + + return prev_obj; +} + +/* Implementation of gdb.Frame.newer (self) -> gdb.Frame. + Returns the frame immediately newer (inner) to this frame, or None if + there isn't one. */ + +static PyObject * +frapy_newer (PyObject *self, PyObject *args) +{ + struct frame_info *frame, *next; + volatile struct gdb_exception except; + PyObject *next_obj = NULL; /* Initialize to appease gcc warning. */ + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + next = get_next_frame (frame); + if (next) + next_obj = (PyObject *) frame_info_to_frame_object (next); + else + { + Py_INCREF (Py_None); + next_obj = Py_None; + } + } + GDB_PY_HANDLE_EXCEPTION (except); + + return next_obj; +} + +/* Implementation of gdb.Frame.find_sal (self) -> gdb.Symtab_and_line. + Returns the frame's symtab and line. */ + +static PyObject * +frapy_find_sal (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + struct symtab_and_line sal; + volatile struct gdb_exception except; + PyObject *sal_obj = NULL; /* Initialize to appease gcc warning. */ + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + find_frame_sal (frame, &sal); + sal_obj = symtab_and_line_to_sal_object (sal); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return sal_obj; +} + +/* Implementation of gdb.Frame.read_var (self, variable) -> gdb.Value. + Returns the value of the given variable in this frame. The argument can be + either a gdb.Symbol or a string. Returns None if GDB can't find the + specified variable. */ + +static PyObject * +frapy_read_var (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + PyObject *sym_obj; + struct symbol *var = NULL; /* gcc-4.3.2 false warning. */ + struct value *val = NULL; + volatile struct gdb_exception except; + + if (!PyArg_ParseTuple (args, "O", &sym_obj)) + return NULL; + + if (PyObject_TypeCheck (sym_obj, &symbol_object_type)) + var = symbol_object_to_symbol (sym_obj); + else if (gdbpy_is_string (sym_obj)) + { + char *var_name; + struct block *block = NULL; + struct cleanup *cleanup; + volatile struct gdb_exception except; + + var_name = python_string_to_target_string (sym_obj); + if (!var_name) + return NULL; + cleanup = make_cleanup (xfree, var_name); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + block = block_for_pc (get_frame_address_in_block (frame)); + var = lookup_symbol (var_name, block, VAR_DOMAIN, NULL); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (!var) + { + PyErr_Format (PyExc_ValueError, + _("variable '%s' not found"), var_name); + do_cleanups (cleanup); + + return NULL; + } + + do_cleanups (cleanup); + } + else + { + PyErr_SetString (PyExc_TypeError, + _("argument must be a symbol or string")); + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + val = read_var_value (var, frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (val) + return value_to_value_object (val); + + Py_RETURN_NONE; +} + +/* Implementation of gdb.frames () -> (gdb.Frame, ...). + Returns a tuple of all frame objects. */ + +PyObject * +gdbpy_frames (PyObject *self, PyObject *args) +{ + int result = 0; + struct frame_info *frame; + frame_object *frame_obj; + PyObject *list, *tuple; + volatile struct gdb_exception except; + + list = PyList_New (0); + if (list == NULL) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate frames list."); + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + for (frame = get_current_frame (); frame; frame = get_prev_frame (frame)) + { + frame_obj = frame_info_to_frame_object (frame); + if (frame_obj == NULL) + { + Py_DECREF (list); + list = NULL; + break; + } + + PyList_Append (list, (PyObject *) frame_obj); + } + } + if (except.reason < 0) + { + Py_DECREF (list); + return PyErr_Format (except.reason == RETURN_QUIT + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, + "%s", except.message); + } + + if (list) + { + tuple = PyList_AsTuple (list); + Py_DECREF (list); + } + else + tuple = NULL; + + return tuple; +} + +/* Implementation of gdb.newest_frame () -> gdb.Frame. + Returns the newest frame object. */ + +PyObject * +gdbpy_newest_frame (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + frame_object *frame_obj = NULL; /* Initialize to appease gcc warning. */ + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + frame = get_current_frame (); + frame_obj = frame_info_to_frame_object (frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return (PyObject *) frame_obj; +} + +/* Implementation of gdb.selected_frame () -> gdb.Frame. + Returns the selected frame object. */ + +PyObject * +gdbpy_selected_frame (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + frame_object *frame_obj = NULL; /* Initialize to appease gcc warning. */ + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + frame = get_selected_frame ("No frame is currently selected."); + frame_obj = frame_info_to_frame_object (frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return (PyObject *) frame_obj; +} + +/* Implementation of gdb.stop_reason_string (Integer) -> String. + Return a string explaining the unwind stop reason. */ + +PyObject * +gdbpy_frame_stop_reason_string (PyObject *self, PyObject *args) +{ + int reason; + const char *str; + + if (!PyArg_ParseTuple (args, "i", &reason)) + return NULL; + + if (reason < 0 || reason > UNWIND_NO_SAVED_PC) + { + PyErr_SetString (PyExc_ValueError, "Invalid frame stop reason."); + return NULL; + } + + str = frame_stop_reason_string (reason); + return PyUnicode_Decode (str, strlen (str), host_charset (), NULL); +} + +/* Sets up the Frame API in the gdb module. */ + +void +gdbpy_initialize_frames (void) +{ + frame_object_type.tp_new = PyType_GenericNew; + if (PyType_Ready (&frame_object_type) < 0) + return; + + /* Note: These would probably be best exposed as class attributes of Frame, + but I don't know how to do it except by messing with the type's dictionary. + That seems too messy. */ + PyModule_AddIntConstant (gdb_module, "NORMAL_FRAME", NORMAL_FRAME); + PyModule_AddIntConstant (gdb_module, "DUMMY_FRAME", DUMMY_FRAME); + PyModule_AddIntConstant (gdb_module, "SIGTRAMP_FRAME", SIGTRAMP_FRAME); + PyModule_AddIntConstant (gdb_module, "SENTINEL_FRAME", SENTINEL_FRAME); + PyModule_AddIntConstant (gdb_module, + "FRAME_UNWIND_NO_REASON", UNWIND_NO_REASON); + PyModule_AddIntConstant (gdb_module, + "FRAME_UNWIND_NULL_ID", UNWIND_NULL_ID); + PyModule_AddIntConstant (gdb_module, + "FRAME_UNWIND_FIRST_ERROR", UNWIND_FIRST_ERROR); + PyModule_AddIntConstant (gdb_module, + "FRAME_UNWIND_INNER_ID", UNWIND_INNER_ID); + PyModule_AddIntConstant (gdb_module, + "FRAME_UNWIND_SAME_ID", UNWIND_SAME_ID); + PyModule_AddIntConstant (gdb_module, + "FRAME_UNWIND_NO_SAVED_PC", UNWIND_NO_SAVED_PC); + + Py_INCREF (&frame_object_type); + PyModule_AddObject (gdb_module, "Frame", (PyObject *) &frame_object_type); +} + + + +static PyMethodDef frame_object_methods[] = { + { "equals", frapy_equal_p, METH_VARARGS, + "equals (frame) -> Boolean.\n\ +Compare this frame to the given frame." }, + { "is_valid", frapy_is_valid, METH_NOARGS, + "is_valid () -> Boolean.\n\ +Return true if this frame is valid, false if not." }, + { "name", frapy_name, METH_NOARGS, + "name () -> String.\n\ +Return the function name of the frame, or None if it can't be determined." }, + { "type", frapy_type, METH_NOARGS, + "type () -> Integer.\n\ +Return the type of the frame." }, + { "unwind_stop_reason", frapy_unwind_stop_reason, METH_NOARGS, + "unwind_stop_reason () -> Integer.\n\ +Return the reason why it's not possible to find frames older than this." }, + { "pc", frapy_pc, METH_NOARGS, + "pc () -> Long.\n\ +Return the frame's resume address." }, + { "block", frapy_block, METH_NOARGS, + "block () -> gdb.Block.\n\ +Return the frame's code block." }, + { "addr_in_block", frapy_addr_in_block, METH_NOARGS, + "addr_in_block () -> Long.\n\ +Return an address which falls within the frame's code block." }, + { "older", frapy_older, METH_NOARGS, + "older () -> gdb.Frame.\n\ +Return the frame immediately older (outer) to this frame." }, + { "newer", frapy_newer, METH_NOARGS, + "newer () -> gdb.Frame.\n\ +Return the frame immetidaely newer (inner) to this frame." }, + { "find_sal", frapy_find_sal, METH_NOARGS, + "find_sal () -> gdb.Symtab_and_line.\n\ +Return the frame's symtab and line." }, + { "read_var", frapy_read_var, METH_VARARGS, + "read_var (variable) -> gdb.Value.\n\ +Return the value of the variable in this frame." }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject frame_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /* ob_size */ + "gdb.Frame", /* tp_name */ + sizeof (frame_object), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + frapy_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "GDB frame object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + frame_object_methods /* tp_methods */ +}; diff --git a/gdb/python/python-function.c b/gdb/python/python-function.c new file mode 100644 index 0000000..4a85a33 --- /dev/null +++ b/gdb/python/python-function.c @@ -0,0 +1,180 @@ +/* Convenience functions implemented in Python. + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + +#include "defs.h" +#include "value.h" +#include "exceptions.h" +#include "python-internal.h" +#include "charset.h" +#include "gdbcmd.h" +#include "cli/cli-decode.h" +#include "completer.h" +#include "expression.h" + +static PyTypeObject fnpy_object_type; + + + +static PyObject * +convert_values_to_python (int argc, struct value **argv) +{ + int i; + PyObject *result = PyTuple_New (argc); + for (i = 0; i < argc; ++i) + { + PyObject *elt = value_to_value_object (argv[i]); + if (! elt) + { + Py_DECREF (result); + error (_("Could not convert value to Python object.")); + } + PyTuple_SetItem (result, i, elt); + } + return result; +} + +/* Call a Python function object's invoke method. */ + +static struct value * +fnpy_call (void *cookie, int argc, struct value **argv) +{ + int i; + struct value *value = NULL; + PyObject *result, *callable, *args; + struct cleanup *cleanup; + PyGILState_STATE state; + + state = PyGILState_Ensure (); + cleanup = make_cleanup_py_restore_gil (&state); + + args = convert_values_to_python (argc, argv); + + callable = PyObject_GetAttrString ((PyObject *) cookie, "invoke"); + if (! callable) + { + Py_DECREF (args); + error (_("No method named 'invoke' in object.")); + } + + result = PyObject_Call (callable, args, NULL); + Py_DECREF (callable); + Py_DECREF (args); + + if (!result) + { + gdbpy_print_stack (); + error (_("Error while executing Python code.")); + } + + value = convert_value_from_python (result); + if (value == NULL) + { + Py_DECREF (result); + gdbpy_print_stack (); + error (_("Error while executing Python code.")); + } + + Py_DECREF (result); + do_cleanups (cleanup); + + return value; +} + +/* Initializer for a Function object. It takes one argument, the name + of the function. */ + +static int +fnpy_init (PyObject *self, PyObject *args, PyObject *kwds) +{ + char *name, *docstring = NULL; + if (! PyArg_ParseTuple (args, "s", &name)) + return -1; + Py_INCREF (self); + + if (PyObject_HasAttrString (self, "__doc__")) + { + PyObject *ds_obj = PyObject_GetAttrString (self, "__doc__"); + if (ds_obj && gdbpy_is_string (ds_obj)) + /* Nothing ever frees this. */ + docstring = python_string_to_host_string (ds_obj); + } + if (! docstring) + docstring = _("This function is not documented."); + + add_internal_function (name, docstring, fnpy_call, self); + return 0; +} + +/* Initialize internal function support. */ + +void +gdbpy_initialize_functions (void) +{ + if (PyType_Ready (&fnpy_object_type) < 0) + return; + + Py_INCREF (&fnpy_object_type); + PyModule_AddObject (gdb_module, "Function", (PyObject *) &fnpy_object_type); +} + + + +static PyTypeObject fnpy_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Function", /*tp_name*/ + sizeof (PyObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "GDB function object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + fnpy_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew /* tp_new */ +}; diff --git a/gdb/python/python-hooks.c b/gdb/python/python-hooks.c new file mode 100644 index 0000000..a3140bc --- /dev/null +++ b/gdb/python/python-hooks.c @@ -0,0 +1,50 @@ +/* Notifications from gdb to Python + + Copyright (C) 2008 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "cli/cli-decode.h" +#include "charset.h" +#include "python.h" +#include "python-internal.h" +#include "observer.h" + +PyObject * +gdbpy_get_hook_function (const char *name) +{ + PyObject *hooks; + PyObject *result; + + if (! PyObject_HasAttrString (gdb_module, "hooks")) + return NULL; + hooks = PyObject_GetAttrString (gdb_module, "hooks"); + if (! hooks) + return NULL; + /* The cast is because the Python function doesn't declare const argument. + This is a problem in Python version 2.4, but not in 2.5. */ + if (! PyObject_HasAttrString (hooks, (char *) name)) + { + Py_DECREF (hooks); + return NULL; + } + /* The cast is because the Python function doesn't declare const argument. + This is a problem in Python version 2.4, but not in 2.5. */ + result = PyObject_GetAttrString (hooks, (char *) name); + Py_DECREF (hooks); + return result; +} diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 02dbfc4..4aae0aa 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -33,6 +33,7 @@ #if HAVE_LIBPYTHON2_4 #include "python2.4/Python.h" +#include "python2.4/frameobject.h" /* Py_ssize_t is not defined until 2.5. Logical type for Py_ssize_t is Py_intptr_t, but that fails in 64-bit compilation due to several apparent mistakes in python2.4 API, so we @@ -40,8 +41,10 @@ typedef int Py_ssize_t; #elif HAVE_LIBPYTHON2_5 #include "python2.5/Python.h" +#include "python2.5/frameobject.h" #elif HAVE_LIBPYTHON2_6 #include "python2.6/Python.h" +#include "python2.6/frameobject.h" #else #error "Unable to find usable Python.h" #endif @@ -58,23 +61,69 @@ typedef int Py_ssize_t; #define PyEval_ReleaseLock() 0 #endif +#include "command.h" + +struct block; +struct symbol; +struct symtab_and_line; struct value; extern PyObject *gdb_module; +extern PyTypeObject block_object_type; extern PyTypeObject value_object_type; +extern PyTypeObject symbol_object_type; PyObject *gdbpy_history (PyObject *self, PyObject *args); - +PyObject *gdbpy_breakpoints (PyObject *, PyObject *); +PyObject *gdbpy_frames (PyObject *, PyObject *); +PyObject *gdbpy_newest_frame (PyObject *, PyObject *); +PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *); +PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw); +PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args); +PyObject *gdbpy_block_for_pc (PyObject *self, PyObject *args); +PyObject *gdbpy_read_memory (PyObject *self, PyObject *args); +PyObject *gdbpy_write_memory (PyObject *self, PyObject *args); + +PyObject *symtab_and_line_to_sal_object (struct symtab_and_line sal); +PyObject *symtab_to_symtab_object (struct symtab *symtab); +PyObject *symbol_to_symbol_object (struct symbol *sym); +PyObject *block_to_block_object (struct block *block); PyObject *value_to_value_object (struct value *v); +PyObject *type_to_type_object (struct type *); +PyObject *objfile_to_objfile_object (struct objfile *); +PyObject *objfpy_get_printers (PyObject *, void *); + +struct block *block_object_to_block (PyObject *obj); +struct symbol *symbol_object_to_symbol (PyObject *obj); +struct value *value_object_to_value (PyObject *self); struct value *convert_value_from_python (PyObject *obj); +struct type *type_object_to_type (PyObject *obj); + +PyObject *gdbpy_get_hook_function (const char *); void gdbpy_initialize_values (void); +void gdbpy_initialize_breakpoints (void); +void gdbpy_initialize_frames (void); +void gdbpy_initialize_symtabs (void); void gdbpy_initialize_commands (void); +void gdbpy_initialize_symbols (void); +void gdbpy_initialize_types (void); +void gdbpy_initialize_blocks (void); +void gdbpy_initialize_functions (void); +void gdbpy_initialize_objfile (void); +void gdbpy_initialize_parameters (void); +void gdbpy_initialize_membuf (void); struct cleanup *make_cleanup_py_decref (PyObject *py); struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state); +char *gdbpy_parse_command_name (char *text, + struct cmd_list_element ***base_list, + struct cmd_list_element **start_list); + +PyObject *gdbpy_parameter_value (enum var_types, void *); + /* Use this after a TRY_EXCEPT to throw the appropriate Python exception. */ #define GDB_PY_HANDLE_EXCEPTION(Exception) \ @@ -85,6 +134,19 @@ struct cleanup *make_cleanup_py_restore_gil (PyGILState_STATE *state); "%s", Exception.message); \ } while (0) +/* Use this after a TRY_EXCEPT to throw the appropriate Python + exception. This macro is for use inside setter functions. */ +#define GDB_PY_SET_HANDLE_EXCEPTION(Exception) \ + do { \ + if (Exception.reason < 0) \ + { \ + PyErr_Format (Exception.reason == RETURN_QUIT \ + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, \ + "%s", Exception.message); \ + return -1; \ + } \ + } while (0) + void gdbpy_print_stack (void); @@ -95,6 +157,21 @@ char *python_string_to_host_string (PyObject *obj); PyObject *target_string_to_unicode (const gdb_byte *str, int length); int gdbpy_is_string (PyObject *obj); +int gdbpy_is_value_object (PyObject *obj); + +/* Note that these are declared here, and not in python.h with the + other pretty-printer functions, because they refer to PyObject. */ +char *apply_varobj_pretty_printer (PyObject *print_obj, + struct value **replacement); +PyObject *gdbpy_get_varobj_pretty_printer (struct value *value); +PyObject *gdbpy_instantiate_printer (PyObject *cons, PyObject *value); +char *gdbpy_get_display_hint (PyObject *printer); + +extern PyObject *gdbpy_children_cst; +extern PyObject *gdbpy_to_string_cst; +extern PyObject *gdbpy_display_hint_cst; extern PyObject *gdbpy_doc_cst; +int get_addr_from_python (PyObject *obj, CORE_ADDR *addr); + #endif /* GDB_PYTHON_INTERNAL_H */ diff --git a/gdb/python/python-membuf.c b/gdb/python/python-membuf.c new file mode 100644 index 0000000..a4c7d74 --- /dev/null +++ b/gdb/python/python-membuf.c @@ -0,0 +1,243 @@ +/* Python interface to the inferior memory. + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "exceptions.h" +#include "gdbcore.h" +#include "python-internal.h" + +typedef struct { + PyObject_HEAD + void *buffer; + + /* These are kept just for mbpy_str. */ + CORE_ADDR addr; + CORE_ADDR length; +} membuf_object; + +static PyTypeObject membuf_object_type; + +/* Implementation of gdb.read_memory (address, length). + Returns a Python buffer object with LENGTH bytes of the inferior's memory + at ADDRESS. Both arguments are integers. */ + +PyObject * +gdbpy_read_memory (PyObject *self, PyObject *args) +{ + CORE_ADDR addr, length; + void *buffer; + membuf_object *membuf_obj; + struct cleanup *cleanups; + volatile struct gdb_exception except; + + /* Assume CORE_ADDR corresponds to unsigned long. */ + if (! PyArg_ParseTuple (args, "kk", &addr, &length)) + return NULL; + + buffer = xmalloc (length); + cleanups = make_cleanup (xfree, buffer); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + read_memory (addr, buffer, length); + } + GDB_PY_HANDLE_EXCEPTION (except); + + discard_cleanups (cleanups); + + membuf_obj = PyObject_New (membuf_object, &membuf_object_type); + if (membuf_obj == NULL) + { + xfree (buffer); + PyErr_SetString (PyExc_MemoryError, + "Could not allocate memory buffer object."); + return NULL; + } + + membuf_obj->buffer = buffer; + + membuf_obj->addr = addr; + membuf_obj->length = length; + + return PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj, 0, Py_END_OF_BUFFER); +} + +/* Implementation of gdb.write_memory (address, buffer [, length]). + Writes the contents of BUFFER (a Python object supporting the read buffer + protocol) at ADDRESS in the inferior's memory. Write LENGTH bytes from + BUFFER, or its entire contents if the argument is not provided. The + function returns nothing. */ + +PyObject * +gdbpy_write_memory (PyObject *self, PyObject *args) +{ + int buf_len; + const char *buffer; + long length = -1; + CORE_ADDR addr; + volatile struct gdb_exception except; + + /* Assume CORE_ADDR corresponds to unsigned long. */ + if (! PyArg_ParseTuple (args, "ks#|l", &addr, &buffer, &buf_len, &length)) + return NULL; + + if (length == -1) + length = buf_len; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + write_memory (addr, buffer, length); + } + GDB_PY_HANDLE_EXCEPTION (except); + + Py_RETURN_NONE; +} + +/* Destructor of Membuf objects. */ + +static void +mbpy_dealloc (PyObject *self) +{ + xfree (((membuf_object *) self)->buffer); + self->ob_type->tp_free (self); +} + +/* Return a description of the Membuf object. */ + +static PyObject * +mbpy_str (PyObject *self) +{ + membuf_object *membuf_obj = (membuf_object *) self; + + return PyString_FromFormat ("memory buffer for address %s, %s bytes long", + paddress (membuf_obj->addr), + pulongest (membuf_obj->length)); +} + +static Py_ssize_t +get_read_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr) +{ + membuf_object *membuf_obj = (membuf_object *) self; + + if (segment) + { + PyErr_SetString (PyExc_SystemError, + "The memory buffer supports only one segment."); + return -1; + } + + *ptrptr = membuf_obj->buffer; + + return membuf_obj->length; +} + +static Py_ssize_t +get_write_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr) +{ + return get_read_buffer (self, segment, ptrptr); +} + +static Py_ssize_t +get_seg_count (PyObject *self, Py_ssize_t *lenp) +{ + if (lenp) + *lenp = ((membuf_object *) self)->length; + + return 1; +} + +static Py_ssize_t +get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr) +{ + void *ptr = NULL; + Py_ssize_t ret; + + ret = get_read_buffer (self, segment, &ptr); + *ptrptr = (char *) ptr; + + return ret; +} + +/* Python doesn't provide a decent way to get compatibility here. */ +#if HAVE_LIBPYTHON2_4 +#define CHARBUFFERPROC_NAME getcharbufferproc +#else +#define CHARBUFFERPROC_NAME charbufferproc +#endif + +static PyBufferProcs buffer_procs = { + get_read_buffer, + get_write_buffer, + get_seg_count, + /* The cast here works around a difference between Python 2.4 and + Python 2.5. */ + (CHARBUFFERPROC_NAME) get_char_buffer +}; + +static PyTypeObject membuf_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Membuf", /*tp_name*/ + sizeof (membuf_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + mbpy_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + mbpy_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + &buffer_procs, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB memory buffer object", /*tp_doc*/ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew /* tp_new */ +}; + +void +gdbpy_initialize_membuf (void) +{ + if (PyType_Ready (&membuf_object_type) < 0) + return; + + Py_INCREF (&membuf_object_type); + PyModule_AddObject (gdb_module, "Membuf", (PyObject *) &membuf_object_type); +} diff --git a/gdb/python/python-objfile.c b/gdb/python/python-objfile.c new file mode 100644 index 0000000..e97d3a2 --- /dev/null +++ b/gdb/python/python-objfile.c @@ -0,0 +1,221 @@ +/* Python interface to objfiles. + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "python-internal.h" +#include "charset.h" +#include "objfiles.h" + +typedef struct +{ + PyObject_HEAD + + /* The corresponding objfile. */ + struct objfile *objfile; + + /* The pretty-printer list of functions. */ + PyObject *printers; +} objfile_object; + +static PyTypeObject objfile_object_type; + +static const struct objfile_data *objfpy_objfile_data_key; + + + +/* An Objfile method which returns the objfile's file name, or None. */ +static PyObject * +objfpy_get_filename (PyObject *self, void *closure) +{ + objfile_object *obj = (objfile_object *) self; + if (obj->objfile && obj->objfile->name) + return PyString_Decode (obj->objfile->name, strlen (obj->objfile->name), + host_charset (), NULL); + Py_RETURN_NONE; +} + +static void +objfpy_dealloc (PyObject *o) +{ + objfile_object *self = (objfile_object *) o; + Py_XDECREF (self->printers); + self->ob_type->tp_free ((PyObject *) self); +} + +static PyObject * +objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords) +{ + objfile_object *self = (objfile_object *) type->tp_alloc (type, 0); + if (self) + { + self->objfile = NULL; + + self->printers = PyList_New (0); + if (!self->printers) + { + Py_DECREF (self); + return NULL; + } + } + return (PyObject *) self; +} + +PyObject * +objfpy_get_printers (PyObject *o, void *ignore) +{ + objfile_object *self = (objfile_object *) o; + Py_INCREF (self->printers); + return self->printers; +} + +static int +objfpy_set_printers (PyObject *o, PyObject *value, void *ignore) +{ + objfile_object *self = (objfile_object *) o; + if (! value) + { + PyErr_SetString (PyExc_TypeError, + "cannot delete the pretty_printers attribute"); + return -1; + } + + if (! PyList_Check (value)) + { + PyErr_SetString (PyExc_TypeError, + "the pretty_printers attribute must be a list"); + return -1; + } + + Py_XDECREF (self->printers); + Py_INCREF (value); + self->printers = value; + + return 0; +} + + + +/* Clear the OBJFILE pointer in an Objfile object and remove the + reference. */ +static void +clean_up_objfile (struct objfile *objfile, void *datum) +{ + objfile_object *object = datum; + object->objfile = NULL; + Py_DECREF ((PyObject *) object); +} + +/* Return the Python object of type Objfile representing OBJFILE. If + the object has already been created, return it. Otherwise, create + it. Return NULL and set the Python error on failure. */ +PyObject * +objfile_to_objfile_object (struct objfile *objfile) +{ + objfile_object *object; + + object = objfile_data (objfile, objfpy_objfile_data_key); + if (!object) + { + object = PyObject_New (objfile_object, &objfile_object_type); + if (object) + { + PyObject *dict; + + object->objfile = objfile; + + object->printers = PyList_New (0); + if (!object->printers) + { + Py_DECREF (object); + return NULL; + } + + set_objfile_data (objfile, objfpy_objfile_data_key, object); + } + } + + return (PyObject *) object; +} + +void +gdbpy_initialize_objfile (void) +{ + objfpy_objfile_data_key + = register_objfile_data_with_cleanup (clean_up_objfile); + + if (PyType_Ready (&objfile_object_type) < 0) + return; + + Py_INCREF (&objfile_object_type); + PyModule_AddObject (gdb_module, "Objfile", (PyObject *) &objfile_object_type); +} + + + +static PyGetSetDef objfile_getset[] = +{ + { "filename", objfpy_get_filename, NULL, + "The objfile's filename, or None.", NULL }, + { "pretty_printers", objfpy_get_printers, objfpy_set_printers, + "Pretty printers.", NULL }, + { NULL } +}; + +static PyTypeObject objfile_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Objfile", /*tp_name*/ + sizeof (objfile_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + objfpy_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB objfile object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + objfile_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + objfpy_new, /* tp_new */ +}; diff --git a/gdb/python/python-param.c b/gdb/python/python-param.c new file mode 100644 index 0000000..1f591a8 --- /dev/null +++ b/gdb/python/python-param.c @@ -0,0 +1,606 @@ +/* gdb parameters implemented in Python + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + +#include "defs.h" +#include "value.h" +#include "exceptions.h" +#include "python-internal.h" +#include "charset.h" +#include "gdbcmd.h" +#include "cli/cli-decode.h" +#include "completer.h" + +/* Parameter constants and their values. */ +struct parm_constant +{ + char *name; + int value; +}; + +struct parm_constant parm_constants[] = +{ + { "PARAM_BOOLEAN", var_boolean }, + { "PARAM_AUTO_BOOLEAN", var_auto_boolean }, + { "PARAM_UINTEGER", var_uinteger }, + { "PARAM_INTEGER", var_integer }, + { "PARAM_STRING", var_string }, + { "PARAM_STRING_NOESCAPE", var_string_noescape }, + { "PARAM_OPTIONAL_FILENAME", var_optional_filename }, + { "PARAM_FILENAME", var_filename }, + { "PARAM_ZINTEGER", var_zinteger }, + { "PARAM_ENUM", var_enum }, + { NULL, 0 } +}; + +/* A union that can hold anything described by enum var_types. */ +union parmpy_variable +{ + /* Hold an integer value, for boolean and integer types. */ + int intval; + + /* Hold an auto_boolean. */ + enum auto_boolean autoboolval; + + /* Hold an unsigned integer value, for uinteger. */ + unsigned int uintval; + + /* Hold a string, for the various string types. */ + char *stringval; + + /* Hold a string, for enums. */ + const char *cstringval; +}; + +/* A gdb parameter. */ +struct parmpy_object +{ + PyObject_HEAD + + /* The type of the parameter. */ + enum var_types type; + + /* The value of the parameter. */ + union parmpy_variable value; + + /* For an enum command, the possible values. The vector is + allocated with xmalloc, as is each element. It is + NULL-terminated. */ + const char **enumeration; +}; + +typedef struct parmpy_object parmpy_object; + +static PyTypeObject parmpy_object_type; + +/* Some handy string constants. */ +static PyObject *set_doc_cst; +static PyObject *show_doc_cst; + + + +/* Get an attribute. */ +static PyObject * +get_attr (PyObject *obj, PyObject *attr_name) +{ + if (PyString_Check (attr_name) + && ! strcmp (PyString_AsString (attr_name), "value")) + { + parmpy_object *self = (parmpy_object *) obj; + return gdbpy_parameter_value (self->type, &self->value); + } + + return PyObject_GenericGetAttr (obj, attr_name); +} + +/* Set a parameter value from a Python value. Return 0 on success, -1 + on failure. */ +static int +set_parameter_value (parmpy_object *self, PyObject *value) +{ + int cmp; + + switch (self->type) + { + case var_string: + case var_string_noescape: + case var_optional_filename: + case var_filename: + if (! gdbpy_is_string (value) + && (self->type == var_filename + || value != Py_None)) + { + PyErr_SetString (PyExc_RuntimeError, "string required"); + return -1; + } + if (self->value.stringval) + xfree (self->value.stringval); + if (value == Py_None) + { + if (self->type == var_optional_filename) + self->value.stringval = xstrdup (""); + else + self->value.stringval = NULL; + } + else + self->value.stringval = python_string_to_host_string (value); + break; + + case var_enum: + { + int i; + char *str; + + if (! gdbpy_is_string (value)) + { + PyErr_SetString (PyExc_RuntimeError, "string required"); + return -1; + } + + str = python_string_to_host_string (value); + for (i = 0; self->enumeration[i]; ++i) + if (! strcmp (self->enumeration[i], str)) + break; + xfree (str); + if (! self->enumeration[i]) + { + PyErr_SetString (PyExc_RuntimeError, + "value must be member of enumeration"); + return -1; + } + self->value.cstringval = self->enumeration[i]; + break; + } + + case var_boolean: + if (! PyBool_Check (value)) + { + PyErr_SetString (PyExc_RuntimeError, "boolean required"); + return -1; + } + cmp = PyObject_IsTrue (value); + if (cmp < 0) + return -1; + self->value.intval = cmp; + break; + + case var_auto_boolean: + if (! PyBool_Check (value) && value != Py_None) + { + PyErr_SetString (PyExc_RuntimeError, + "boolean or None required"); + return -1; + } + + if (value == Py_None) + self->value.autoboolval = AUTO_BOOLEAN_AUTO; + else + { + cmp = PyObject_IsTrue (value); + if (cmp < 0 ) + return -1; + if (cmp == 1) + self->value.autoboolval = AUTO_BOOLEAN_TRUE; + else + self->value.autoboolval = AUTO_BOOLEAN_FALSE; + + break; + } + + case var_integer: + case var_zinteger: + case var_uinteger: + { + long l; + int ok; + + if (! PyInt_Check (value)) + { + PyErr_SetString (PyExc_RuntimeError, "value must be integer"); + return -1; + } + + l = PyInt_AsLong (value); + if (self->type == var_uinteger) + { + ok = (l >= 0 && l <= UINT_MAX); + if (l == 0) + l = UINT_MAX; + } + else if (self->type == var_integer) + { + ok = (l >= INT_MIN && l <= INT_MAX); + if (l == 0) + l = INT_MAX; + } + else + ok = (l >= INT_MIN && l <= INT_MAX); + + if (! ok) + { + PyErr_SetString (PyExc_RuntimeError, "range exceeded"); + return -1; + } + + self->value.intval = (int) l; + break; + } + + default: + PyErr_SetString (PyExc_RuntimeError, "programmer error: unhandled type"); + return -1; + } + + return 0; +} + +/* Set an attribute. */ +static int +set_attr (PyObject *obj, PyObject *attr_name, PyObject *val) +{ + if (PyString_Check (attr_name) + && ! strcmp (PyString_AsString (attr_name), "value")) + { + if (!val) + { + PyErr_SetString (PyExc_RuntimeError, + "cannot delete a parameter's value"); + return -1; + } + return set_parameter_value ((parmpy_object *) obj, val); + } + + return PyObject_GenericSetAttr (obj, attr_name, val); +} + + + +/* A helper function that dispatches to the appropriate add_setshow + function. */ +static void +add_setshow_generic (int parmclass, enum command_class cmdclass, + char *cmd_name, parmpy_object *self, + char *set_doc, char *show_doc, char *help_doc, + struct cmd_list_element **set_list, + struct cmd_list_element **show_list) +{ + switch (parmclass) + { + case var_boolean: + add_setshow_boolean_cmd (cmd_name, cmdclass, &self->value.intval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_auto_boolean: + add_setshow_auto_boolean_cmd (cmd_name, cmdclass, + &self->value.autoboolval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_uinteger: + add_setshow_uinteger_cmd (cmd_name, cmdclass, &self->value.uintval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_integer: + add_setshow_integer_cmd (cmd_name, cmdclass, &self->value.intval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_string: + add_setshow_string_cmd (cmd_name, cmdclass, &self->value.stringval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_string_noescape: + add_setshow_string_noescape_cmd (cmd_name, cmdclass, + &self->value.stringval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_optional_filename: + add_setshow_optional_filename_cmd (cmd_name, cmdclass, + &self->value.stringval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_filename: + add_setshow_filename_cmd (cmd_name, cmdclass, &self->value.stringval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_zinteger: + add_setshow_zinteger_cmd (cmd_name, cmdclass, &self->value.intval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_enum: + add_setshow_enum_cmd (cmd_name, cmdclass, self->enumeration, + &self->value.cstringval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + /* Initialize the value, just in case. */ + self->value.cstringval = self->enumeration[0]; + break; + } +} + +/* A helper which computes enum values. Returns 1 on success, 0 on + error. */ +static int +compute_enum_values (parmpy_object *self, PyObject *enum_values) +{ + Py_ssize_t size, i; + + if (! enum_values) + { + PyErr_SetString (PyExc_RuntimeError, + "enumeration required for PARAM_ENUM"); + return 0; + } + + if (! PySequence_Check (enum_values)) + { + PyErr_SetString (PyExc_RuntimeError, "enumeration is not a sequence"); + return 0; + } + + size = PySequence_Size (enum_values); + if (size < 0) + return 0; + if (size == 0) + { + PyErr_SetString (PyExc_RuntimeError, "empty enumeration"); + return 0; + } + + self->enumeration = xmalloc ((size + 1) * sizeof (char *)); + memset (self->enumeration, 0, (size + 1) * sizeof (char *)); + + for (i = 0; i < size; ++i) + { + PyObject *item = PySequence_GetItem (enum_values, i); + if (! item) + return 0; + if (! gdbpy_is_string (item)) + { + PyErr_SetString (PyExc_RuntimeError, "enumeration item not a string"); + return 0; + } + self->enumeration[i] = python_string_to_host_string (item); + } + + return 1; +} + +/* A helper function which returns a documentation string for an + object. */ +static char * +get_doc_string (PyObject *object, PyObject *attr) +{ + char *result = NULL; + if (PyObject_HasAttr (object, attr)) + { + PyObject *ds_obj = PyObject_GetAttr (object, attr); + if (ds_obj && gdbpy_is_string (ds_obj)) + result = python_string_to_host_string (ds_obj); + } + if (! result) + result = xstrdup ("This command is not documented."); + return result; +} + +/* Object initializer; sets up gdb-side structures for command. + + Use: __init__(NAME, CMDCLASS, PARMCLASS, [ENUM]) + + NAME is the name of the parameter. It may consist of multiple + words, in which case the final word is the name of the new command, + and earlier words must be prefix commands. + + CMDCLASS is the kind of command. It should be one of the COMMAND_* + constants defined in the gdb module. + + PARMCLASS is the type of the parameter. It should be one of the + PARAM_* constants defined in the gdb module. + + If PARMCLASS is PARAM_ENUM, then the final argument should be a + collection of strings. These strings are the valid values for this + parameter. + + The documentation for the parameter is taken from the doc string + for the python class. + +*/ +static int +parmpy_init (PyObject *self, PyObject *args, PyObject *kwds) +{ + parmpy_object *obj = (parmpy_object *) self; + char *name; + char *set_doc, *show_doc, *doc; + char *cmd_name; + int parmclass, cmdtype; + PyObject *enum_values = NULL; + struct cmd_list_element *cmd_list; + struct cmd_list_element **set_list, **show_list; + volatile struct gdb_exception except; + + if (! PyArg_ParseTuple (args, "sii|O", &name, &cmdtype, &parmclass, + &enum_values)) + return -1; + + if (cmdtype != no_class && cmdtype != class_run + && cmdtype != class_vars && cmdtype != class_stack + && cmdtype != class_files && cmdtype != class_support + && cmdtype != class_info && cmdtype != class_breakpoint + && cmdtype != class_trace && cmdtype != class_obscure + && cmdtype != class_maintenance) + { + PyErr_Format (PyExc_RuntimeError, "invalid command class argument"); + return -1; + } + + if (parmclass != var_boolean && parmclass != var_auto_boolean + && parmclass != var_uinteger && parmclass != var_integer + && parmclass != var_string && parmclass != var_string_noescape + && parmclass != var_optional_filename && parmclass != var_filename + && parmclass != var_zinteger && parmclass != var_enum) + { + PyErr_SetString (PyExc_RuntimeError, "invalid parameter class argument"); + return -1; + } + + if (enum_values && parmclass != var_enum) + { + PyErr_SetString (PyExc_RuntimeError, + "only PARAM_ENUM accepts a fourth argument"); + return -1; + } + if (parmclass == var_enum) + { + if (! compute_enum_values (obj, enum_values)) + return -1; + } + + obj->type = (enum var_types) parmclass; + memset (&obj->value, 0, sizeof (obj->value)); + obj->enumeration = NULL; + + cmd_name = gdbpy_parse_command_name (name, &set_list, &setlist); + if (! cmd_name) + return -1; + xfree (cmd_name); + cmd_name = gdbpy_parse_command_name (name, &show_list, &showlist); + if (! cmd_name) + return -1; + + /* FIXME: there is no way to register a destructor function for + set/show commands. So, these are leaked. */ + set_doc = get_doc_string (self, set_doc_cst); + show_doc = get_doc_string (self, show_doc_cst); + doc = get_doc_string (self, gdbpy_doc_cst); + + Py_INCREF (self); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + add_setshow_generic (parmclass, (enum command_class) cmdtype, + cmd_name, obj, + set_doc, show_doc, + doc, set_list, show_list); + } + if (except.reason < 0) + { + xfree (cmd_name); + xfree (set_doc); + xfree (show_doc); + xfree (doc); + Py_DECREF (self); + PyErr_Format (except.reason == RETURN_QUIT + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, + "%s", except.message); + return -1; + } + return 0; +} + + + +/* Initialize the 'parameters' module. */ +void +gdbpy_initialize_parameters (void) +{ + int i; + + if (PyType_Ready (&parmpy_object_type) < 0) + return; + + set_doc_cst = PyString_FromString ("set_doc"); + if (! set_doc_cst) + return; + show_doc_cst = PyString_FromString ("show_doc"); + if (! show_doc_cst) + return; + + for (i = 0; parm_constants[i].name; ++i) + { + if (PyModule_AddIntConstant (gdb_module, + parm_constants[i].name, + parm_constants[i].value) < 0) + return; + } + + Py_INCREF (&parmpy_object_type); + PyModule_AddObject (gdb_module, "Parameter", + (PyObject *) &parmpy_object_type); +} + + + +static PyTypeObject parmpy_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Parameter", /*tp_name*/ + sizeof (parmpy_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + get_attr, /*tp_getattro*/ + set_attr, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "GDB parameter object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + parmpy_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew /* tp_new */ +}; diff --git a/gdb/python/python-symbol.c b/gdb/python/python-symbol.c new file mode 100644 index 0000000..c7fda5c --- /dev/null +++ b/gdb/python/python-symbol.c @@ -0,0 +1,337 @@ +/* Python interface to symbols. + + Copyright (C) 2008 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "block.h" +#include "exceptions.h" +#include "frame.h" +#include "symtab.h" +#include "python-internal.h" + +typedef struct { + PyObject_HEAD + struct symbol *symbol; +} symbol_object; + + +static PyObject * +sympy_str (PyObject *self) +{ + int ret; + char *s; + PyObject *result; + + ret = asprintf (&s, "symbol for %s", + SYMBOL_PRINT_NAME (((symbol_object *) self)->symbol)); + if (ret < 0) + Py_RETURN_NONE; + + result = PyString_FromString (s); + xfree (s); + + return result; +} + +static PyObject * +sympy_get_value (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + switch (SYMBOL_CLASS (self_sym->symbol)) + { + case LOC_BLOCK: + return block_to_block_object (SYMBOL_BLOCK_VALUE (self_sym->symbol)); + } + + PyErr_SetString (PyExc_NotImplementedError, + "Symbol type not yet supported in Python scripts."); + return NULL; +} + +static PyObject * +sympy_get_symtab (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return symtab_to_symtab_object (SYMBOL_SYMTAB (self_sym->symbol)); +} + +static PyObject * +sympy_get_name (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyString_FromString (SYMBOL_NATURAL_NAME (self_sym->symbol)); +} + +static PyObject * +sympy_get_linkage_name (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyString_FromString (SYMBOL_LINKAGE_NAME (self_sym->symbol)); +} + +static PyObject * +sympy_get_print_name (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyString_FromString (SYMBOL_PRINT_NAME (self_sym->symbol)); +} + +static PyObject * +sympy_get_addr_class (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyInt_FromLong (SYMBOL_CLASS (self_sym->symbol)); +} + +static PyObject * +sympy_is_argument (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyBool_FromLong (SYMBOL_IS_ARGUMENT (self_sym->symbol)); +} + +static PyObject * +sympy_is_constant (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + enum address_class class = SYMBOL_CLASS (self_sym->symbol); + + return PyBool_FromLong (class == LOC_CONST || class == LOC_CONST_BYTES); +} + +static PyObject * +sympy_is_function (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + enum address_class class = SYMBOL_CLASS (self_sym->symbol); + + return PyBool_FromLong (class == LOC_BLOCK); +} + +static PyObject * +sympy_is_variable (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + enum address_class class = SYMBOL_CLASS (self_sym->symbol); + + return PyBool_FromLong (!SYMBOL_IS_ARGUMENT (self_sym->symbol) + && (class == LOC_LOCAL || class == LOC_REGISTER || class == LOC_STATIC + || class == LOC_COMPUTED || class == LOC_OPTIMIZED_OUT)); +} + +PyObject * +symbol_to_symbol_object (struct symbol *sym) +{ + symbol_object *sym_obj; + + sym_obj = PyObject_New (symbol_object, &symbol_object_type); + if (sym_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate symbol object."); + return NULL; + } + + sym_obj->symbol = sym; + + return (PyObject *) sym_obj; +} + +struct symbol * +symbol_object_to_symbol (PyObject *obj) +{ + if (! PyObject_TypeCheck (obj, &symbol_object_type)) + return NULL; + return ((symbol_object *) obj)->symbol; +} + +/* Implementation of + gdb.lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this) + A tuple with 2 elements is always returned. The first is the symbol + object or None, the second is a boolean with the value of + is_a_field_of_this (see comment in lookup_symbol_in_language). */ + +PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw) +{ + int domain = VAR_DOMAIN, is_a_field_of_this = 0; + const char *name; + static char *keywords[] = { "name", "block", "domain", NULL }; + struct symbol *symbol; + PyObject *block_obj = NULL, *ret_tuple, *sym_obj, *bool_obj; + struct block *block = NULL; + + if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O!i", keywords, &name, + &block_object_type, &block_obj, &domain)) + return NULL; + + if (block_obj) + block = block_object_to_block (block_obj); + else + { + struct frame_info *selected_frame; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + selected_frame = get_selected_frame (_("No frame selected.")); + block = block_for_pc (get_frame_address_in_block (selected_frame)); + } + GDB_PY_HANDLE_EXCEPTION (except); + } + + symbol = lookup_symbol (name, block, domain, &is_a_field_of_this); + + ret_tuple = PyTuple_New (2); + if (!ret_tuple) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate tuple object."); + return NULL; + } + + if (symbol) + { + sym_obj = symbol_to_symbol_object (symbol); + if (!sym_obj) + { + Py_DECREF (ret_tuple); + return NULL; + } + } + else + { + sym_obj = Py_None; + Py_INCREF (Py_None); + } + PyTuple_SET_ITEM (ret_tuple, 0, sym_obj); + + bool_obj = is_a_field_of_this? Py_True : Py_False; + Py_INCREF (bool_obj); + PyTuple_SET_ITEM (ret_tuple, 1, bool_obj); + + return ret_tuple; +} + +void +gdbpy_initialize_symbols (void) +{ + symbol_object_type.tp_new = PyType_GenericNew; + if (PyType_Ready (&symbol_object_type) < 0) + return; + + /* FIXME: These would probably be best exposed as class attributes of Symbol, + but I don't know how to do it except by messing with the type's dictionary. + That seems too messy. */ + /* FIXME 2: Some of these were removed from GDB since I first wrote this code, + so it's probably a good idea not to expose them to Python. */ + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_UNDEF", LOC_UNDEF); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_CONST", LOC_CONST); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_STATIC", LOC_STATIC); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REGISTER", LOC_REGISTER); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_ARG", LOC_ARG); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REF_ARG", LOC_REF_ARG); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_LOCAL", LOC_LOCAL); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_TYPEDEF", LOC_TYPEDEF); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_LABEL", LOC_LABEL); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_BLOCK", LOC_BLOCK); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_CONST_BYTES", + LOC_CONST_BYTES); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_UNRESOLVED", LOC_UNRESOLVED); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_OPTIMIZED_OUT", + LOC_OPTIMIZED_OUT); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_COMPUTED", LOC_COMPUTED); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REGPARM_ADDR", + LOC_REGPARM_ADDR); + PyModule_AddIntConstant (gdb_module, "SYMBOL_UNDEF_DOMAIN", UNDEF_DOMAIN); + PyModule_AddIntConstant (gdb_module, "SYMBOL_VAR_DOMAIN", VAR_DOMAIN); + PyModule_AddIntConstant (gdb_module, "SYMBOL_STRUCT_DOMAIN", STRUCT_DOMAIN); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LABEL_DOMAIN", LABEL_DOMAIN); + PyModule_AddIntConstant (gdb_module, "SYMBOL_VARIABLES_DOMAIN", + VARIABLES_DOMAIN); + PyModule_AddIntConstant (gdb_module, "SYMBOL_FUNCTIONS_DOMAIN", + FUNCTIONS_DOMAIN); + PyModule_AddIntConstant (gdb_module, "SYMBOL_TYPES_DOMAIN", TYPES_DOMAIN); + + Py_INCREF (&symbol_object_type); + PyModule_AddObject (gdb_module, "Symbol", (PyObject *) &symbol_object_type); +} + + + +static PyGetSetDef symbol_object_getset[] = { + { "value", sympy_get_value, NULL, "Value of the symbol.", NULL }, + { "symtab", sympy_get_symtab, NULL, + "Symbol table in which the symbol appears.", NULL }, + { "name", sympy_get_name, NULL, + "Name of the symbol, as it appears in the source code.", NULL }, + { "linkage_name", sympy_get_linkage_name, NULL, + "Name of the symbol, as used by the linker (i.e., may be mangled).", NULL }, + { "print_name", sympy_get_print_name, NULL, + "Name of the symbol in a form suitable for output.\n\ +This is either name or linkage_name, depending on whether the user asked GDB\n\ +to display demangled or mangled names.", NULL }, + { "addr_class", sympy_get_addr_class, NULL, "Address class of the symbol." }, + { "is_argument", sympy_is_argument, NULL, + "True if the symbol is an argument of a function." }, + { "is_constant", sympy_is_constant, NULL, + "True if the symbol is a constant." }, + { "is_function", sympy_is_function, NULL, + "True if the symbol is a function or method." }, + { "is_variable", sympy_is_variable, NULL, + "True if the symbol is a variable." }, + { NULL } /* Sentinel */ +}; + +PyTypeObject symbol_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Symbol", /*tp_name*/ + sizeof (symbol_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + sympy_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB symbol object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + symbol_object_getset /* tp_getset */ +}; diff --git a/gdb/python/python-symtab.c b/gdb/python/python-symtab.c new file mode 100644 index 0000000..a48c38c --- /dev/null +++ b/gdb/python/python-symtab.c @@ -0,0 +1,311 @@ +/* Python interface to symbol tables. + + Copyright (C) 2008 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "charset.h" +#include "symtab.h" +#include "source.h" +#include "python-internal.h" + +typedef struct { + PyObject_HEAD + struct symtab *symtab; +} symtab_object; + +static PyTypeObject symtab_object_type; + +typedef struct { + PyObject_HEAD + symtab_object *symtab; + struct symtab_and_line *sal; +} sal_object; + +static PyTypeObject sal_object_type; + + +static PyObject * +stpy_str (PyObject *self) +{ + int ret; + char *s; + PyObject *result; + + ret = asprintf (&s, "symbol table for %s", + ((symtab_object *) self)->symtab->filename); + if (ret < 0) + Py_RETURN_NONE; + + result = PyString_FromString (s); + xfree (s); + + return result; +} + +static PyObject * +stpy_get_filename (PyObject *self, void *closure) +{ + symtab_object *self_symtab = (symtab_object *) self; + PyObject *str_obj; + + /* FIXME: Can symtab->filename really be NULL? */ + if (self_symtab->symtab->filename) + str_obj = PyString_Decode (self_symtab->symtab->filename, + strlen (self_symtab->symtab->filename), + host_charset (), NULL); + else + { + str_obj = Py_None; + Py_INCREF (Py_None); + } + + return str_obj; +} + +static PyObject * +stpy_fullname (PyObject *self, PyObject *args) +{ + char *fullname; + + fullname = symtab_to_fullname (((symtab_object *) self)->symtab); + if (fullname) + return PyString_Decode (fullname, strlen (fullname), host_charset (), NULL); + + Py_RETURN_NONE; +} + +static PyObject * +salpy_str (PyObject *self) +{ + int ret; + char *s, *filename; + sal_object *sal_obj; + PyObject *result; + + sal_obj = (sal_object *) self; + filename = (sal_obj->symtab == (symtab_object *) Py_None)? "" : + sal_obj->symtab->symtab->filename; + ret = asprintf (&s, "symbol and line for %s, line %d", filename, + sal_obj->sal->line); + if (ret < 0) + Py_RETURN_NONE; + + result = PyString_FromString (s); + xfree (s); + + return result; +} + +static PyObject * +salpy_get_pc (PyObject *self, void *closure) +{ + return PyLong_FromUnsignedLongLong (((sal_object *) self)->sal->pc); +} + +static PyObject * +salpy_get_line (PyObject *self, void *closure) +{ + return PyLong_FromUnsignedLongLong (((sal_object *) self)->sal->line); +} + +static PyObject * +salpy_get_symtab (PyObject *self, void *closure) +{ + sal_object *self_sal = (sal_object *) self; + + Py_INCREF (self_sal->symtab); + + return (PyObject *) self_sal->symtab; +} + +static void +salpy_dealloc (PyObject *self) +{ + sal_object *self_sal = (sal_object *) self; + + Py_DECREF (self_sal->symtab); + xfree (self_sal->sal); + self_sal->ob_type->tp_free (self); +} + +PyObject * +symtab_and_line_to_sal_object (struct symtab_and_line sal) +{ + sal_object *sal_obj; + symtab_object *symtab_obj; + + sal_obj = PyObject_New (sal_object, &sal_object_type); + if (sal_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, + "Could not allocate Symtab_and_line object."); + return NULL; + } + + if (sal.symtab) + { + symtab_obj = (symtab_object *) symtab_to_symtab_object (sal.symtab); + if (symtab_obj == NULL) + { + Py_DECREF (sal_obj); + return NULL; + } + + symtab_obj->symtab = sal.symtab; + } + else + { + symtab_obj = (symtab_object *) Py_None; + Py_INCREF (Py_None); + } + + sal_obj->sal = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + *(sal_obj->sal) = sal; + sal_obj->symtab = symtab_obj; + + return (PyObject *) sal_obj; +} + +PyObject * +symtab_to_symtab_object (struct symtab *symtab) +{ + symtab_object *symtab_obj; + + symtab_obj = PyObject_New (symtab_object, &symtab_object_type); + if (symtab_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, + "Could not allocate Symtab object."); + + return NULL; + } + + symtab_obj->symtab = symtab; + + return (PyObject *) symtab_obj; +} + +void +gdbpy_initialize_symtabs (void) +{ + symtab_object_type.tp_new = PyType_GenericNew; + if (PyType_Ready (&symtab_object_type) < 0) + return; + + sal_object_type.tp_new = PyType_GenericNew; + if (PyType_Ready (&sal_object_type) < 0) + return; + + Py_INCREF (&symtab_object_type); + PyModule_AddObject (gdb_module, "Symtab", (PyObject *) &symtab_object_type); + + Py_INCREF (&sal_object_type); + PyModule_AddObject (gdb_module, "Symtab_and_line", + (PyObject *) &sal_object_type); +} + + + +static PyGetSetDef symtab_object_getset[] = { + { "filename", stpy_get_filename, NULL, + "The symbol table's source filename.", NULL }, + {NULL} /* Sentinel */ +}; + +static PyMethodDef symtab_object_methods[] = { + { "fullname", stpy_fullname, METH_NOARGS, + "Return the symtab's full source filename." }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject symtab_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Symtab", /*tp_name*/ + sizeof (symtab_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + stpy_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB symtab object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + symtab_object_methods, /* tp_methods */ + 0, /* tp_members */ + symtab_object_getset /* tp_getset */ +}; + +static PyGetSetDef sal_object_getset[] = { + { "symtab", salpy_get_symtab, NULL, "Symtab object.", NULL }, + { "pc", salpy_get_pc, NULL, "Return the symtab_and_line's pc.", NULL }, + { "line", salpy_get_line, NULL, + "Return the symtab_and_line's line.", NULL }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject sal_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Symtab_and_line", /*tp_name*/ + sizeof (sal_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + salpy_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + salpy_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB symtab_and_line object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + sal_object_getset /* tp_getset */ +}; diff --git a/gdb/python/python-type.c b/gdb/python/python-type.c new file mode 100644 index 0000000..772a011 --- /dev/null +++ b/gdb/python/python-type.c @@ -0,0 +1,821 @@ +/* Python interface to types. + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "value.h" +#include "exceptions.h" +#include "python-internal.h" +#include "charset.h" +#include "gdbtypes.h" +#include "cp-support.h" +#include "demangle.h" +#include "objfiles.h" +#include "gdb_assert.h" + +typedef struct pyty_type_object +{ + PyObject_HEAD + struct type *type; + + /* 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. */ + struct pyty_type_object *prev; + struct pyty_type_object *next; +} type_object; + +static PyTypeObject type_object_type; + +/* A Field object. */ +typedef struct pyty_field_object +{ + PyObject_HEAD + + /* Dictionary holding our attributes. */ + PyObject *dict; +} field_object; + +static PyTypeObject field_object_type; + +/* This is used to initialize various gdb.TYPE_ constants. */ +struct pyty_code +{ + /* The code. */ + enum type_code code; + /* The name. */ + const char *name; +}; + +#define ENTRY(X) { X, #X } + +static struct pyty_code pyty_codes[] = +{ + ENTRY (TYPE_CODE_PTR), + ENTRY (TYPE_CODE_ARRAY), + ENTRY (TYPE_CODE_STRUCT), + ENTRY (TYPE_CODE_UNION), + ENTRY (TYPE_CODE_ENUM), + ENTRY (TYPE_CODE_FLAGS), + ENTRY (TYPE_CODE_FUNC), + ENTRY (TYPE_CODE_INT), + ENTRY (TYPE_CODE_FLT), + ENTRY (TYPE_CODE_VOID), + ENTRY (TYPE_CODE_SET), + ENTRY (TYPE_CODE_RANGE), + ENTRY (TYPE_CODE_STRING), + ENTRY (TYPE_CODE_BITSTRING), + ENTRY (TYPE_CODE_ERROR), + ENTRY (TYPE_CODE_METHOD), + ENTRY (TYPE_CODE_METHODPTR), + ENTRY (TYPE_CODE_MEMBERPTR), + ENTRY (TYPE_CODE_REF), + ENTRY (TYPE_CODE_CHAR), + ENTRY (TYPE_CODE_BOOL), + ENTRY (TYPE_CODE_COMPLEX), + ENTRY (TYPE_CODE_TYPEDEF), + ENTRY (TYPE_CODE_TEMPLATE), + ENTRY (TYPE_CODE_TEMPLATE_ARG), + ENTRY (TYPE_CODE_NAMESPACE), + ENTRY (TYPE_CODE_DECFLOAT), + ENTRY (TYPE_CODE_INTERNAL_FUNCTION), + { TYPE_CODE_UNDEF, NULL } +}; + + + +static void +field_dealloc (PyObject *obj) +{ + field_object *f = (field_object *) obj; + Py_XDECREF (f->dict); +} + +static PyObject * +field_new (void) +{ + field_object *result = PyObject_New (field_object, &field_object_type); + if (result) + { + result->dict = PyDict_New (); + if (!result->dict) + { + Py_DECREF (result); + result = NULL; + } + } + return (PyObject *) result; +} + + + +/* Return the code for this type. */ +static PyObject * +typy_code (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + return PyInt_FromLong (TYPE_CODE (type)); +} + +/* Helper function for typy_fields which converts a single field to a + dictionary. Returns NULL on error. */ +static PyObject * +convert_field (struct type *type, int field) +{ + PyObject *result = field_new (); + PyObject *arg; + + if (!result) + return NULL; + + if (!field_is_static (&TYPE_FIELD (type, field))) + { + arg = PyLong_FromLong (TYPE_FIELD_BITPOS (type, field)); + if (!arg) + goto fail; + + if (PyObject_SetAttrString (result, "bitpos", arg) < 0) + goto failarg; + } + + if (TYPE_FIELD_NAME (type, field)) + arg = PyString_FromString (TYPE_FIELD_NAME (type, field)); + else + { + arg = Py_None; + Py_INCREF (arg); + } + if (!arg) + goto fail; + if (PyObject_SetAttrString (result, "name", arg) < 0) + goto failarg; + + arg = TYPE_FIELD_ARTIFICIAL (type, field) ? Py_True : Py_False; + Py_INCREF (arg); + if (PyObject_SetAttrString (result, "artificial", arg) < 0) + goto failarg; + + arg = PyLong_FromLong (TYPE_FIELD_BITSIZE (type, field)); + if (!arg) + goto fail; + if (PyObject_SetAttrString (result, "bitsize", arg) < 0) + goto failarg; + + arg = type_to_type_object (TYPE_FIELD_TYPE (type, field)); + if (!arg) + goto fail; + if (PyObject_SetAttrString (result, "type", arg) < 0) + goto failarg; + + return result; + + failarg: + Py_DECREF (arg); + fail: + Py_DECREF (result); + return NULL; +} + +/* Return a sequence of all fields. Each field is a dictionary with + some pre-defined keys. */ +static PyObject * +typy_fields (PyObject *self, PyObject *args) +{ + PyObject *result; + int i; + struct type *type = ((type_object *) self)->type; + + /* We would like to make a tuple here, make fields immutable, and + then memoize the result (and perhaps make Field.type() lazy). + However, that can lead to cycles. */ + result = PyList_New (0); + + for (i = 0; i < TYPE_NFIELDS (type); ++i) + { + PyObject *dict = convert_field (type, i); + if (!dict) + { + Py_DECREF (result); + return NULL; + } + if (PyList_Append (result, dict)) + { + Py_DECREF (dict); + Py_DECREF (result); + return NULL; + } + } + + return result; +} + +/* Return the type's tag, or None. */ +static PyObject * +typy_tag (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + if (!TYPE_TAG_NAME (type)) + Py_RETURN_NONE; + return PyString_FromString (TYPE_TAG_NAME (type)); +} + +/* Return the type, stripped of typedefs. */ +static PyObject * +typy_strip_typedefs (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + + return type_to_type_object (check_typedef (type)); +} + +/* Return a Type object which represents a pointer to SELF. */ +static PyObject * +typy_pointer (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + type = lookup_pointer_type (type); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return type_to_type_object (type); +} + +/* Return a Type object which represents a reference to SELF. */ +static PyObject * +typy_reference (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + type = lookup_reference_type (type); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return type_to_type_object (type); +} + +/* Return a Type object which represents the target type of SELF. */ +static PyObject * +typy_target (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + + if (!TYPE_TARGET_TYPE (type)) + { + PyErr_SetString (PyExc_RuntimeError, "type does not have a target"); + return NULL; + } + + return type_to_type_object (TYPE_TARGET_TYPE (type)); +} + +/* Return a const-qualified type variant. */ +static PyObject * +typy_const (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + type = make_cv_type (1, 0, type, NULL); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return type_to_type_object (type); +} + +/* Return a volatile-qualified type variant. */ +static PyObject * +typy_volatile (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + type = make_cv_type (0, 1, type, NULL); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return type_to_type_object (type); +} + +/* Return an unqualified type variant. */ +static PyObject * +typy_unqualified (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + type = make_cv_type (0, 0, type, NULL); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return type_to_type_object (type); +} + +/* Return the size of the type represented by SELF, in bytes. */ +static PyObject * +typy_sizeof (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + CHECK_TYPEDEF (type); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return PyLong_FromLong (TYPE_LENGTH (type)); +} + +static struct type * +typy_lookup_typename (char *type_name, struct block *block) +{ + struct type *type = NULL; + volatile struct gdb_exception except; + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (!strncmp (type_name, "struct ", 7)) + type = lookup_struct (type_name + 7, block); + else if (!strncmp (type_name, "union ", 6)) + type = lookup_union (type_name + 6, block); + else if (!strncmp (type_name, "enum ", 5)) + type = lookup_enum (type_name + 5, block); + else + type = lookup_typename (type_name, block, 0); + } + if (except.reason < 0) + { + PyErr_Format (except.reason == RETURN_QUIT + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, + "%s", except.message); + return NULL; + } + + return type; +} + +static struct type * +typy_lookup_type (struct demangle_component *demangled, + struct block *block) +{ + struct type *type; + char *type_name; + enum demangle_component_type demangled_type; + + /* Save the type: typy_lookup_type() may (indirectly) overwrite + memory pointed by demangled. */ + demangled_type = demangled->type; + + if (demangled_type == DEMANGLE_COMPONENT_POINTER + || demangled_type == DEMANGLE_COMPONENT_REFERENCE + || demangled_type == DEMANGLE_COMPONENT_CONST + || demangled_type == DEMANGLE_COMPONENT_VOLATILE) + { + type = typy_lookup_type (demangled->u.s_binary.left, block); + if (! type) + return NULL; + + switch (demangled_type) + { + case DEMANGLE_COMPONENT_REFERENCE: + return lookup_reference_type (type); + case DEMANGLE_COMPONENT_POINTER: + return lookup_pointer_type (type); + case DEMANGLE_COMPONENT_CONST: + return make_cv_type (1, 0, type, NULL); + case DEMANGLE_COMPONENT_VOLATILE: + return make_cv_type (0, 1, type, NULL); + } + } + + type_name = cp_comp_to_string (demangled, 10); + type = typy_lookup_typename (type_name, block); + xfree (type_name); + + return type; +} + +static PyObject * +typy_template_argument (PyObject *self, PyObject *args) +{ + int i, argno, n_pointers; + struct type *type = ((type_object *) self)->type; + struct demangle_component *demangled; + const char *err; + struct type *argtype; + struct block *block = NULL; + PyObject *block_obj = NULL; + + if (! PyArg_ParseTuple (args, "i|O", &argno, &block_obj)) + return NULL; + + if (block_obj) + { + block = block_object_to_block (block_obj); + if (! block) + { + PyErr_SetString (PyExc_RuntimeError, + "second argument must be block"); + return NULL; + } + } + + type = check_typedef (type); + if (TYPE_CODE (type) == TYPE_CODE_REF) + type = check_typedef (TYPE_TARGET_TYPE (type)); + + if (TYPE_NAME (type) == NULL) + { + PyErr_SetString (PyExc_RuntimeError, "null type name"); + return NULL; + } + + /* Note -- this is not thread-safe. */ + demangled = cp_demangled_name_to_comp (TYPE_NAME (type), &err); + if (! demangled) + { + PyErr_SetString (PyExc_RuntimeError, err); + return NULL; + } + + /* Strip off component names. */ + while (demangled->type == DEMANGLE_COMPONENT_QUAL_NAME + || demangled->type == DEMANGLE_COMPONENT_LOCAL_NAME) + demangled = demangled->u.s_binary.right; + + if (demangled->type != DEMANGLE_COMPONENT_TEMPLATE) + { + PyErr_SetString (PyExc_RuntimeError, "type is not a template"); + return NULL; + } + + /* Skip from the template to the arguments. */ + demangled = demangled->u.s_binary.right; + + for (i = 0; demangled && i < argno; ++i) + demangled = demangled->u.s_binary.right; + + if (! demangled) + { + PyErr_Format (PyExc_RuntimeError, "no argument %d in template", + argno); + return NULL; + } + + argtype = typy_lookup_type (demangled->u.s_binary.left, block); + if (! argtype) + return NULL; + + return type_to_type_object (argtype); +} + +static PyObject * +typy_str (PyObject *self) +{ + volatile struct gdb_exception except; + char *thetype = NULL; + PyObject *result; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + struct cleanup *old_chain; + struct ui_file *stb; + long length; + + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); + + type_print (type_object_to_type (self), "", stb, -1); + + thetype = ui_file_xstrdup (stb, &length); + do_cleanups (old_chain); + } + if (except.reason < 0) + { + xfree (thetype); + GDB_PY_HANDLE_EXCEPTION (except); + } + + result = PyUnicode_Decode (thetype, strlen (thetype), host_charset (), NULL); + xfree (thetype); + + return result; +} + + + +static const struct objfile_data *typy_objfile_data_key; + +static void +clean_up_objfile_types (struct objfile *objfile, void *datum) +{ + type_object *obj = datum; + htab_t copied_types; + struct cleanup *cleanup; + PyGILState_STATE state; + + /* This prevents another thread from freeing the objects we're + operating on. */ + state = PyGILState_Ensure (); + cleanup = make_cleanup_py_restore_gil (&state); + + copied_types = create_copied_types_hash (objfile); + + while (obj) + { + type_object *next = obj->next; + + htab_empty (copied_types); + + /* No need to decref the old type here, since we know it has no + reference count. */ + gdb_assert (objfile == TYPE_OBJFILE (obj->type)); + obj->type = copy_type_recursive (obj->type, copied_types); + type_incref (obj->type); + + obj->next = NULL; + obj->prev = NULL; + + obj = next; + } + + htab_delete (copied_types); + + do_cleanups (cleanup); +} + +static void +set_type (type_object *obj, struct type *type) +{ + obj->type = type; + type_incref (type); + obj->prev = NULL; + if (type && !OBJFILE_IS_VIRTUAL (TYPE_OBJFILE (type))) + { + struct objfile *objfile = TYPE_OBJFILE (type); + + 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; +} + +static PyObject * +typy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) +{ + char *type_name = NULL; + struct type *type = NULL; + type_object *result; + PyObject *block_obj = NULL; + struct block *block = NULL; + + /* FIXME: it is strange to allow a Type with no name, but we need + this for type_to_type_object. */ + if (! PyArg_ParseTuple (args, "|sO", &type_name, &block_obj)) + return NULL; + + if (block_obj) + { + block = block_object_to_block (block_obj); + if (! block) + { + PyErr_SetString (PyExc_RuntimeError, + "second argument must be block"); + return NULL; + } + } + + if (type_name) + { + type = typy_lookup_typename (type_name, block); + if (! type) + return NULL; + } + + result = (type_object *) subtype->tp_alloc (subtype, 1); + if (! result) + return NULL; + + set_type (result, type); + + return (PyObject *) result; +} + +static void +typy_dealloc (PyObject *obj) +{ + type_object *type = (type_object *) obj; + + if (type->type) + type_decref (type->type); + + if (type->prev) + type->prev->next = type->next; + else if (type->type && !OBJFILE_IS_VIRTUAL (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->ob_type->tp_free (type); +} + +/* Create a new Type referring to TYPE. */ +PyObject * +type_to_type_object (struct type *type) +{ + type_object *type_obj; + + type_obj = PyObject_New (type_object, &type_object_type); + if (type_obj) + set_type (type_obj, type); + + return (PyObject *) type_obj; +} + +struct type * +type_object_to_type (PyObject *obj) +{ + if (! PyObject_TypeCheck (obj, &type_object_type)) + return NULL; + return ((type_object *) obj)->type; +} + + + +void +gdbpy_initialize_types (void) +{ + int i; + + typy_objfile_data_key + = register_objfile_data_with_cleanup (clean_up_objfile_types); + + if (PyType_Ready (&type_object_type) < 0) + return; + if (PyType_Ready (&field_object_type) < 0) + return; + + for (i = 0; pyty_codes[i].name; ++i) + { + if (PyModule_AddIntConstant (gdb_module, + /* Cast needed for Python 2.4. */ + (char *) pyty_codes[i].name, + pyty_codes[i].code) < 0) + return; + } + + Py_INCREF (&type_object_type); + PyModule_AddObject (gdb_module, "Type", (PyObject *) &type_object_type); + + Py_INCREF (&field_object_type); + PyModule_AddObject (gdb_module, "Field", (PyObject *) &field_object_type); +} + + + +static PyMethodDef type_object_methods[] = +{ + { "code", typy_code, METH_NOARGS, "Return the code for this type" }, + { "const", typy_const, METH_NOARGS, "Return a const variant of this type" }, + { "fields", typy_fields, METH_NOARGS, + "Return a sequence holding all the fields of this type.\n\ +Each field is a dictionary." }, + { "pointer", typy_pointer, METH_NOARGS, "Return pointer to this type" }, + { "reference", typy_reference, METH_NOARGS, "Return reference to this type" }, + { "sizeof", typy_sizeof, METH_NOARGS, + "Return the size of this type, in bytes" }, + { "tag", typy_tag, METH_NOARGS, + "Return the tag name for this type, or None." }, + { "strip_typedefs", typy_strip_typedefs, METH_NOARGS, + "Return a type stripped of typedefs"}, + { "target", typy_target, METH_NOARGS, + "Return the target type of this type" }, + { "template_argument", typy_template_argument, METH_VARARGS, + "Return a single template argument type" }, + { "unqualified", typy_unqualified, METH_NOARGS, + "Return a variant of this type without const or volatile attributes" }, + { "volatile", typy_volatile, METH_NOARGS, + "Return a volatile variant of this type" }, + { NULL } +}; + +static PyTypeObject type_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Type", /*tp_name*/ + sizeof (type_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + typy_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + typy_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ + "GDB type object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + type_object_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + typy_new, /* tp_new */ +}; + +static PyTypeObject field_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Field", /*tp_name*/ + sizeof (field_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + field_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ + "GDB field object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof (field_object, dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; diff --git a/gdb/python/python-utils.c b/gdb/python/python-utils.c index ddac2f5..f9c9486 100644 --- a/gdb/python/python-utils.c +++ b/gdb/python/python-utils.c @@ -19,6 +19,7 @@ #include "defs.h" #include "charset.h" +#include "value.h" #include "python-internal.h" @@ -99,8 +100,8 @@ python_string_to_unicode (PyObject *obj) } /* Returns a newly allocated string with the contents of the given unicode - string object converted to CHARSET. If an error occurs during the - conversion, NULL will be returned and a python exception will be set. + string object converted to a named charset. If an error occurs during + the conversion, NULL will be returned and a python exception will be set. The caller is responsible for xfree'ing the string. */ static char * @@ -191,3 +192,48 @@ gdbpy_is_string (PyObject *obj) { return PyString_Check (obj) || PyUnicode_Check (obj); } + +/* Converts OBJ to a CORE_ADDR value. + + Returns 1 on success or 0 on failure, with a Python exception set. This + function can also throw GDB exceptions. */ + +int +get_addr_from_python (PyObject *obj, CORE_ADDR *addr) +{ + if (gdbpy_is_value_object (obj)) + *addr = value_as_address (value_object_to_value (obj)); + else if (PyLong_Check (obj)) + { + /* Assume CORE_ADDR corresponds to unsigned long. */ + *addr = PyLong_AsUnsignedLong (obj); + if (PyErr_Occurred () != NULL) + return 0; + } + else if (PyInt_Check (obj)) + { + long val; + + /* Assume CORE_ADDR corresponds to unsigned long. */ + val = PyInt_AsLong (obj); + + if (val >= 0) + *addr = val; + else + { + /* If no error ocurred, VAL is indeed negative. */ + if (PyErr_Occurred () != NULL) + return 0; + + PyErr_SetString (PyExc_ValueError, "negative address"); + return 0; + } + } + else + { + PyErr_SetString (PyExc_TypeError, "invalid type for address"); + return 0; + } + + return 1; +} diff --git a/gdb/python/python-value.c b/gdb/python/python-value.c index bc077b6..2507fcd 100644 --- a/gdb/python/python-value.c +++ b/gdb/python/python-value.c @@ -52,6 +52,10 @@ struct value *values_in_python = NULL; /* Python's long type corresponds to C's long long type. */ #define builtin_type_pylong builtin_type (current_gdbarch)->builtin_long_long +/* Python's long type corresponds to C's long long type. Unsigned version. */ +#define builtin_type_upylong builtin_type \ + (current_gdbarch)->builtin_unsigned_long_long + #define builtin_type_pybool \ language_bool_type (current_language, current_gdbarch) @@ -143,10 +147,19 @@ valpy_address (PyObject *self, PyObject *args) return value_to_value_object (res_val); } -/* Return Unicode string with value contents (assumed to be encoded in the - target's charset). */ +/* Return type of the value. */ +static PyObject * +valpy_type (PyObject *self, PyObject *args) +{ + struct value *value = ((value_object *) self)->value; + return type_to_type_object (value_type (value)); +} + +/* Implementation of gdb.Value.string ([encoding] [, errors]) -> string + Return Unicode string with value contents. If ENCODING is not given, + the string is assumed to be encoded in the target's charset. */ static PyObject * -valpy_string (PyObject *self, PyObject *args) +valpy_string (PyObject *self, PyObject *args, PyObject *kw) { int length, ret = 0; gdb_byte *buffer; @@ -157,8 +170,10 @@ valpy_string (PyObject *self, PyObject *args) const char *errors = NULL; const char *user_encoding = NULL; const char *la_encoding = NULL; + static char *keywords[] = { "encoding", "errors" }; - if (!PyArg_ParseTuple (args, "|ss", &user_encoding, &errors)) + if (!PyArg_ParseTupleAndKeywords (args, kw, "|ss", keywords, + &user_encoding, &errors)) return NULL; TRY_CATCH (except, RETURN_MASK_ALL) @@ -174,6 +189,34 @@ valpy_string (PyObject *self, PyObject *args) return unicode; } +/* Cast a value to a given type. */ +static PyObject * +valpy_cast (PyObject *self, PyObject *args) +{ + PyObject *type_obj; + struct type *type; + struct value *res_val = NULL; /* Initialize to appease gcc warning. */ + volatile struct gdb_exception except; + + if (! PyArg_ParseTuple (args, "O", &type_obj)) + return NULL; + + type = type_object_to_type (type_obj); + if (! type) + { + PyErr_SetString (PyExc_RuntimeError, "argument must be a Type"); + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + res_val = value_cast (type, ((value_object *) self)->value); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return value_to_value_object (res_val); +} + static Py_ssize_t valpy_length (PyObject *self) { @@ -306,11 +349,11 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other) a gdb.Value object and need to convert it from python as well. */ arg1 = convert_value_from_python (self); if (arg1 == NULL) - return NULL; + break; arg2 = convert_value_from_python (other); if (arg2 == NULL) - return NULL; + break; switch (opcode) { @@ -387,7 +430,7 @@ valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other) } GDB_PY_HANDLE_EXCEPTION (except); - return value_to_value_object (res_val); + return res_val ? value_to_value_object (res_val) : NULL; } static PyObject * @@ -718,6 +761,17 @@ value_to_value_object (struct value *val) return (PyObject *) val_obj; } +/* Returns value structure corresponding to the given value object. */ +struct value * +value_object_to_value (PyObject *self) +{ + value_object *real; + if (! PyObject_TypeCheck (self, &value_object_type)) + return NULL; + real = (value_object *) self; + return real->value; +} + /* Try to convert a Python value to a gdb value. If the value cannot be converted, set a Python exception and return NULL. */ @@ -751,7 +805,34 @@ convert_value_from_python (PyObject *obj) { LONGEST l = PyLong_AsLongLong (obj); - if (! PyErr_Occurred ()) + if (PyErr_Occurred ()) + { + /* If the error was an overflow, we can try converting to + ULONGEST instead. */ + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + { + PyObject *etype, *evalue, *etraceback, *zero; + + PyErr_Fetch (&etype, &evalue, &etraceback); + zero = PyInt_FromLong (0); + + /* Check whether obj is positive. */ + if (PyObject_RichCompareBool (obj, zero, Py_GT) > 0) + { + ULONGEST ul; + + ul = PyLong_AsUnsignedLongLong (obj); + if (! PyErr_Occurred ()) + value = value_from_ulongest (builtin_type_upylong, ul); + } + else + /* There's nothing we can do. */ + PyErr_Restore (etype, evalue, etraceback); + + Py_DECREF (zero); + } + } + else value = value_from_longest (builtin_type_pylong, l); } else if (PyFloat_Check (obj)) @@ -774,7 +855,7 @@ convert_value_from_python (PyObject *obj) } } else if (PyObject_TypeCheck (obj, &value_object_type)) - value = ((value_object *) obj)->value; + value = value_copy (((value_object *) obj)->value); else PyErr_Format (PyExc_TypeError, _("Could not convert Python object: %s"), PyString_AsString (PyObject_Str (obj))); @@ -810,6 +891,14 @@ gdbpy_history (PyObject *self, PyObject *args) return value_to_value_object (res_val); } +/* Returns 1 in OBJ is a gdb.Value object, 0 otherwise. */ + +int +gdbpy_is_value_object (PyObject *obj) +{ + return PyObject_TypeCheck (obj, &value_object_type); +} + void gdbpy_initialize_values (void) { @@ -822,11 +911,16 @@ gdbpy_initialize_values (void) values_in_python = NULL; } + + static PyMethodDef value_object_methods[] = { { "address", valpy_address, METH_NOARGS, "Return the address of the value." }, + { "cast", valpy_cast, METH_VARARGS, "Cast the value to the supplied type." }, { "dereference", valpy_dereference, METH_NOARGS, "Dereferences the value." }, - { "string", valpy_string, METH_VARARGS, - "Return Unicode string representation of the value." }, + { "type", valpy_type, METH_NOARGS, "Return type of the value." }, + { "string", (PyCFunction) valpy_string, METH_VARARGS | METH_KEYWORDS, + "string ([encoding] [, errors]) -> string\n\ +Return Unicode string representation of the value." }, {NULL} /* Sentinel */ }; diff --git a/gdb/python/python.c b/gdb/python/python.c index b3a27d6..2b06748 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -22,6 +22,12 @@ #include "ui-out.h" #include "cli/cli-script.h" #include "gdbcmd.h" +#include "objfiles.h" +#include "observer.h" +#include "gdb_regex.h" +#include "language.h" +#include "valprint.h" +#include "event-loop.h" #include @@ -29,6 +35,10 @@ false otherwise. */ static int gdbpy_should_print_stack = 1; +/* This is true if we should auto-load python code when an objfile is + opened, false otherwise. */ +static int gdbpy_auto_load = 1; + #ifdef HAVE_PYTHON #include "python.h" @@ -36,16 +46,29 @@ static int gdbpy_should_print_stack = 1; #include "cli/cli-decode.h" #include "charset.h" #include "top.h" +#include "solib.h" #include "exceptions.h" #include "python-internal.h" +#include "linespec.h" +#include "symtab.h" +#include "source.h" #include "version.h" +#include "inferior.h" +#include "gdbthread.h" #include "target.h" #include "gdbthread.h" +#include "event-top.h" + +static PyMethodDef GdbMethods[]; static PyMethodDef GdbMethods[]; PyObject *gdb_module; +/* Some string constants we may wish to use. */ +PyObject *gdbpy_to_string_cst; +PyObject *gdbpy_children_cst; +PyObject *gdbpy_display_hint_cst; PyObject *gdbpy_doc_cst; /* Given a command_line, return a command string suitable for passing @@ -143,10 +166,10 @@ python_command (char *arg, int from_tty) NULL (and set a Python exception) on error. Helper function for get_parameter. */ -static PyObject * -parameter_to_python (struct cmd_list_element *cmd) +PyObject * +gdbpy_parameter_value (enum var_types type, void *var) { - switch (cmd->var_type) + switch (type) { case var_string: case var_string_noescape: @@ -154,7 +177,7 @@ parameter_to_python (struct cmd_list_element *cmd) case var_filename: case var_enum: { - char *str = * (char **) cmd->var; + char *str = * (char **) var; if (! str) str = ""; return PyString_Decode (str, strlen (str), host_charset (), NULL); @@ -162,7 +185,7 @@ parameter_to_python (struct cmd_list_element *cmd) case var_boolean: { - if (* (int *) cmd->var) + if (* (int *) var) Py_RETURN_TRUE; else Py_RETURN_FALSE; @@ -170,7 +193,7 @@ parameter_to_python (struct cmd_list_element *cmd) case var_auto_boolean: { - enum auto_boolean ab = * (enum auto_boolean *) cmd->var; + enum auto_boolean ab = * (enum auto_boolean *) var; if (ab == AUTO_BOOLEAN_TRUE) Py_RETURN_TRUE; else if (ab == AUTO_BOOLEAN_FALSE) @@ -180,15 +203,15 @@ parameter_to_python (struct cmd_list_element *cmd) } case var_integer: - if ((* (int *) cmd->var) == INT_MAX) + if ((* (int *) var) == INT_MAX) Py_RETURN_NONE; /* Fall through. */ case var_zinteger: - return PyLong_FromLong (* (int *) cmd->var); + return PyLong_FromLong (* (int *) var); case var_uinteger: { - unsigned int val = * (unsigned int *) cmd->var; + unsigned int val = * (unsigned int *) var; if (val == UINT_MAX) Py_RETURN_NONE; return PyLong_FromUnsignedLong (val); @@ -202,10 +225,11 @@ parameter_to_python (struct cmd_list_element *cmd) value. */ static PyObject * -get_parameter (PyObject *self, PyObject *args) +gdbpy_parameter (PyObject *self, PyObject *args) { struct cmd_list_element *alias, *prefix, *cmd; char *arg, *newarg; + int found = -1; volatile struct gdb_exception except; if (! PyArg_ParseTuple (args, "s", &arg)) @@ -215,19 +239,17 @@ get_parameter (PyObject *self, PyObject *args) TRY_CATCH (except, RETURN_MASK_ALL) { - if (! lookup_cmd_composition (newarg, &alias, &prefix, &cmd)) - { - xfree (newarg); - return PyErr_Format (PyExc_RuntimeError, - "could not find variable `%s'", arg); - } + found = lookup_cmd_composition (newarg, &alias, &prefix, &cmd); } xfree (newarg); GDB_PY_HANDLE_EXCEPTION (except); + if (!found) + return PyErr_Format (PyExc_RuntimeError, + "could not find parameter `%s'", arg); if (! cmd->var) - return PyErr_Format (PyExc_RuntimeError, "`%s' is not a variable", arg); - return parameter_to_python (cmd); + return PyErr_Format (PyExc_RuntimeError, "`%s' is not a parameter", arg); + return gdbpy_parameter_value (cmd->var_type, cmd->var); } /* A Python function which evaluates a string using the gdb CLI. */ @@ -266,6 +288,570 @@ execute_gdb_command (PyObject *self, PyObject *args) Py_RETURN_NONE; } +/* Implementation of gdb.solib_address (Long) -> String. + Returns the name of the shared library holding a given address, or None. */ + +static PyObject * +gdbpy_solib_address (PyObject *self, PyObject *args) +{ + unsigned long long pc; + char *soname; + PyObject *str_obj; + + if (!PyArg_ParseTuple (args, "K", &pc)) + return NULL; + + soname = solib_address (pc); + if (soname) + str_obj = PyString_Decode (soname, strlen (soname), host_charset (), NULL); + else + { + str_obj = Py_None; + Py_INCREF (Py_None); + } + + return str_obj; +} + +static PyObject * +gdbpy_find_pc_function (PyObject *self, PyObject *args) +{ + unsigned long long pc; + struct symbol *sym; + PyObject *sym_obj; + + if (!PyArg_ParseTuple (args, "K", &pc)) + return NULL; + + sym = find_pc_function (pc); + if (sym) + return symbol_to_symbol_object (sym); + + Py_RETURN_NONE; +} + +/* Adds GDB value V to the pattern buffer in *PATTERN_BUF. If SIZE is not zero, + it specifies the number of bytes from V to copy to *PATTERN_BUF. The + function increases the size of *PATTERN_BUF as necessary, adjusting + *PATTERN_BUF_END and *PATTERN_BUF_SIZE in the process. */ + +static void +add_value_pattern (struct value *v, int size, char **pattern_buf, + char **pattern_buf_end, ULONGEST *pattern_buf_size) +{ + int val_bytes; + + if (size) + { + LONGEST x = value_as_long (v); + + if (size == 1) + *(*pattern_buf_end)++ = x; + else + { + put_bits (x, *pattern_buf_end, size * 8, + gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG); + *pattern_buf_end += size; + } + } + else + { + val_bytes = TYPE_LENGTH (value_type (v)); + + increase_pattern_buffer (pattern_buf, pattern_buf_end, + pattern_buf_size, val_bytes); + + memcpy (*pattern_buf_end, value_contents_raw (v), val_bytes); + *pattern_buf_end += val_bytes; + } +} + +/* This function does the actual work of constructing the pattern buffer from + OBJ. If OBJ is an object which implements the read buffer protocol (such + as a string, a byte array or gdb.Membuf), then its contents are directly + copied to *PATTERN_BUF. If it is a list, then this function is recursively + called for each of its elements. If OBJ is an object which can be converted + to a GDB value, then the contents of the value are copied to PATTERN_BUF. + If SIZE is different than zero, then it limits the number of bytes which + are copied to the buffer in case OBJ is converted to a GDB value. That + means that SIZE influences only Python scalars and gdb.Value objects. + The function increases the size of *PATTERN_BUF as necessary, adjusting + *PATTERN_BUF_END and *PATTERN_BUF_SIZE in the process. + + Returns 1 on success or 0 on failure, with a Python exception set. This + function can also throw GDB exceptions. */ + +static int +add_pattern_element (PyObject *obj, int size, char **pattern_buf, + char **pattern_buf_end, ULONGEST *pattern_buf_size) +{ + if (PyObject_CheckReadBuffer (obj)) + { + /* Handle string, Unicode string, byte array, gdb.Membuf and any other + object implementing the buffer protocol. The SIZE parameter is + ignored in this case. */ + + Py_ssize_t val_bytes; + const void *buffer; + + if (PyObject_AsReadBuffer (obj, &buffer, &val_bytes) == -1) + return 0; + + increase_pattern_buffer (pattern_buf, pattern_buf_end, + pattern_buf_size, val_bytes); + + memcpy (*pattern_buf_end, buffer, val_bytes); + *pattern_buf_end += val_bytes; + } + else if (gdbpy_is_value_object (obj)) + add_value_pattern (value_object_to_value (obj), size, pattern_buf, + pattern_buf_end, pattern_buf_size); + else if (PySequence_Check (obj)) + { + /* Handle lists and tuples. */ + + Py_ssize_t i, num_objs; + + num_objs = PySequence_Size (obj); + for (i = 0; i < num_objs; i++) + if (!add_pattern_element (PySequence_GetItem (obj, i), size, + pattern_buf, pattern_buf_end, + pattern_buf_size)) + return 0; + } + else + { + /* See if we can convert from a Python object to a GDB value. */ + + struct value *v = convert_value_from_python (obj); + + if (v) + add_value_pattern (v, size, pattern_buf, pattern_buf_end, + pattern_buf_size); + else + return 0; + } + + return 1; +} + +/* Constructs the search pattern from OBJ, putting it in *PATTERN_BUFP, and its + size in *PATTERN_LENP. See the function add_pattern_element to learn how + the search pattern is obtained from OBJ. + + Returns 1 on success or 0 on failure, with a Python exception set. This + function can also throw GDB exceptions. */ + +static int +get_search_pattern (PyObject *obj, int size, char **pattern_bufp, + ULONGEST *pattern_lenp) +{ + /* Buffer to hold the search pattern. */ + char *pattern_buf; + /* Current size of search pattern buffer. + We realloc space as needed. */ + ULONGEST pattern_buf_size; + /* Pointer to one past the last in-use part of pattern_buf. */ + char *pattern_buf_end; + struct cleanup *old_cleanups; + + allocate_pattern_buffer (&pattern_buf, &pattern_buf_end, &pattern_buf_size); + old_cleanups = make_cleanup (free_current_contents, &pattern_buf); + + if (!add_pattern_element (obj, size, &pattern_buf, &pattern_buf_end, + &pattern_buf_size)) + { + do_cleanups (old_cleanups); + + return 0; + } + + *pattern_bufp = pattern_buf; + *pattern_lenp = pattern_buf_end - pattern_buf; + + discard_cleanups (old_cleanups); + + return 1; +} + +/* Implementation of + gdb.search_memory (address, length, pattern [, size] [, max_count]). + The third argument may be either a pattern, or a list or tupple of patterns + to be searched. Size is the size in bytes of each search query value, either + 1, 2, 4 or 8. Returns a list of the addresses where matches were found. */ + +PyObject * +gdbpy_search_memory (PyObject *self, PyObject *args, PyObject *kw) +{ + int size = 0; + long length; + unsigned int found_count = 0; + long max_count = 0; + CORE_ADDR start_addr; + char *pattern_buf; + static char *keywords[] = { "address", "length", "pattern", "size", + "max_count", NULL }; + ULONGEST pattern_len, search_space_len; + PyObject *pattern, *list = NULL, *start_addr_obj; + volatile struct gdb_exception except; + + /* Assume CORE_ADDR corresponds to unsigned long. */ + if (! PyArg_ParseTupleAndKeywords (args, kw, "OlO|il", keywords, + &start_addr_obj, &length, &pattern, + &size, &max_count)) + return NULL; + + if (!max_count) + max_count = LONG_MAX; + + if (!length) + { + PyErr_SetString (PyExc_ValueError, "empty search range"); + return NULL; + } + else if (length < 0) + { + PyErr_SetString (PyExc_ValueError, "invalid search range"); + return NULL; + } + else + { + /* Watch for overflows. */ + if (length > CORE_ADDR_MAX + || (start_addr + length - 1) < start_addr) + { + PyErr_SetString (PyExc_ValueError, "search range too large"); + return NULL; + } + + search_space_len = length; + } + + if (size != 0 && size != 1 && size != 2 && size != 4 && size != 8) + { + PyErr_SetString (PyExc_ValueError, "invalid pattern size"); + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (get_addr_from_python (start_addr_obj, &start_addr)) + { + if (get_search_pattern (pattern, size, &pattern_buf, &pattern_len)) + { + /* Any cleanups get automatically executed on an exception. */ + struct cleanup *cleanups = make_cleanup (xfree, pattern_buf); + + list = PyList_New (0); + + while (search_space_len >= pattern_len && found_count < max_count) + { + CORE_ADDR found_addr; + int found; + + found = search_memory (&start_addr, &search_space_len, + pattern_buf, pattern_len, &found_addr); + if (found <= 0) + break; + + PyList_Append (list, PyLong_FromUnsignedLong (found_addr)); + ++found_count; + } + + do_cleanups (cleanups); + } + } + } + GDB_PY_HANDLE_EXCEPTION (except); + + return list; +} + +/* A Python function which is a wrapper for decode_line_1. */ + +static PyObject * +gdbpy_decode_line (PyObject *self, PyObject *args) +{ + struct symtabs_and_lines sals = { NULL, 0 }; /* Initialize to appease gcc. */ + struct symtab_and_line sal; + char *arg = NULL; + int free_sals = 0, i; + PyObject *result = NULL; + volatile struct gdb_exception except; + + if (! PyArg_ParseTuple (args, "|s", &arg)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (arg) + { + char *copy; + + arg = strdup (arg); + copy = arg; + + sals = decode_line_1 (©, 0, 0, 0, 0, 0); + free_sals = 1; + } + else + { + set_default_source_symtab_and_line (); + sal = get_current_source_symtab_and_line (); + sals.sals = &sal; + sals.nelts = 1; + } + } + if (arg) + xfree (arg); + + if (except.reason < 0) + { + if (free_sals) + xfree (sals.sals); + /* We know this will always throw. */ + GDB_PY_HANDLE_EXCEPTION (except); + } + + if (sals.nelts) + { + result = PyTuple_New (sals.nelts); + for (i = 0; i < sals.nelts; ++i) + { + PyObject *obj; + char *str; + + obj = symtab_and_line_to_sal_object (sals.sals[i]); + if (! obj) + { + Py_DECREF (result); + result = NULL; + break; + } + + PyTuple_SetItem (result, i, obj); + } + } + + if (free_sals) + xfree (sals.sals); + + if (result) + return result; + Py_RETURN_NONE; +} + +/* Parse a string and evaluate it as an expression. */ +static PyObject * +gdbpy_parse_and_eval (PyObject *self, PyObject *args) +{ + char *expr_str; + struct value *result = NULL; + volatile struct gdb_exception except; + + if (!PyArg_ParseTuple (args, "s", &expr_str)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + result = parse_and_eval (expr_str); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return value_to_value_object (result); +} + + + +/* Posting and handling events. */ + +/* A single event. */ +struct gdbpy_event +{ + /* The Python event. This is just a callable object. */ + PyObject *event; + /* The next event. */ + struct gdbpy_event *next; +}; + +/* All pending events. */ +static struct gdbpy_event *gdbpy_event_list; +/* The final link of the event list. */ +static struct gdbpy_event **gdbpy_event_list_end; + +/* We use a file handler, and not an async handler, so that we can + wake up the main thread even when it is blocked in poll(). */ +static int gdbpy_event_fds[2]; + +/* The file handler callback. This reads from the internal pipe, and + then processes the Python event queue. This will always be run in + the main gdb thread. */ +static void +gdbpy_run_events (int err, gdb_client_data ignore) +{ + PyGILState_STATE state; + char buffer[100]; + int r; + + state = PyGILState_Ensure (); + + /* Just read whatever is available on the fd. It is relatively + harmless if there are any bytes left over. */ + r = read (gdbpy_event_fds[0], buffer, sizeof (buffer)); + + while (gdbpy_event_list) + { + /* Dispatching the event might push a new element onto the event + loop, so we update here "atomically enough". */ + struct gdbpy_event *item = gdbpy_event_list; + gdbpy_event_list = gdbpy_event_list->next; + if (gdbpy_event_list == NULL) + gdbpy_event_list_end = &gdbpy_event_list; + + /* Ignore errors. */ + PyObject_CallObject (item->event, NULL); + + Py_DECREF (item->event); + xfree (item); + } + + PyGILState_Release (state); +} + +/* Submit an event to the gdb thread. */ +static PyObject * +gdbpy_post_event (PyObject *self, PyObject *args) +{ + struct gdbpy_event *event; + PyObject *func; + int wakeup; + + if (!PyArg_ParseTuple (args, "O", &func)) + return NULL; + + if (!PyCallable_Check (func)) + { + PyErr_SetString (PyExc_RuntimeError, "Posted event is not callable"); + return NULL; + } + + Py_INCREF (func); + + /* From here until the end of the function, we have the GIL, so we + can operate on our global data structures without worrying. */ + wakeup = gdbpy_event_list == NULL; + + event = XNEW (struct gdbpy_event); + event->event = func; + event->next = NULL; + *gdbpy_event_list_end = event; + gdbpy_event_list_end = &event->next; + + /* Wake up gdb when needed. */ + if (wakeup) + { + char c = 'q'; /* Anything. */ + if (write (gdbpy_event_fds[1], &c, 1) != 1) + return PyErr_SetFromErrno (PyExc_IOError); + } + + Py_RETURN_NONE; +} + +/* Initialize the Python event handler. */ +static void +gdbpy_initialize_events (void) +{ + if (!pipe (gdbpy_event_fds)) + { + gdbpy_event_list_end = &gdbpy_event_list; + add_file_handler (gdbpy_event_fds[0], gdbpy_run_events, NULL); + } +} + + + +/* Threads. */ + +/* Callback function for use with iterate_over_threads. This function + just counts the number of threads. */ + +static int +count_callback (struct thread_info *info, void *user_data) +{ + int *count = (int *) user_data; + ++*count; + return 0; +} + +/* Structure for storing some state when iterating over threads. */ + +struct set_thread_info +{ + PyObject *tuple; + int index; +}; + +/* Callback function for use with iterate_over_threads. This function + stores the thread ID into a Python tuple. */ + +static int +update_tuple_callback (struct thread_info *info, void *user_data) +{ + struct set_thread_info *tinfo = (struct set_thread_info *) user_data; + PyTuple_SetItem (tinfo->tuple, tinfo->index, PyInt_FromLong (info->num)); + ++tinfo->index; + return 0; +} + +/* Python function which yields a tuple holding all valid thread IDs. */ + +static PyObject * +gdbpy_threads (PyObject *unused1, PyObject *unused2) +{ + int thread_count = 0; + struct set_thread_info info; + PyObject *result; + + prune_threads (); + target_find_new_threads (); + + iterate_over_threads (count_callback, &thread_count); + + if (!thread_count) + Py_RETURN_NONE; + + result = PyTuple_New (thread_count); + info.tuple = result; + info.index = 0; + iterate_over_threads (update_tuple_callback, &info); + return result; +} + +/* Python function that returns the current thread's ID. */ + +static PyObject * +gdbpy_current_thread (PyObject *unused1, PyObject *unused2) +{ + if (PIDGET (inferior_ptid) == 0) + Py_RETURN_NONE; + return PyInt_FromLong (pid_to_thread_id (inferior_ptid)); +} + +/* Python function for switching to a given thread. */ + +static PyObject * +gdbpy_switch_to_thread (PyObject *self, PyObject *args) +{ + int id; + if (! PyArg_ParseTuple (args, "i", &id)) + return NULL; + if (! valid_thread_id (id)) + return PyErr_Format (PyExc_RuntimeError, "invalid thread id"); + switch_to_thread (thread_id_to_pid (id)); + Py_RETURN_NONE; +} + /* Printing. */ @@ -302,6 +888,769 @@ gdbpy_print_stack (void) PyErr_Clear (); } + + +/* Script interface. */ + +/* True if 'gdb -P' was used, false otherwise. */ +static int running_python_script; + +/* True if we are currently in a call to 'gdb.cli', false otherwise. */ +static int in_cli; + +/* Enter the command loop. */ + +static PyObject * +gdbpy_cli (PyObject *unused1, PyObject *unused2) +{ + if (! running_python_script || in_cli) + return PyErr_Format (PyExc_RuntimeError, "cannot invoke CLI recursively"); + + in_cli = 1; + cli_command_loop (); + in_cli = 0; + + Py_RETURN_NONE; +} + +/* Set up the Python argument vector and evaluate a script. This is + used to implement 'gdb -P'. */ + +void +run_python_script (int argc, char **argv) +{ + FILE *input; + PyGILState_STATE state; + + /* We never free this, since we plan to exit at the end. */ + state = PyGILState_Ensure (); + + running_python_script = 1; + PySys_SetArgv (argc - 1, argv + 1); + input = fopen (argv[0], "r"); + if (! input) + { + fprintf (stderr, "could not open %s: %s\n", argv[0], strerror (errno)); + exit (1); + } + PyRun_SimpleFile (input, argv[0]); + fclose (input); + exit (0); +} + +void +source_python_script (FILE *stream, char *file) +{ + PyGILState_STATE state; + + state = PyGILState_Ensure (); + + PyRun_SimpleFile (stream, file); + + fclose (stream); + PyGILState_Release (state); +} + + + +/* The "current" objfile. This is set when gdb detects that a new + objfile has been loaded. It is only set for the duration of a call + to gdbpy_new_objfile; it is NULL at other times. */ +static struct objfile *gdbpy_current_objfile; + +/* The file name we attempt to read. */ +#define GDBPY_AUTO_FILENAME "-gdb.py" + +/* This is a new_objfile observer callback which loads python code + based on the path to the objfile. */ +static void +gdbpy_new_objfile (struct objfile *objfile) +{ + char *realname; + char *filename, *debugfile; + int len; + FILE *input; + PyGILState_STATE state; + struct cleanup *cleanups; + + if (!gdbpy_auto_load || !objfile || !objfile->name) + return; + + state = PyGILState_Ensure (); + + gdbpy_current_objfile = objfile; + + realname = gdb_realpath (objfile->name); + len = strlen (realname); + filename = xmalloc (len + sizeof (GDBPY_AUTO_FILENAME)); + memcpy (filename, realname, len); + strcpy (filename + len, GDBPY_AUTO_FILENAME); + + input = fopen (filename, "r"); + debugfile = filename; + + cleanups = make_cleanup (xfree, filename); + make_cleanup (xfree, realname); + + if (!input && debug_file_directory) + { + /* Also try the same file in the separate debug info directory. */ + debugfile = xmalloc (strlen (filename) + + strlen (debug_file_directory) + 1); + strcpy (debugfile, debug_file_directory); + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + } + + if (!input && gdb_datadir) + { + /* Also try the same file in a subdirectory of gdb's data + directory. */ + debugfile = xmalloc (strlen (gdb_datadir) + strlen (filename) + + strlen ("/auto-load") + 1); + strcpy (debugfile, gdb_datadir); + strcat (debugfile, "/auto-load"); + /* FILENAME is absolute, so we don't need a "/" here. */ + strcat (debugfile, filename); + + make_cleanup (xfree, debugfile); + input = fopen (debugfile, "r"); + } + + if (input) + { + /* We don't want to throw an exception here -- but the user + would like to know that something went wrong. */ + if (PyRun_SimpleFile (input, debugfile)) + gdbpy_print_stack (); + fclose (input); + } + + do_cleanups (cleanups); + gdbpy_current_objfile = NULL; + + PyGILState_Release (state); +} + +/* Return the current Objfile, or None if there isn't one. */ +static PyObject * +gdbpy_get_current_objfile (PyObject *unused1, PyObject *unused2) +{ + PyObject *result; + + if (! gdbpy_current_objfile) + Py_RETURN_NONE; + + result = objfile_to_objfile_object (gdbpy_current_objfile); + if (result) + Py_INCREF (result); + return result; +} + +/* Return a sequence holding all the Objfiles. */ +static PyObject * +gdbpy_objfiles (PyObject *unused1, PyObject *unused2) +{ + struct objfile *objf; + PyObject *list; + + list = PyList_New (0); + if (!list) + return NULL; + + ALL_OBJFILES (objf) + { + PyObject *item = objfile_to_objfile_object (objf); + if (!item || PyList_Append (list, item) == -1) + { + Py_DECREF (list); + return NULL; + } + } + + return list; +} + + + +/* Helper function for find_pretty_printer which iterates over a + list, calls each function and inspects output. */ +static PyObject * +search_pp_list (PyObject *list, PyObject *value) +{ + Py_ssize_t pp_list_size, list_index; + PyObject *function, *printer = NULL; + + pp_list_size = PyList_Size (list); + for (list_index = 0; list_index < pp_list_size; list_index++) + { + function = PyList_GetItem (list, list_index); + if (! function) + return NULL; + + /* gdbpy_instantiate_printer can return three possible return + values: NULL on error; Py_None if the pretty-printer + in the list cannot print the value; or a printer instance if + the printer can print the value. */ + printer = gdbpy_instantiate_printer (function, value); + if (! printer) + return NULL; + else if (printer != Py_None) + return printer; + + Py_DECREF (printer); + } + + Py_RETURN_NONE; +} + +/* Find the pretty-printing constructor function for TYPE. If no + pretty-printer exists, return NULL. If one exists, return a new + reference. */ +static PyObject * +find_pretty_printer (PyObject *value) +{ + PyObject *pp_list = NULL; + PyObject *function = NULL; + struct objfile *obj; + volatile struct gdb_exception except; + + /* Look at the pretty-printer dictionary for each objfile. */ + ALL_OBJFILES (obj) + { + PyObject *objf = objfile_to_objfile_object (obj); + if (!objf) + continue; + + pp_list = objfpy_get_printers (objf, NULL); + function = search_pp_list (pp_list, value); + + /* If there is an error in any objfile list, abort the search and + exit. */ + if (! function) + { + Py_XDECREF (pp_list); + return NULL; + } + + if (function != Py_None) + goto done; + + /* In this loop, if function is not an instantiation of a + pretty-printer, and it is not null, then it is a return of + Py_RETURN_NONE, which must be decremented. */ + Py_DECREF (function); + Py_XDECREF (pp_list); + } + + pp_list = NULL; + /* Fetch the global pretty printer dictionary. */ + if (! PyObject_HasAttrString (gdb_module, "pretty_printers")) + goto done; + pp_list = PyObject_GetAttrString (gdb_module, "pretty_printers"); + if (! pp_list) + goto done; + if (! PyList_Check (pp_list)) + goto done; + + function = search_pp_list (pp_list, value); + + done: + Py_XDECREF (pp_list); + + return function; +} + +/* Pretty-print a single value, via the printer object PRINTER. If + the function returns a string, an xmalloc()d copy is returned. + Otherwise, if the function returns a value, a *OUT_VALUE is set to + the value, and NULL is returned. On error, *OUT_VALUE is set to + NULL and NULL is returned. */ +static char * +pretty_print_one_value (PyObject *printer, struct value **out_value) +{ + char *output = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + PyObject *result; + + result = PyObject_CallMethodObjArgs (printer, gdbpy_to_string_cst, NULL); + if (result) + { + if (gdbpy_is_string (result)) + output = python_string_to_host_string (result); + else if (PyObject_TypeCheck (result, &value_object_type)) + { + /* If we just call convert_value_from_python for this + type, we won't know who owns the result. For this + one case we need to copy the resulting value. */ + struct value *v = value_object_to_value (result); + *out_value = value_copy (v); + } + else + *out_value = convert_value_from_python (result); + Py_DECREF (result); + } + } + + return output; +} + +/* Instantiate a pretty-printer given a constructor, CONS, and a + value, VAL. Return NULL on error. Ownership of the object + instance is transferred to the reciever */ +PyObject * +gdbpy_instantiate_printer (PyObject *cons, PyObject *value) +{ + PyObject *result; + result = PyObject_CallFunctionObjArgs (cons, value, NULL); + return result; +} + +/* Return the display hint for the object printer, PRINTER. Return + NULL if there is no display_hint method, or if the method did not + return a string. On error, print stack trace and return NULL. On + success, return an xmalloc()d string. */ +char * +gdbpy_get_display_hint (PyObject *printer) +{ + PyObject *hint; + char *result = NULL; + + if (! PyObject_HasAttr (printer, gdbpy_display_hint_cst)) + return NULL; + + hint = PyObject_CallMethodObjArgs (printer, gdbpy_display_hint_cst, NULL); + if (gdbpy_is_string (hint)) + result = python_string_to_host_string (hint); + if (hint) + Py_DECREF (hint); + else + gdbpy_print_stack (); + + return result; +} + +/* Helper for apply_val_pretty_printer which calls to_string and + formats the result. */ +static void +print_string_repr (PyObject *printer, const char *hint, + struct ui_file *stream, int recurse, + const struct value_print_options *options, + const struct language_defn *language) +{ + char *output; + struct value *replacement = NULL; + + output = pretty_print_one_value (printer, &replacement); + if (output) + { + if (hint && !strcmp (hint, "string")) + { + struct type *string_char_type; + + /* OUTPUT is already in the hosts's charset. */ + string_char_type = language_string_char_type (language, + current_gdbarch); + LA_PRINT_STRING (stream, string_char_type, (gdb_byte *) output, + strlen (output), 0, options); + } + else + fputs_filtered (output, stream); + xfree (output); + } + else if (replacement) + common_val_print (replacement, stream, recurse, options, language); + else + gdbpy_print_stack (); +} + +static void +py_restore_tstate (void *p) +{ + PyFrameObject *frame = p; + PyThreadState *tstate = PyThreadState_GET (); + tstate->frame = frame; +} + +/* Create a dummy PyFrameObject, needed to work around + a Python-2.4 bug with generators. */ +static PyObject * +push_dummy_python_frame () +{ + PyObject *empty_string, *null_tuple, *globals; + PyCodeObject *code; + PyFrameObject *frame; + PyThreadState *tstate; + + empty_string = PyString_FromString (""); + if (!empty_string) + return NULL; + + null_tuple = PyTuple_New (0); + if (!null_tuple) + { + Py_DECREF (empty_string); + return NULL; + } + + code = PyCode_New (0, /* argcount */ + 0, /* nlocals */ + 0, /* stacksize */ + 0, /* flags */ + empty_string, /* code */ + null_tuple, /* consts */ + null_tuple, /* names */ + null_tuple, /* varnames */ +#if PYTHON_API_VERSION >= 1010 + null_tuple, /* freevars */ + null_tuple, /* cellvars */ +#endif + empty_string, /* filename */ + empty_string, /* name */ + 1, /* firstlineno */ + empty_string /* lnotab */ + ); + + Py_DECREF (empty_string); + Py_DECREF (null_tuple); + + if (!code) + return NULL; + + globals = PyDict_New (); + if (!globals) + { + Py_DECREF (code); + return NULL; + } + + tstate = PyThreadState_GET (); + + frame = PyFrame_New (tstate, code, globals, NULL); + + Py_DECREF (globals); + Py_DECREF (code); + + if (!frame) + return NULL; + + tstate->frame = frame; + make_cleanup (py_restore_tstate, frame->f_back); + return (PyObject *) frame; +} + +/* Helper for apply_val_pretty_printer that formats children of the + printer, if any exist. */ +static void +print_children (PyObject *printer, const char *hint, + struct ui_file *stream, int recurse, + const struct value_print_options *options, + const struct language_defn *language) +{ + int is_map, is_array, done_flag, pretty; + unsigned int i; + PyObject *children, *iter, *frame; + struct cleanup *cleanups; + + if (! PyObject_HasAttr (printer, gdbpy_children_cst)) + return; + + /* If we are printing a map or an array, we want some special + formatting. */ + is_map = hint && ! strcmp (hint, "map"); + is_array = hint && ! strcmp (hint, "array"); + + children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst, + NULL); + if (! children) + { + gdbpy_print_stack (); + return; + } + + cleanups = make_cleanup_py_decref (children); + + iter = PyObject_GetIter (children); + if (!iter) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (iter); + + /* Use the prettyprint_arrays option if we are printing an array, + and the pretty option otherwise. */ + pretty = is_array ? options->prettyprint_arrays : options->pretty; + + /* Manufacture a dummy Python frame to work around Python 2.4 bug, + where it insists on having a non-NULL tstate->frame when + a generator is called. */ + frame = push_dummy_python_frame (); + if (!frame) + { + gdbpy_print_stack (); + goto done; + } + make_cleanup_py_decref (frame); + + done_flag = 0; + for (i = 0; i < options->print_max; ++i) + { + PyObject *py_v, *item = PyIter_Next (iter); + char *name; + struct cleanup *inner_cleanup; + + if (! item) + { + if (PyErr_Occurred ()) + gdbpy_print_stack (); + /* Set a flag so we can know whether we printed all the + available elements. */ + else + done_flag = 1; + break; + } + + if (! PyArg_ParseTuple (item, "sO", &name, &py_v)) + { + gdbpy_print_stack (); + Py_DECREF (item); + continue; + } + inner_cleanup = make_cleanup_py_decref (item); + + /* Print initial "{". For other elements, there are three + cases: + 1. Maps. Print a "," after each value element. + 2. Arrays. Always print a ",". + 3. Other. Always print a ",". */ + if (i == 0) + fputs_filtered (" = {", stream); + else if (! is_map || i % 2 == 0) + fputs_filtered (pretty ? "," : ", ", stream); + + /* In summary mode, we just want to print "= {...}" if there is + a value. */ + if (options->summary) + { + /* This increment tricks the post-loop logic to print what + we want. */ + ++i; + /* Likewise. */ + pretty = 0; + break; + } + + if (! is_map || i % 2 == 0) + { + if (pretty) + { + fputs_filtered ("\n", stream); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + wrap_here (n_spaces (2 + 2 *recurse)); + } + + if (is_map && i % 2 == 0) + fputs_filtered ("[", stream); + else if (is_array) + { + /* We print the index, not whatever the child method + returned as the name. */ + if (options->print_array_indexes) + fprintf_filtered (stream, "[%d] = ", i); + } + else if (! is_map) + { + fputs_filtered (name, stream); + fputs_filtered (" = ", stream); + } + + if (gdbpy_is_string (py_v)) + { + char *text = python_string_to_host_string (py_v); + if (! text) + gdbpy_print_stack (); + else + { + fputs_filtered (text, stream); + xfree (text); + } + } + else + { + struct value *value = convert_value_from_python (py_v); + + if (value == NULL) + { + gdbpy_print_stack (); + error (_("Error while executing Python code.")); + } + else + common_val_print (value, stream, recurse + 1, options, language); + } + + if (is_map && i % 2 == 0) + fputs_filtered ("] = ", stream); + + do_cleanups (inner_cleanup); + } + + if (i) + { + if (!done_flag) + { + if (pretty) + { + fputs_filtered ("\n", stream); + print_spaces_filtered (2 + 2 * recurse, stream); + } + fputs_filtered ("...", stream); + } + if (pretty) + { + fputs_filtered ("\n", stream); + print_spaces_filtered (2 * recurse, stream); + } + fputs_filtered ("}", stream); + } + + done: + do_cleanups (cleanups); +} + +int +apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, + int embedded_offset, CORE_ADDR address, + struct ui_file *stream, int recurse, + const struct value_print_options *options, + const struct language_defn *language) +{ + PyObject *printer = NULL; + PyObject *val_obj = NULL; + struct value *value; + char *hint = NULL; + struct cleanup *cleanups; + int result = 0; + PyGILState_STATE state; + + state = PyGILState_Ensure (); + cleanups = make_cleanup_py_restore_gil (&state); + + /* Instantiate the printer. */ + if (valaddr) + valaddr += embedded_offset; + value = value_from_contents_and_address (type, valaddr, address); + + val_obj = value_to_value_object (value); + if (! val_obj) + goto done; + + /* Find the constructor. */ + printer = find_pretty_printer (val_obj); + Py_DECREF (val_obj); + make_cleanup_py_decref (printer); + if (! printer || printer == Py_None) + goto done; + + /* If we are printing a map, we want some special formatting. */ + hint = gdbpy_get_display_hint (printer); + make_cleanup (free_current_contents, &hint); + + /* Print the section */ + print_string_repr (printer, hint, stream, recurse, options, language); + print_children (printer, hint, stream, recurse, options, language); + result = 1; + + + done: + if (PyErr_Occurred ()) + gdbpy_print_stack (); + do_cleanups (cleanups); + return result; +} + +/* Apply a pretty-printer for the varobj code. PRINTER_OBJ is the + print object. It must have a 'to_string' method (but this is + checked by varobj, not here) which takes no arguments and + returns a string. This function returns an xmalloc()d string if + the printer returns a string. The printer may return a replacement + value instead; in this case *REPLACEMENT is set to the replacement + value, and this function returns NULL. On error, *REPLACEMENT is + set to NULL and this function also returns NULL. */ +char * +apply_varobj_pretty_printer (PyObject *printer_obj, + struct value **replacement) +{ + char *result; + PyGILState_STATE state = PyGILState_Ensure (); + + *replacement = NULL; + result = pretty_print_one_value (printer_obj, replacement); + if (result == NULL); + gdbpy_print_stack (); + PyGILState_Release (state); + + return result; +} + +/* Find a pretty-printer object for the varobj module. Returns a new + reference to the object if successful; returns NULL if not. VALUE + is the value for which a printer tests to determine if it + can pretty-print the value. */ +PyObject * +gdbpy_get_varobj_pretty_printer (struct value *value) +{ + PyObject *val_obj; + PyObject *pretty_printer = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + value = value_copy (value); + } + GDB_PY_HANDLE_EXCEPTION (except); + + val_obj = value_to_value_object (value); + if (! val_obj) + return NULL; + + pretty_printer = find_pretty_printer (val_obj); + Py_DECREF (val_obj); + return pretty_printer; +} + +/* A Python function which wraps find_pretty_printer and instantiates + the resulting class. This accepts a Value argument and returns a + pretty printer instance, or None. This function is useful as an + argument to the MI command -var-set-visualizer. */ +static PyObject * +gdbpy_default_visualizer (PyObject *self, PyObject *args) +{ + PyObject *val_obj; + PyObject *cons, *printer = NULL; + struct value *value; + + if (! PyArg_ParseTuple (args, "O", &val_obj)) + return NULL; + value = value_object_to_value (val_obj); + if (! value) + { + PyErr_SetString (PyExc_TypeError, "argument must be a gdb.Value"); + return NULL; + } + + cons = find_pretty_printer (val_obj); + return cons; +} + #else /* HAVE_PYTHON */ /* Dummy implementation of the gdb "python" command. */ @@ -328,6 +1677,24 @@ eval_python_from_control_command (struct command_line *cmd) error (_("Python scripting is not supported in this copy of GDB.")); } +int +apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, + int embedded_offset, CORE_ADDR address, + struct ui_file *stream, int format, + int deref_ref, int recurse, + enum val_prettyprint pretty, + const struct language_defn *language) +{ + return 0; +} + +void +source_python_script (FILE *stream) +{ + fclose (stream); + error (_("Python scripting is not supported in this copy of GDB.")); +} + #endif /* HAVE_PYTHON */ @@ -355,9 +1722,6 @@ show_python (char *args, int from_tty) /* Initialize the Python code. */ -/* Provide a prototype to silence -Wmissing-prototypes. */ -extern initialize_file_ftype _initialize_python; - void _initialize_python (void) { @@ -400,6 +1764,15 @@ Enables or disables printing of Python stack traces."), &set_python_list, &show_python_list); + add_setshow_boolean_cmd ("auto-load", class_maintenance, + &gdbpy_auto_load, _("\ +Enable or disable auto-loading of Python code when an object is opened."), _("\ +Show whether Python code will be auto-loaded when an object is opened."), _("\ +Enables or disables auto-loading of Python code when an object is opened."), + NULL, NULL, + &set_python_list, + &show_python_list); + #ifdef HAVE_PYTHON Py_Initialize (); PyEval_InitThreads (); @@ -410,11 +1783,36 @@ Enables or disables printing of Python stack traces."), PyModule_AddStringConstant (gdb_module, "VERSION", (char*) version); PyModule_AddStringConstant (gdb_module, "HOST_CONFIG", (char*) host_name); PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name); +#ifdef PYTHONDIR + PyModule_AddStringConstant (gdb_module, "pythondir", PYTHONDIR); +#else + if (gdb_datadir) + PyModule_AddStringConstant (gdb_module, "datadir", gdb_datadir); +#endif gdbpy_initialize_values (); + gdbpy_initialize_breakpoints (); + gdbpy_initialize_frames (); + gdbpy_initialize_symtabs (); gdbpy_initialize_commands (); + gdbpy_initialize_symbols (); + gdbpy_initialize_blocks (); + gdbpy_initialize_functions (); + gdbpy_initialize_types (); + gdbpy_initialize_parameters (); + gdbpy_initialize_objfile (); + gdbpy_initialize_events (); + gdbpy_initialize_membuf (); PyRun_SimpleString ("import gdb"); + PyRun_SimpleString ("gdb.pretty_printers = []"); + + observer_attach_new_objfile (gdbpy_new_objfile); + + gdbpy_to_string_cst = PyString_FromString ("to_string"); + gdbpy_children_cst = PyString_FromString ("children"); + gdbpy_display_hint_cst = PyString_FromString ("display_hint"); + gdbpy_doc_cst = PyString_FromString ("__doc__"); gdbpy_doc_cst = PyString_FromString ("__doc__"); @@ -442,6 +1840,15 @@ class GdbOutputFile:\n\ \n\ sys.stderr = GdbOutputFile()\n\ sys.stdout = GdbOutputFile()\n\ +if hasattr (gdb, 'datadir'):\n\ + gdb.pythondir = gdb.datadir + '/python'\n\ +if hasattr (gdb, 'pythondir'):\n\ + sys.path.insert(0, gdb.pythondir)\n\ + gdb.__path__ = [gdb.pythondir + '/gdb']\n\ + from os.path import exists\n\ + ipy = gdb.pythondir + '/gdb/__init__.py'\n\ + if exists (ipy):\n\ + execfile (ipy)\n\ "); /* Release the GIL while gdb runs. */ @@ -461,9 +1868,79 @@ static PyMethodDef GdbMethods[] = "Get a value from history" }, { "execute", execute_gdb_command, METH_VARARGS, "Execute a gdb command" }, - { "get_parameter", get_parameter, METH_VARARGS, + { "cli", gdbpy_cli, METH_NOARGS, + "Enter the gdb CLI" }, + { "parameter", gdbpy_parameter, METH_VARARGS, "Return a gdb parameter's value" }, + { "breakpoints", gdbpy_breakpoints, METH_NOARGS, + "Return a tuple of all breakpoint objects" }, + + { "default_visualizer", gdbpy_default_visualizer, METH_VARARGS, + "Find the default visualizer for a Value." }, + + { "current_objfile", gdbpy_get_current_objfile, METH_NOARGS, + "Return the current Objfile being loaded, or None." }, + { "objfiles", gdbpy_objfiles, METH_NOARGS, + "Return a sequence of all loaded objfiles." }, + + { "frames", gdbpy_frames, METH_NOARGS, + "frames () -> (gdb.Frame, ...).\n\ +Return a tuple of all frame objects." }, + { "newest_frame", gdbpy_newest_frame, METH_NOARGS, + "newest_frame () -> gdb.Frame.\n\ +Return the newest frame object." }, + { "selected_frame", gdbpy_selected_frame, METH_NOARGS, + "selected_frame () -> gdb.Frame.\n\ +Return the selected frame object." }, + { "frame_stop_reason_string", gdbpy_frame_stop_reason_string, METH_VARARGS, + "stop_reason_string (Integer) -> String.\n\ +Return a string explaining unwind stop reason." }, + + { "lookup_symbol", (PyCFunction) gdbpy_lookup_symbol, + METH_VARARGS | METH_KEYWORDS, + "lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this)\n\ +Return a tuple with the symbol corresponding to the given name (or None) and\n\ +a boolean indicating if name is a field of the current implied argument\n\ +`this' (when the current language is object-oriented)." }, + { "solib_address", gdbpy_solib_address, METH_VARARGS, + "solib_address (Long) -> String.\n\ +Return the name of the shared library holding a given address, or None." }, + + { "find_pc_function", gdbpy_find_pc_function, METH_VARARGS, + "Return the function containing the given pc value, or None." }, + + { "block_for_pc", gdbpy_block_for_pc, METH_VARARGS, + "Return the block containing the given pc value, or None." }, + + { "decode_line", gdbpy_decode_line, METH_VARARGS, + "Decode a string argument the way that 'break' or 'edit' does.\n\ +Return a tuple holding the file name (or None) and line number (or None).\n\ +Note: may later change to return an object." }, + + { "threads", gdbpy_threads, METH_NOARGS, + "Return a tuple holding all the valid thread IDs." }, + { "current_thread", gdbpy_current_thread, METH_NOARGS, + "Return the thread ID of the current thread." }, + { "switch_to_thread", gdbpy_switch_to_thread, METH_VARARGS, + "Switch to a thread, given the thread ID." }, + + { "parse_and_eval", gdbpy_parse_and_eval, METH_VARARGS, + "Parse a string as an expression, evaluate it, and return the result." }, + + { "post_event", gdbpy_post_event, METH_VARARGS, + "Post an event into gdb's event loop." }, + + { "read_memory", gdbpy_read_memory, METH_VARARGS, + "read_memory (address, length) -> buffer\n\ +Return a buffer object for reading from the inferior's memory." }, + { "write_memory", gdbpy_write_memory, METH_VARARGS, + "write_memory (address, buffer [, length])\n\ +Write the given buffer object to the inferior's memory." }, + { "search_memory", (PyCFunction) gdbpy_search_memory, METH_VARARGS | METH_KEYWORDS, + "search_memory (address, length, pattern [, size] [, max_count]) -> list\n\ +Return a list with the addresses where matches were found." }, + { "write", gdbpy_write, METH_VARARGS, "Write a string using gdb's filtered stream." }, { "flush", gdbpy_flush, METH_NOARGS, diff --git a/gdb/python/python.h b/gdb/python/python.h index e63c447..767af86 100644 --- a/gdb/python/python.h +++ b/gdb/python/python.h @@ -26,4 +26,14 @@ extern struct value *values_in_python; void eval_python_from_control_command (struct command_line *); +void source_python_script (FILE *stream, char *file); + +void run_python_script (int argc, char **argv); + +int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr, + int embedded_offset, CORE_ADDR address, + struct ui_file *stream, int recurse, + const struct value_print_options *options, + const struct language_defn *language); + #endif /* GDB_PYTHON_H */ diff --git a/gdb/scm-lang.c b/gdb/scm-lang.c index 345befd..e2568c8 100644 --- a/gdb/scm-lang.c +++ b/gdb/scm-lang.c @@ -43,14 +43,14 @@ static int in_eval_c (void); struct type *builtin_type_scm; void -scm_printchar (int c, struct ui_file *stream) +scm_printchar (int c, struct type *type, struct ui_file *stream) { fprintf_filtered (stream, "#\\%c", c); } static void -scm_printstr (struct ui_file *stream, const gdb_byte *string, - unsigned int length, int width, int force_ellipses, +scm_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string, + unsigned int length, int force_ellipses, const struct value_print_options *options) { fprintf_filtered (stream, "\"%s\"", string); diff --git a/gdb/scm-lang.h b/gdb/scm-lang.h index 6bf88f5..1798b2f 100644 --- a/gdb/scm-lang.h +++ b/gdb/scm-lang.h @@ -59,7 +59,7 @@ extern void scm_scmval_print (LONGEST, struct ui_file *, int, extern int is_scmvalue_type (struct type *); -extern void scm_printchar (int, struct ui_file *); +extern void scm_printchar (int, struct type *, struct ui_file *); extern struct value *scm_evaluate_string (char *, int); diff --git a/gdb/scm-valprint.c b/gdb/scm-valprint.c index f0a7642..a32add5 100644 --- a/gdb/scm-valprint.c +++ b/gdb/scm-valprint.c @@ -187,7 +187,8 @@ taloop: if (SCM_ICHRP (svalue)) { svalue = SCM_ICHR (svalue); - scm_printchar (svalue, stream); + scm_printchar (svalue, builtin_type (current_gdbarch)->builtin_char, + stream); break; } else if (SCM_IFLAGP (svalue) diff --git a/gdb/stabsread.c b/gdb/stabsread.c index 2d7eb15..7423b32 100644 --- a/gdb/stabsread.c +++ b/gdb/stabsread.c @@ -322,7 +322,7 @@ dbx_alloc_type (int typenums[2], struct objfile *objfile) if (typenums[0] == -1) { - return (alloc_type (objfile)); + return (alloc_type (objfile, NULL)); } type_addr = dbx_lookup_type (typenums); @@ -332,7 +332,7 @@ dbx_alloc_type (int typenums[2], struct objfile *objfile) We will fill it in later if we find out how. */ if (*type_addr == 0) { - *type_addr = alloc_type (objfile); + *type_addr = alloc_type (objfile, NULL); } return (*type_addr); @@ -589,6 +589,7 @@ define_symbol (CORE_ADDR valu, char *string, int desc, int type, int deftype; int synonym = 0; int i; + char *new_name = NULL; /* We would like to eliminate nameless symbols, but keep their types. E.g. stab entry ":t10=*2" should produce a type 10, which is a pointer @@ -683,9 +684,37 @@ define_symbol (CORE_ADDR valu, char *string, int desc, int type, { normal: SYMBOL_LANGUAGE (sym) = current_subfile->language; - SYMBOL_SET_NAMES (sym, string, p - string, objfile); + if (current_subfile->language == language_cplus) + { + char *name = alloca (p - string + 1); + memcpy (name, string, p - string); + name[p - string] = '\0'; + new_name = cp_canonicalize_string (name); + } + + if (new_name != NULL) + { + SYMBOL_SET_NAMES (sym, new_name, strlen (new_name), objfile); + xfree (new_name); + } + else + SYMBOL_SET_NAMES (sym, string, p - string, objfile); + if (SYMBOL_LANGUAGE (sym) == language_cplus) - cp_scan_for_anonymous_namespaces (sym); + { + char *name = alloca (p - string + 1); + memcpy (name, string, p - string); + name[p - string] = '\0'; + new_name = cp_canonicalize_string (name); + cp_scan_for_anonymous_namespaces (sym); + } + if (new_name != NULL) + { + SYMBOL_SET_NAMES (sym, new_name, strlen (new_name), objfile); + xfree (new_name); + } + else + SYMBOL_SET_NAMES (sym, string, p - string, objfile); } p++; @@ -1519,18 +1548,35 @@ again: if (*p != ':') return error_type (pp, objfile); } - to = type_name = - (char *) obstack_alloc (&objfile->objfile_obstack, p - *pp + 1); - - /* Copy the name. */ - from = *pp + 1; - while (from < p) - *to++ = *from++; - *to = '\0'; + type_name = NULL; + if (current_subfile->language == language_cplus) + { + char *new_name, *name = alloca (p - *pp + 1); + memcpy (name, *pp, p - *pp); + name[p - *pp] = '\0'; + new_name = cp_canonicalize_string (name); + if (new_name != NULL) + { + type_name = obsavestring (new_name, strlen (new_name), + &objfile->objfile_obstack); + xfree (new_name); + } + } + if (type_name == NULL) + { + to = type_name = + (char *) obstack_alloc (&objfile->objfile_obstack, p - *pp + 1); + + /* Copy the name. */ + from = *pp + 1; + while (from < p) + *to++ = *from++; + *to = '\0'; + } /* Set the pointer ahead of the name which we just read, and the colon. */ - *pp = from + 1; + *pp = p + 1; } /* If this type has already been declared, then reuse the same diff --git a/gdb/stack.c b/gdb/stack.c index 3bcf758..fa7fc61 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -380,6 +380,7 @@ print_frame_args (struct symbol *func, struct frame_info *frame, get_raw_print_options (&opts); opts.deref_ref = 0; + opts.summary = 1; common_val_print (val, stb->stream, 2, &opts, language); ui_out_field_stream (uiout, "value", stb); @@ -579,20 +580,16 @@ print_frame_info (struct frame_info *frame, int print_level, gdb_flush (gdb_stdout); } -static void -print_frame (struct frame_info *frame, int print_level, - enum print_what print_what, int print_args, - struct symtab_and_line sal) +/* Attempt to obtain the FUNNAME and FUNLANG of the function corresponding + to FRAME. */ +void +find_frame_funname (struct frame_info *frame, char **funname, + enum language *funlang) { struct symbol *func; - char *funname = NULL; - enum language funlang = language_unknown; - struct ui_stream *stb; - struct cleanup *old_chain, *list_chain; - struct value_print_options opts; - stb = ui_out_stream_new (uiout); - old_chain = make_cleanup_ui_out_stream_delete (stb); + *funname = NULL; + *funlang = language_unknown; func = find_pc_function (get_frame_address_in_block (frame)); if (func) @@ -625,24 +622,24 @@ print_frame (struct frame_info *frame, int print_level, /* We also don't know anything about the function besides its address and name. */ func = 0; - funname = SYMBOL_PRINT_NAME (msymbol); - funlang = SYMBOL_LANGUAGE (msymbol); + *funname = SYMBOL_PRINT_NAME (msymbol); + *funlang = SYMBOL_LANGUAGE (msymbol); } else { - funname = SYMBOL_PRINT_NAME (func); - funlang = SYMBOL_LANGUAGE (func); - if (funlang == language_cplus) + *funname = SYMBOL_PRINT_NAME (func); + *funlang = SYMBOL_LANGUAGE (func); + if (*funlang == language_cplus) { /* It seems appropriate to use SYMBOL_PRINT_NAME() here, to display the demangled name that we already have stored in the symbol table, but we stored a version with DMGL_PARAMS turned on, and here we don't want to display parameters. So remove the parameters. */ - char *func_only = cp_remove_params (funname); + char *func_only = cp_remove_params (*funname); if (func_only) { - funname = func_only; + *funname = func_only; make_cleanup (xfree, func_only); } } @@ -655,10 +652,27 @@ print_frame (struct frame_info *frame, int print_level, if (msymbol != NULL) { - funname = SYMBOL_PRINT_NAME (msymbol); - funlang = SYMBOL_LANGUAGE (msymbol); + *funname = SYMBOL_PRINT_NAME (msymbol); + *funlang = SYMBOL_LANGUAGE (msymbol); } } +} + +static void +print_frame (struct frame_info *frame, int print_level, + enum print_what print_what, int print_args, + struct symtab_and_line sal) +{ + char *funname = NULL; + enum language funlang = language_unknown; + struct ui_stream *stb; + struct cleanup *old_chain, *list_chain; + struct value_print_options opts; + + stb = ui_out_stream_new (uiout); + old_chain = make_cleanup_ui_out_stream_delete (stb); + + find_frame_funname (frame, &funname, &funlang); annotate_frame_begin (print_level ? frame_relative_level (frame) : 0, get_frame_pc (frame)); @@ -694,7 +708,7 @@ print_frame (struct frame_info *frame, int print_level, struct print_args_args args; struct cleanup *args_list_chain; args.frame = frame; - args.func = func; + args.func = find_pc_function (get_frame_address_in_block (frame)); args.stream = gdb_stdout; args_list_chain = make_cleanup_ui_out_list_begin_end (uiout, "args"); catch_errors (print_args_stub, &args, "", RETURN_MASK_ERROR); @@ -1208,24 +1222,24 @@ backtrace_command_1 (char *count_exp, int show_locals, int from_tty) else count = -1; - if (info_verbose) - { - struct partial_symtab *ps; - - /* Read in symbols for all of the frames. Need to do this in a - separate pass so that "Reading in symbols for xxx" messages - don't screw up the appearance of the backtrace. Also if - people have strong opinions against reading symbols for - backtrace this may have to be an option. */ - i = count; - for (fi = trailing; fi != NULL && i--; fi = get_prev_frame (fi)) - { - QUIT; - ps = find_pc_psymtab (get_frame_address_in_block (fi)); - if (ps) - PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in. */ - } - } + { + struct partial_symtab *ps; + + /* Read in symbols for all of the frames. Need to do this + unconditionally to ensure that psymbols are read. Also need to + do this in a separate pass so that "Reading in symbols for xxx" + messages don't screw up the appearance of the backtrace. Also + if people have strong opinions against reading symbols for + backtrace this may have to be an option. */ + i = count; + for (fi = trailing; fi != NULL && i--; fi = get_prev_frame (fi)) + { + QUIT; + ps = find_pc_psymtab (get_frame_address_in_block (fi)); + if (info_verbose && ps) + PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in. */ + } + } for (i = 0, fi = trailing; fi && count--; i++, fi = get_prev_frame (fi)) { @@ -1373,6 +1387,8 @@ print_block_frame_locals (struct block *b, struct frame_info *frame, case LOC_COMPUTED: if (SYMBOL_IS_ARGUMENT (sym)) break; + if (SYMBOL_DOMAIN (sym) == COMMON_BLOCK_DOMAIN) + break; values_printed = 1; print_variable_and_value (NULL, sym, frame, stream, 4 * num_tabs); break; @@ -1777,7 +1793,75 @@ down_command (char *count_exp, int from_tty) down_silently_base (count_exp); print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); } - + +/* Verify whether if RETURN_VALUE width gets extended to EXT_TYPE it will still + be the same value after reading it back using the RETURN_VALUE type. */ + +static int +return_extended_value_cast (struct value *return_value, struct type *ext_type) +{ + struct regcache *current_regcache = get_current_regcache (); + struct gdbarch *gdbarch = get_regcache_arch (current_regcache); + struct type *return_type = value_type (return_value); + struct value *ext_value, *compare_value; + + if (gdbarch_return_value (gdbarch, NULL, ext_type, NULL, NULL, NULL) + != RETURN_VALUE_REGISTER_CONVENTION) + return 0; + + ext_value = value_cast (ext_type, return_value); + gdbarch_return_value (gdbarch, NULL, ext_type, + current_regcache, NULL /*read*/, + value_contents (ext_value) /*write*/); + + compare_value = allocate_value (return_type); + gdbarch_return_value (gdbarch, NULL, return_type, current_regcache, + value_contents_raw (compare_value) /*read*/, + NULL /*write*/); + + return value_equal (return_value, compare_value); +} + +/* Set RETURN_VALUE extended to the largest type width which will still be the + same value after reading it back using the RETURN_VALUE type. */ + +static void +return_extended_value (struct value *return_value) +{ + struct type *return_type = value_type (return_value); + struct regcache *current_regcache = get_current_regcache (); + struct gdbarch *gdbarch = get_regcache_arch (current_regcache); + const struct builtin_type *builtins = builtin_type (gdbarch); + struct type **extp, *ext_tab[] = + { + builtins->builtin_long_long, + builtins->builtin_long, + return_type + }; + unsigned width_tried = 0; + + for (extp = ext_tab; extp < ext_tab + ARRAY_SIZE (ext_tab); extp++) + { + struct type *ext_type = *extp; + + /* Do not retry extension to the integer of an already tried width. */ + if (ext_type != return_type && width_tried == TYPE_LENGTH (ext_type)) + continue; + + /* Do not extend to non-original smaller (or the same size) type. */ + if (ext_type != return_type + && TYPE_LENGTH (ext_type) <= TYPE_LENGTH (return_type)) + continue; + + gdb_assert (TYPE_LENGTH (return_type) <= TYPE_LENGTH (ext_type)); + width_tried = TYPE_LENGTH (ext_type); + if (return_extended_value_cast (return_value, ext_type)) + break; + } + + /* Ensure at least the attempt with original RETURN_TYPE was successful. */ + gdb_assert (extp < ext_tab + ARRAY_SIZE (ext_tab)); +} void return_command (char *retval_exp, int from_tty) @@ -1806,6 +1890,8 @@ return_command (char *retval_exp, int from_tty) the cast fail, this call throws an error. */ if (thisfun != NULL) return_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (thisfun)); + else + return_type = value_type (return_value); if (return_type == NULL) return_type = builtin_type (get_frame_arch (thisframe))->builtin_int; CHECK_TYPEDEF (return_type); @@ -1862,9 +1948,13 @@ If you continue, the return value that you specified will be ignored.\n"; gdb_assert (gdbarch_return_value (gdbarch, func_type, return_type, NULL, NULL, NULL) == RETURN_VALUE_REGISTER_CONVENTION); - gdbarch_return_value (gdbarch, func_type, return_type, - get_current_regcache (), NULL /*read*/, - value_contents (return_value) /*write*/); + + if (thisfun != NULL) + gdbarch_return_value (gdbarch, func_type, return_type, + get_current_regcache (), NULL /*read*/, + value_contents (return_value) /*write*/); + else + return_extended_value (return_value); } /* If we are at the end of a call dummy now, pop the dummy frame diff --git a/gdb/stack.h b/gdb/stack.h index 973a57f..56b1d91 100644 --- a/gdb/stack.h +++ b/gdb/stack.h @@ -22,4 +22,9 @@ void select_frame_command (char *level_exp, int from_tty); +/* Attempt to obtain the FUNNAME and FUNLANG of the function corresponding + to FRAME. */ +void find_frame_funname (struct frame_info *frame, char **funname, + enum language *funlang); + #endif /* #ifndef STACK_H */ diff --git a/gdb/symfile.c b/gdb/symfile.c index 63b5c1d..b047e94 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -929,6 +929,17 @@ new_symfile_objfile (struct objfile *objfile, int mainline, int verbo) clear_complaints (&symfile_complaints, 0, verbo); } +/* A helper function which returns true if OBJFILE has any debug + symbols, and false otherwise. */ +static int +has_any_debug_symbols (struct objfile *objfile) +{ + return (objfile->psymtabs || objfile->quick_addrmap + || (objfile->separate_debug_objfile + && (objfile->separate_debug_objfile->psymtabs + || objfile->separate_debug_objfile->quick_addrmap))); +} + /* Process a symbol file, as either the main file or as a dynamically loaded file. @@ -965,13 +976,15 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty, /* Give user a chance to burp if we'd be interactively wiping out any existing symbols. */ - if ((have_full_symbols () || have_partial_symbols ()) - && mainline + if (mainline && from_tty + && (have_full_symbols () || have_partial_symbols ()) && !query (_("Load new symbol table from \"%s\"? "), name)) error (_("Not confirmed.")); objfile = allocate_objfile (abfd, flags); + if (mainline) + objfile->flags |= OBJF_MAIN; discard_cleanups (my_cleanups); if (addrs) @@ -1007,6 +1020,8 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty, if ((flags & OBJF_READNOW) || readnow_symbol_files) { + require_partial_symbols (objfile); + if ((from_tty || info_verbose) && print_symbol_loading) { printf_unfiltered (_("expanding to full symbols...")); @@ -1025,7 +1040,7 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty, /* If the file has its own symbol tables it has no separate debug info. `.dynsym'/`.symtab' go to MSYMBOLS, `.debug_info' goes to SYMTABS/PSYMTABS. `.gnu_debuglink' may no longer be present with `.note.gnu.build-id'. */ - if (objfile->psymtabs == NULL) + if (!has_any_debug_symbols (objfile)) debugfile = find_separate_debug_file (objfile); if (debugfile) { @@ -1049,8 +1064,10 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty, xfree (debugfile); } - if (!have_partial_symbols () && !have_full_symbols () - && print_symbol_loading) + /* has_any_debug_symbols is not fully compatible with the former calls which + would just be needlessly expensive here. */ + if ((from_tty || info_verbose) && print_symbol_loading + && !has_any_debug_symbols (objfile) && mainline) { wrap_here (""); printf_unfiltered (_("(no debugging symbols found)")); @@ -2423,13 +2440,15 @@ reread_symbols (void) zero is OK since dbxread.c also does what it needs to do if objfile->global_psymbols.size is 0. */ (*objfile->sf->sym_read) (objfile, 0); - if (!have_partial_symbols () && !have_full_symbols ()) + if (!has_any_debug_symbols (objfile)) { wrap_here (""); printf_unfiltered (_("(no debugging symbols found)\n")); wrap_here (""); } + objfile->flags &= ~OBJF_SYMTABS_READ; + /* We're done reading the symbol file; finish off complaints. */ clear_complaints (&symfile_complaints, 0, 1); @@ -2726,7 +2745,7 @@ allocate_symtab (char *filename, struct objfile *objfile) } struct partial_symtab * -allocate_psymtab (char *filename, struct objfile *objfile) +allocate_psymtab (const char *filename, struct objfile *objfile) { struct partial_symtab *psymtab; @@ -3040,7 +3059,8 @@ again2: struct partial_symtab * start_psymtab_common (struct objfile *objfile, - struct section_offsets *section_offsets, char *filename, + struct section_offsets *section_offsets, + const char *filename, CORE_ADDR textlow, struct partial_symbol **global_syms, struct partial_symbol **static_syms) { diff --git a/gdb/symfile.h b/gdb/symfile.h index 88f8326..50671c1 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -140,6 +140,12 @@ struct sym_fns void (*sym_read) (struct objfile *, int); + /* Read the partial symbols for an objfile. This may be NULL, in + which case gdb assumes that sym_read already read the partial + symbols. */ + + void (*sym_read_psymbols) (struct objfile *); + /* Called when we are finished with an objfile. Should do all cleanup that is specific to the object file format for the particular objfile. */ @@ -250,7 +256,7 @@ extern void free_section_addr_info (struct section_addr_info *); extern struct partial_symtab *start_psymtab_common (struct objfile *, struct section_offsets *, - char *, CORE_ADDR, + const char *, CORE_ADDR, struct partial_symbol **, struct partial_symbol **); @@ -300,7 +306,7 @@ extern int auto_solib_limit; extern void set_initial_language (void); -extern struct partial_symtab *allocate_psymtab (char *, struct objfile *); +extern struct partial_symtab *allocate_psymtab (const char *, struct objfile *); extern void discard_psymtab (struct partial_symtab *); @@ -369,7 +375,7 @@ void free_symfile_segment_data (struct symfile_segment_data *data); /* From dwarf2read.c */ extern int dwarf2_has_info (struct objfile *); - +extern void dwarf2_create_quick_addrmap (struct objfile *); extern void dwarf2_build_psymtabs (struct objfile *, int); extern void dwarf2_build_frame_info (struct objfile *); diff --git a/gdb/symtab.c b/gdb/symtab.c index d2ba1f3..593cded 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -42,6 +42,7 @@ #include "ada-lang.h" #include "p-lang.h" #include "addrmap.h" +#include "cp-support.h" #include "hashtab.h" @@ -55,6 +56,7 @@ #include "gdb_stat.h" #include #include "cp-abi.h" +#include "cp-support.h" #include "observer.h" #include "gdb_assert.h" #include "solist.h" @@ -273,7 +275,7 @@ lookup_partial_symtab (const char *name) make_cleanup (xfree, real_path); } - ALL_PSYMTABS (objfile, pst) + ALL_PSYMTABS_REQUIRED (objfile, pst) { if (FILENAME_CMP (name, pst->filename) == 0) { @@ -870,7 +872,13 @@ find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section) than the later used TEXTLOW/TEXTHIGH one. */ ALL_OBJFILES (objfile) - if (objfile->psymtabs_addrmap != NULL) + { + if (objfile->quick_addrmap) + { + if (!addrmap_find (objfile->quick_addrmap, pc)) + continue; + } + if (require_partial_symbols (objfile)->psymtabs_addrmap != NULL) { struct partial_symtab *pst; @@ -903,6 +911,7 @@ find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section) return pst; } } + } /* Existing PSYMTABS_ADDRMAP mapping is present even for PARTIAL_SYMTABs which still have no corresponding full SYMTABs read. But it is not @@ -1170,6 +1179,22 @@ fixup_psymbol_section (struct partial_symbol *psym, struct objfile *objfile) return psym; } +/* Ensure that the partial symbols for OBJFILE have been loaded. This + function always returns its argument, as a convenience. */ + +struct objfile * +require_partial_symbols (struct objfile *objfile) +{ + if ((objfile->flags & OBJF_SYMTABS_READ) == 0) + { + objfile->flags |= OBJF_SYMTABS_READ; + + if (objfile->sf->sym_read_psymbols) + (*objfile->sf->sym_read_psymbols) (objfile); + } + return objfile; +} + /* Find the definition for a specified symbol name NAME in domain DOMAIN, visible from lexical block BLOCK. Returns the struct symbol pointer, or zero if no symbol is found. @@ -1200,6 +1225,11 @@ lookup_symbol_in_language (const char *name, const struct block *block, int needtofreename = 0; struct symbol *returnval; + if(strncmp(name, "::", 2) == 0){/* this must be a global name */ + name = name+2; + block = NULL; + } + modified_name = name; /* If we are using C++ or Java, demangle the name before doing a lookup, so @@ -1213,6 +1243,17 @@ lookup_symbol_in_language (const char *name, const struct block *block, modified_name = demangled_name; needtofreename = 1; } + else + { + /* If we were given a non-mangled name, canonicalize it + according to the language (so far only for C++). */ + demangled_name = cp_canonicalize_string (name); + if (demangled_name) + { + modified_name = demangled_name; + needtofreename = 1; + } + } } else if (lang == language_java) { @@ -1361,22 +1402,23 @@ lookup_symbol_aux_local (const char *name, const char *linkage_name, const domain_enum domain) { struct symbol *sym; - const struct block *static_block = block_static_block (block); + const struct block *global_block = block_global_block (block); /* Check if either no block is specified or it's a global block. */ - if (static_block == NULL) + if (global_block == NULL) return NULL; - while (block != static_block) + while (block != global_block) { sym = lookup_symbol_aux_block (name, linkage_name, block, domain); if (sym != NULL) return sym; + block = BLOCK_SUPERBLOCK (block); } - /* We've reached the static block without finding a result. */ + /* We've reached the global block without finding a result. */ return NULL; } @@ -1450,6 +1492,7 @@ lookup_global_symbol_from_objfile (const struct objfile *objfile, } /* Now go through psymtabs. */ + require_partial_symbols ((struct objfile *) objfile); ALL_OBJFILE_PSYMTABS (objfile, ps) { if (!ps->readin @@ -1520,7 +1563,7 @@ lookup_symbol_aux_psymtabs (int block_index, const char *name, struct symtab *s; const int psymtab_index = (block_index == GLOBAL_BLOCK ? 1 : 0); - ALL_PSYMTABS (objfile, ps) + ALL_PSYMTABS_REQUIRED (objfile, ps) { if (!ps->readin && lookup_partial_symbol (ps, name, linkage_name, @@ -1805,7 +1848,11 @@ basic_lookup_transparent_type (const char *name) } } - ALL_PSYMTABS (objfile, ps) + /* FIXME: .debug_pubnames should be read in. + + One may also try to the first pass without the require_partial_symbols + call but that would behave nondeterministically. */ + ALL_PSYMTABS_REQUIRED (objfile, ps) { if (!ps->readin && lookup_partial_symbol (ps, name, NULL, 1, STRUCT_DOMAIN)) @@ -1853,7 +1900,12 @@ basic_lookup_transparent_type (const char *name) } } - ALL_PSYMTABS (objfile, ps) + /* FIXME: Something like .debug_pubnames containing also static symbols + should be read in. Compiler needs to be taught to generate it first. + + One may also try to the first pass without the require_partial_symbols + call but that would behave nondeterministically. */ + ALL_PSYMTABS_REQUIRED (objfile, ps) { if (!ps->readin && lookup_partial_symbol (ps, name, NULL, 0, STRUCT_DOMAIN)) { @@ -1894,7 +1946,21 @@ find_main_psymtab (void) struct partial_symtab *pst; struct objfile *objfile; - ALL_PSYMTABS (objfile, pst) + ALL_OBJFILES (objfile) + { + if ((objfile->flags & OBJF_MAIN) == 0) + continue; + require_partial_symbols (objfile); + ALL_OBJFILE_PSYMTABS (objfile, pst) + { + if (lookup_partial_symbol (pst, main_name (), NULL, 1, VAR_DOMAIN)) + { + return pst; + } + } + } + + ALL_PSYMTABS_REQUIRED (objfile, pst) { if (lookup_partial_symbol (pst, main_name (), NULL, 1, VAR_DOMAIN)) { @@ -3085,7 +3151,7 @@ search_symbols (char *regexp, domain_enum kind, int nfiles, char *files[], matching the regexp. That way we don't have to reproduce all of the machinery below. */ - ALL_PSYMTABS (objfile, ps) + ALL_PSYMTABS_REQUIRED (objfile, ps) { struct partial_symbol **bound, **gbound, **sbound; int keep_going = 1; diff --git a/gdb/symtab.h b/gdb/symtab.h index 8b086f3..06bf7e8 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -171,9 +171,6 @@ extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, struct obj_section *); #define SYMBOL_SECTION(symbol) (symbol)->ginfo.section #define SYMBOL_OBJ_SECTION(symbol) (symbol)->ginfo.obj_section -#define SYMBOL_CPLUS_DEMANGLED_NAME(symbol) \ - (symbol)->ginfo.language_specific.cplus_specific.demangled_name - /* Initializes the language dependent portion of a symbol depending upon the language for the symbol. */ #define SYMBOL_INIT_LANGUAGE_SPECIFIC(symbol,language) \ @@ -394,7 +391,10 @@ typedef enum domain_enum_tag FUNCTIONS_DOMAIN, /* All defined types */ - TYPES_DOMAIN + TYPES_DOMAIN, + + /* Fortran common blocks. Their naming must be separate from VAR_DOMAIN. */ + COMMON_BLOCK_DOMAIN } domain_enum; @@ -1027,6 +1027,8 @@ extern void clear_pc_function_cache (void); /* from symtab.c: */ +struct objfile *require_partial_symbols (struct objfile *); + /* lookup partial symbol table by filename */ extern struct partial_symtab *lookup_partial_symtab (const char *); diff --git a/gdb/syscalls/gdb-syscalls.dtd b/gdb/syscalls/gdb-syscalls.dtd new file mode 100644 index 0000000..0d40ab4 --- /dev/null +++ b/gdb/syscalls/gdb-syscalls.dtd @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/gdb/syscalls/i386-linux.xml b/gdb/syscalls/i386-linux.xml new file mode 100644 index 0000000..6f2beee --- /dev/null +++ b/gdb/syscalls/i386-linux.xml @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/syscalls/ppc-linux.xml b/gdb/syscalls/ppc-linux.xml new file mode 100644 index 0000000..f09fabd --- /dev/null +++ b/gdb/syscalls/ppc-linux.xml @@ -0,0 +1,304 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/syscalls/ppc64-linux.xml b/gdb/syscalls/ppc64-linux.xml new file mode 100644 index 0000000..7ee929c --- /dev/null +++ b/gdb/syscalls/ppc64-linux.xml @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/target.c b/gdb/target.c index b89d551..831070c 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -443,6 +443,8 @@ update_current_target (void) /* Do not inherit to_follow_fork. */ INHERIT (to_insert_exec_catchpoint, t); INHERIT (to_remove_exec_catchpoint, t); + INHERIT (to_passed_by_entrypoint, t); + INHERIT (to_set_syscall_catchpoint, t); INHERIT (to_has_exited, t); /* Do not inherit to_mourn_inferiour. */ INHERIT (to_can_run, t); @@ -586,9 +588,15 @@ update_current_target (void) de_fault (to_insert_exec_catchpoint, (void (*) (int)) tcomplain); + de_fault (to_passed_by_entrypoint, + (int (*) (void)) + tcomplain); de_fault (to_remove_exec_catchpoint, (int (*) (int)) tcomplain); + de_fault (to_set_syscall_catchpoint, + (int (*) (int, int, int, int, int *)) + tcomplain); de_fault (to_has_exited, (int (*) (int, int, int *)) return_zero); @@ -2677,9 +2685,9 @@ target_waitstatus_to_string (const struct target_waitstatus *ws) case TARGET_WAITKIND_EXECD: return xstrprintf ("%sexecd", kind_str); case TARGET_WAITKIND_SYSCALL_ENTRY: - return xstrprintf ("%ssyscall-entry", kind_str); + return xstrprintf ("%sentered syscall", kind_str); case TARGET_WAITKIND_SYSCALL_RETURN: - return xstrprintf ("%ssyscall-return", kind_str); + return xstrprintf ("%sexited syscall", kind_str); case TARGET_WAITKIND_SPURIOUS: return xstrprintf ("%sspurious", kind_str); case TARGET_WAITKIND_IGNORE: diff --git a/gdb/target.h b/gdb/target.h index 7f4cd8f..8dcc3d6 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -140,18 +140,34 @@ struct target_waitstatus { enum target_waitkind kind; - /* Forked child pid, execd pathname, exit status or signal number. */ + /* Forked child pid, execd pathname, exit status, signal number or + syscall name. */ union { int integer; enum target_signal sig; ptid_t related_pid; char *execd_pathname; - int syscall_id; + int syscall_number; } value; }; +/* The structure below stores information about a system call. + It is basically used in the "catch syscall" command, and in + every function that gives information about a system call. + + It's also good to mention that its fields represent everything + that we currently know about a syscall in GDB. */ +struct syscall + { + /* The syscall number. */ + int number; + + /* The syscall name. */ + const char *name; + }; + /* Return a pretty printed form of target_waitstatus. Space for the result is malloc'd, caller must free. */ extern char *target_waitstatus_to_string (const struct target_waitstatus *); @@ -392,6 +408,8 @@ struct target_ops int (*to_follow_fork) (struct target_ops *, int); void (*to_insert_exec_catchpoint) (int); int (*to_remove_exec_catchpoint) (int); + int (*to_passed_by_entrypoint) (void); + int (*to_set_syscall_catchpoint) (int, int, int, int, int *); int (*to_has_exited) (int, int, int *); void (*to_mourn_inferior) (struct target_ops *); int (*to_can_run) (void); @@ -723,6 +741,8 @@ extern int inferior_has_vforked (ptid_t pid, ptid_t *child_pid); extern int inferior_has_execd (ptid_t pid, char **execd_pathname); +extern int inferior_has_called_syscall (ptid_t pid, int *syscall_number); + /* From exec.c */ extern void print_section_info (struct target_ops *, bfd *); @@ -881,6 +901,21 @@ int target_follow_fork (int follow_child); #define target_remove_exec_catchpoint(pid) \ (*current_target.to_remove_exec_catchpoint) (pid) +/* Has the inferior already passed through its entrypoint? */ +#define target_passed_by_entrypoint() \ + (*current_target.to_passed_by_entrypoint) () + +/* Syscall catch. NEEDED is nonzero if any syscall catch (of any + kind) is requested. ANY_COUNT is nonzero if a generic + (filter-less) syscall catch is being requested. TABLE is an array + of ints, indexed by syscall number. An element in this array is + nonzero if that syscall should be caught. TABLE_SIZE is the number + of elements in TABLE. */ + +#define target_set_syscall_catchpoint(pid, needed, any_count, table_size, table) \ + (*current_target.to_set_syscall_catchpoint) (pid, needed, any_count, \ + table_size, table) + /* Returns TRUE if PID has exited. And, also sets EXIT_STATUS to the exit code of PID, if any. */ @@ -1146,6 +1181,20 @@ extern int target_search_memory (CORE_ADDR start_addr, ULONGEST pattern_len, CORE_ADDR *found_addrp); +/* Utility functions which can be used by search_memory implementations. */ + +void allocate_pattern_buffer (char **pattern_bufp, char **pattern_buf_end, + ULONGEST *pattern_buf_size); + +void increase_pattern_buffer (char **pattern_bufp, char **pattern_buf_end, + ULONGEST *pattern_buf_size, int val_bytes); + +int search_memory (CORE_ADDR *start_addr, ULONGEST *search_space_len, + const char *pattern_buf, ULONGEST pattern_len, + CORE_ADDR *found_addr); + +void put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p); + /* Command logging facility. */ #define target_log_command(p) \ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index e3aaeab..e886869 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2009-03-05 Pedro Alves + + * gdb.arch/i386-permbkpt.S, gdb.arch/i386-permbkpt.exp: New. + 2009-02-18 Jan Kratochvil * gdb.base/macscp.exp (objfile): Move it to ${objdir}/${subdir}/. diff --git a/gdb/testsuite/configure.ac b/gdb/testsuite/configure.ac index 3d8fae4..5fb9067 100644 --- a/gdb/testsuite/configure.ac +++ b/gdb/testsuite/configure.ac @@ -1,7 +1,7 @@ # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. -# Copyright 2002, 2003, 2004, 2005 +# Copyright 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or modify diff --git a/gdb/testsuite/gdb.arch/i386-permbkpt.S b/gdb/testsuite/gdb.arch/i386-permbkpt.S new file mode 100644 index 0000000..02a31d6 --- /dev/null +++ b/gdb/testsuite/gdb.arch/i386-permbkpt.S @@ -0,0 +1,30 @@ +/* Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + This file is part of the gdb testsuite. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +#ifdef SYMBOL_PREFIX +# define SYMBOL(str) CONCAT1(SYMBOL_PREFIX, str) +#else +# define SYMBOL(str) str +#endif + + .global SYMBOL(main) +SYMBOL(main): + int3 + ret diff --git a/gdb/testsuite/gdb.arch/i386-permbkpt.exp b/gdb/testsuite/gdb.arch/i386-permbkpt.exp new file mode 100644 index 0000000..f1930e5 --- /dev/null +++ b/gdb/testsuite/gdb.arch/i386-permbkpt.exp @@ -0,0 +1,52 @@ +# Copyright (C) 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# This file is part of the gdb testsuite. + +if $tracelevel { + strace $tracelevel +} + +# Test inserting breakpoints over permanent breakpoints on i386 and amd64. + +if { ![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] } then { + verbose "Skipping i386 test for multi break at permanent breakpoint location." + return +} + +set testfile "i386-permbkpt" +set srcfile ${testfile}.S +set binfile ${objdir}/${subdir}/${testfile} + +# Some targets have leading underscores on assembly symbols. +# TODO: detect this automatically +set additional_flags "" +if { [istarget "*-*-cygwin*"] || [istarget "*-*-mingw*"] } then { + set additional_flags "additional_flags=-DSYMBOL_PREFIX=_" +} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug $additional_flags]] != "" } { + untested i386-permbkpt.exp + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +gdb_test "break main" "" "First permanent break" +gdb_test "break main" "" "Second permanent break" diff --git a/gdb/testsuite/gdb.arch/powerpc-power7.exp b/gdb/testsuite/gdb.arch/powerpc-power7.exp new file mode 100644 index 0000000..d9c48f9 --- /dev/null +++ b/gdb/testsuite/gdb.arch/powerpc-power7.exp @@ -0,0 +1,166 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Test PowerPC Power7 instructions disassembly. + +if {![istarget "powerpc*-*-*"]} then { + verbose "Skipping PowerPC Power7 instructions disassembly." + return +} + +set testfile "powerpc-power7" +set srcfile ${testfile}.s +set objfile ${objdir}/${subdir}/${testfile}.o + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objfile}" object {debug}] != "" } { + untested "PowerPC Power7 instructions disassembly" + return -1 +} + + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${objfile} + + +# Disassemble the function. + +set test "disass func" +gdb_test_multiple $test $test { + -re "\r\nDump of assembler code for function func:(\r\n.*\r\n)End of assembler dump.\r\n$gdb_prompt $" { + set func $expect_out(1,string) + pass $test + } +} + +proc func_check {offset instr} { + global func + + # 0x0000000000000018 : stxvd2x vs43,r4,r5 + set patt ".*\r\n[string map {0x 0x0*} $offset] :\[ \t\]*[string map [list { } "\[ \t\]+" . {\.}] $instr]\[ \t\]*\r\n.*" + set test "Found $offset: $instr" + if [regexp -nocase -line $patt $func] { + pass $test + } else { + fail $test + } +} + +func_check 0x0 "lxvd2x vs3,r4,r5" +func_check 0x4 "lxvd2ux vs3,r4,r5" +func_check 0x8 "lxvd2x vs43,r4,r5" +func_check 0xc "lxvd2ux vs43,r4,r5" +func_check 0x10 "stxvd2x vs3,r4,r5" +func_check 0x14 "stxvd2ux vs3,r4,r5" +func_check 0x18 "stxvd2x vs43,r4,r5" +func_check 0x1c "stxvd2ux vs43,r4,r5" +func_check 0x20 "xxmrghd vs3,vs4,vs5" +func_check 0x24 "xxmrghd vs43,vs44,vs45" +func_check 0x28 "xxmrgld vs3,vs4,vs5" +func_check 0x2c "xxmrgld vs43,vs44,vs45" +func_check 0x30 "xxmrghd vs3,vs4,vs5" +func_check 0x34 "xxmrghd vs43,vs44,vs45" +func_check 0x38 "xxmrgld vs3,vs4,vs5" +func_check 0x3c "xxmrgld vs43,vs44,vs45" +func_check 0x40 "xxpermdi vs3,vs4,vs5,1" +func_check 0x44 "xxpermdi vs43,vs44,vs45,1" +func_check 0x48 "xxpermdi vs3,vs4,vs5,2" +func_check 0x4c "xxpermdi vs43,vs44,vs45,2" +func_check 0x50 "xvmovdp vs3,vs4" +func_check 0x54 "xvmovdp vs43,vs44" +func_check 0x58 "xvmovdp vs3,vs4" +func_check 0x5c "xvmovdp vs43,vs44" +func_check 0x60 "xvcpsgndp vs3,vs4,vs5" +func_check 0x64 "xvcpsgndp vs43,vs44,vs45" +func_check 0x68 "wait" +func_check 0x6c "wait" +func_check 0x70 "waitrsv" +func_check 0x74 "waitrsv" +func_check 0x78 "waitimpl" +func_check 0x7c "waitimpl" +func_check 0x80 "doze" +func_check 0x84 "nap" +func_check 0x88 "sleep" +func_check 0x8c "rvwinkle" +func_check 0x90 "prtyw r3,r4" +func_check 0x94 "prtyd r13,r14" +func_check 0x98 "mfcfar r10" +func_check 0x9c "mtcfar r11" +func_check 0xa0 "cmpb r3,r4,r5" +func_check 0xa4 "lwzcix r10,r11,r12" +func_check 0xa8 "dadd f16,f17,f18" +func_check 0xac "daddq f20,f22,f24" +func_check 0xb0 "dss 3" +func_check 0xb4 "dssall" +func_check 0xb8 "dst r5,r4,1" +func_check 0xbc "dstt r8,r7,0" +func_check 0xc0 "dstst r5,r6,3" +func_check 0xc4 "dststt r4,r5,2" +func_check 0xc8 "divwe r10,r11,r12" +func_check 0xcc "divwe. r11,r12,r13" +func_check 0xd0 "divweo r12,r13,r14" +func_check 0xd4 "divweo. r13,r14,r15" +func_check 0xd8 "divweu r10,r11,r12" +func_check 0xdc "divweu. r11,r12,r13" +func_check 0xe0 "divweuo r12,r13,r14" +func_check 0xe4 "divweuo. r13,r14,r15" +func_check 0xe8 "bpermd r7,r17,r27" +func_check 0xec "popcntw r10,r20" +func_check 0xf0 "popcntd r10,r20" +func_check 0xf4 "ldbrx r20,r21,r22" +func_check 0xf8 "stdbrx r20,r21,r22" +func_check 0xfc "lfiwzx f10,0,r10" +func_check 0x100 "lfiwzx f10,r9,r10" +func_check 0x104 "fcfids f4,f5" +func_check 0x108 "fcfids. f4,f5" +func_check 0x10c "fcfidus f4,f5" +func_check 0x110 "fcfidus. f4,f5" +func_check 0x114 "fctiwu f4,f5" +func_check 0x118 "fctiwu. f4,f5" +func_check 0x11c "fctiwuz f4,f5" +func_check 0x120 "fctiwuz. f4,f5" +func_check 0x124 "fctidu f4,f5" +func_check 0x128 "fctidu. f4,f5" +func_check 0x12c "fctiduz f4,f5" +func_check 0x130 "fctiduz. f4,f5" +func_check 0x134 "fcfidu f4,f5" +func_check 0x138 "fcfidu. f4,f5" +func_check 0x13c "ftdiv cr0,f10,f11" +func_check 0x140 "ftdiv cr7,f10,f11" +func_check 0x144 "ftsqrt cr0,f10" +func_check 0x148 "ftsqrt cr7,f10" +func_check 0x14c "dcbtt r8,r9" +func_check 0x150 "dcbtstt r8,r9" +func_check 0x154 "dcffix f10,f12" +func_check 0x158 "dcffix. f20,f22" +func_check 0x15c "lbarx r10,r11,r12" +func_check 0x160 "lbarx r10,r11,r12" +func_check 0x164 "lbarx r10,r11,r12,1" +func_check 0x168 "lharx r20,r21,r22" +func_check 0x16c "lharx r20,r21,r22" +func_check 0x170 "lharx r20,r21,r22,1" +func_check 0x174 "stbcx. r10,r11,r12" +func_check 0x178 "sthcx. r10,r11,r12" +func_check 0x17c "fre f14,f15" +func_check 0x180 "fre. f14,f15" +func_check 0x184 "fres f14,f15" +func_check 0x188 "fres. f14,f15" +func_check 0x18c "frsqrte f14,f15" +func_check 0x190 "frsqrte. f14,f15" +func_check 0x194 "frsqrtes f14,f15" +func_check 0x198 "frsqrtes. f14,f15" +func_check 0x19c "isel r2,r3,r4,28" diff --git a/gdb/testsuite/gdb.arch/powerpc-power7.s b/gdb/testsuite/gdb.arch/powerpc-power7.s new file mode 100644 index 0000000..98b2e79 --- /dev/null +++ b/gdb/testsuite/gdb.arch/powerpc-power7.s @@ -0,0 +1,107 @@ + .text + .globl func +func: + .long 0x7c642e98 /* 0: lxvd2x vs3,r4,r5 */ + .long 0x7c642ed8 /* 4: lxvd2ux vs3,r4,r5 */ + .long 0x7d642e99 /* 8: lxvd2x vs43,r4,r5 */ + .long 0x7d642ed9 /* c: lxvd2ux vs43,r4,r5 */ + .long 0x7c642f98 /* 10: stxvd2x vs3,r4,r5 */ + .long 0x7c642fd8 /* 14: stxvd2ux vs3,r4,r5 */ + .long 0x7d642f99 /* 18: stxvd2x vs43,r4,r5 */ + .long 0x7d642fd9 /* 1c: stxvd2ux vs43,r4,r5 */ + .long 0xf0642850 /* 20: xxmrghd vs3,vs4,vs5 */ + .long 0xf16c6857 /* 24: xxmrghd vs43,vs44,vs45 */ + .long 0xf0642b50 /* 28: xxmrgld vs3,vs4,vs5 */ + .long 0xf16c6b57 /* 2c: xxmrgld vs43,vs44,vs45 */ + .long 0xf0642850 /* 30: xxmrghd vs3,vs4,vs5 */ + .long 0xf16c6857 /* 34: xxmrghd vs43,vs44,vs45 */ + .long 0xf0642b50 /* 38: xxmrgld vs3,vs4,vs5 */ + .long 0xf16c6b57 /* 3c: xxmrgld vs43,vs44,vs45 */ + .long 0xf0642950 /* 40: xxpermdi vs3,vs4,vs5,1 */ + .long 0xf16c6957 /* 44: xxpermdi vs43,vs44,vs45,1 */ + .long 0xf0642a50 /* 48: xxpermdi vs3,vs4,vs5,2 */ + .long 0xf16c6a57 /* 4c: xxpermdi vs43,vs44,vs45,2 */ + .long 0xf0642780 /* 50: xvmovdp vs3,vs4 */ + .long 0xf16c6787 /* 54: xvmovdp vs43,vs44 */ + .long 0xf0642780 /* 58: xvmovdp vs3,vs4 */ + .long 0xf16c6787 /* 5c: xvmovdp vs43,vs44 */ + .long 0xf0642f80 /* 60: xvcpsgndp vs3,vs4,vs5 */ + .long 0xf16c6f87 /* 64: xvcpsgndp vs43,vs44,vs45 */ + .long 0x7c00007c /* 68: wait */ + .long 0x7c00007c /* 6c: wait */ + .long 0x7c20007c /* 70: waitrsv */ + .long 0x7c20007c /* 74: waitrsv */ + .long 0x7c40007c /* 78: waitimpl */ + .long 0x7c40007c /* 7c: waitimpl */ + .long 0x4c000324 /* 80: doze */ + .long 0x4c000364 /* 84: nap */ + .long 0x4c0003a4 /* 88: sleep */ + .long 0x4c0003e4 /* 8c: rvwinkle */ + .long 0x7c830134 /* 90: prtyw r3,r4 */ + .long 0x7dcd0174 /* 94: prtyd r13,r14 */ + .long 0x7d5c02a6 /* 98: mfcfar r10 */ + .long 0x7d7c03a6 /* 9c: mtcfar r11 */ + .long 0x7c832bf8 /* a0: cmpb r3,r4,r5 */ + .long 0x7d4b662a /* a4: lwzcix r10,r11,r12 */ + .long 0xee119004 /* a8: dadd f16,f17,f18 */ + .long 0xfe96c004 /* ac: daddq f20,f22,f24 */ + .long 0x7c60066c /* b0: dss 3 */ + .long 0x7e00066c /* b4: dssall */ + .long 0x7c2522ac /* b8: dst r5,r4,1 */ + .long 0x7e083aac /* bc: dstt r8,r7,0 */ + .long 0x7c6532ec /* c0: dstst r5,r6,3 */ + .long 0x7e442aec /* c4: dststt r4,r5,2 */ + .long 0x7d4b6356 /* c8: divwe r10,r11,r12 */ + .long 0x7d6c6b57 /* cc: divwe. r11,r12,r13 */ + .long 0x7d8d7756 /* d0: divweo r12,r13,r14 */ + .long 0x7dae7f57 /* d4: divweo. r13,r14,r15 */ + .long 0x7d4b6316 /* d8: divweu r10,r11,r12 */ + .long 0x7d6c6b17 /* dc: divweu. r11,r12,r13 */ + .long 0x7d8d7716 /* e0: divweuo r12,r13,r14 */ + .long 0x7dae7f17 /* e4: divweuo. r13,r14,r15 */ + .long 0x7e27d9f8 /* e8: bpermd r7,r17,r27 */ + .long 0x7e8a02f4 /* ec: popcntw r10,r20 */ + .long 0x7e8a03f4 /* f0: popcntd r10,r20 */ + .long 0x7e95b428 /* f4: ldbrx r20,r21,r22 */ + .long 0x7e95b528 /* f8: stdbrx r20,r21,r22 */ + .long 0x7d4056ee /* fc: lfiwzx f10,0,r10 */ + .long 0x7d4956ee /* 100: lfiwzx f10,r9,r10 */ + .long 0xec802e9c /* 104: fcfids f4,f5 */ + .long 0xec802e9d /* 108: fcfids. f4,f5 */ + .long 0xec802f9c /* 10c: fcfidus f4,f5 */ + .long 0xec802f9d /* 110: fcfidus. f4,f5 */ + .long 0xfc80291c /* 114: fctiwu f4,f5 */ + .long 0xfc80291d /* 118: fctiwu. f4,f5 */ + .long 0xfc80291e /* 11c: fctiwuz f4,f5 */ + .long 0xfc80291f /* 120: fctiwuz. f4,f5 */ + .long 0xfc802f5c /* 124: fctidu f4,f5 */ + .long 0xfc802f5d /* 128: fctidu. f4,f5 */ + .long 0xfc802f5e /* 12c: fctiduz f4,f5 */ + .long 0xfc802f5f /* 130: fctiduz. f4,f5 */ + .long 0xfc802f9c /* 134: fcfidu f4,f5 */ + .long 0xfc802f9d /* 138: fcfidu. f4,f5 */ + .long 0xfc0a5900 /* 13c: ftdiv cr0,f10,f11 */ + .long 0xff8a5900 /* 140: ftdiv cr7,f10,f11 */ + .long 0xfc005140 /* 144: ftsqrt cr0,f10 */ + .long 0xff805140 /* 148: ftsqrt cr7,f10 */ + .long 0x7e084a2c /* 14c: dcbtt r8,r9 */ + .long 0x7e0849ec /* 150: dcbtstt r8,r9 */ + .long 0xed406644 /* 154: dcffix f10,f12 */ + .long 0xee80b645 /* 158: dcffix. f20,f22 */ + .long 0x7d4b6068 /* 15c: lbarx r10,r11,r12 */ + .long 0x7d4b6068 /* 160: lbarx r10,r11,r12 */ + .long 0x7d4b6069 /* 164: lbarx r10,r11,r12,1 */ + .long 0x7e95b0e8 /* 168: lharx r20,r21,r22 */ + .long 0x7e95b0e8 /* 16c: lharx r20,r21,r22 */ + .long 0x7e95b0e9 /* 170: lharx r20,r21,r22,1 */ + .long 0x7d4b656d /* 174: stbcx. r10,r11,r12 */ + .long 0x7d4b65ad /* 178: sthcx. r10,r11,r12 */ + .long 0xfdc07830 /* 17c: fre f14,f15 */ + .long 0xfdc07831 /* 180: fre. f14,f15 */ + .long 0xedc07830 /* 184: fres f14,f15 */ + .long 0xedc07831 /* 188: fres. f14,f15 */ + .long 0xfdc07834 /* 18c: frsqrte f14,f15 */ + .long 0xfdc07835 /* 190: frsqrte. f14,f15 */ + .long 0xedc07834 /* 194: frsqrtes f14,f15 */ + .long 0xedc07835 /* 198: frsqrtes. f14,f15 */ + .long 0x7c43271e /* 19c: isel r2,r3,r4,28 */ diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S b/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S new file mode 100644 index 0000000..66f7a39 --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S @@ -0,0 +1,455 @@ + .file "x86_64-vla-typedef.c" + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .section .debug_line,"",@progbits +.Ldebug_line0: + .text +.Ltext0: +.globl foo + .type foo, @function +foo: +.LFB2: + .file 1 "x86_64-vla-typedef.c" + .loc 1 22 0 + pushq %rbp +.LCFI0: + movq %rsp, %rbp +.LCFI1: + subq $64, %rsp +.LCFI2: + movl %edi, -36(%rbp) + .loc 1 22 0 + movq %rsp, %rax + movq %rax, -48(%rbp) + .loc 1 23 0 + movl -36(%rbp), %edx + movslq %edx,%rax + subq $1, %rax + movq %rax, -24(%rbp) + .loc 1 24 0 + movslq %edx,%rax + addq $15, %rax + addq $15, %rax + shrq $4, %rax + salq $4, %rax + subq %rax, %rsp + movq %rsp, -56(%rbp) + movq -56(%rbp), %rax + addq $15, %rax + shrq $4, %rax + salq $4, %rax + movq %rax, -56(%rbp) + movq -56(%rbp), %rax + movq %rax, -16(%rbp) + .loc 1 27 0 + movl $0, -4(%rbp) + jmp .L2 +.L3: + .loc 1 28 0 + movl -4(%rbp), %esi + movl -4(%rbp), %eax + movl %eax, %ecx + movq -16(%rbp), %rdx + movslq %esi,%rax + movb %cl, (%rdx,%rax) + .loc 1 27 0 + addl $1, -4(%rbp) +.L2: + movl -4(%rbp), %eax + cmpl -36(%rbp), %eax + jl .L3 + .loc 1 30 0 + .globl break_here +break_here: + movq -16(%rbp), %rax + movb $0, (%rax) + movq -48(%rbp), %rsp + .loc 1 31 0 + leave + ret +.LFE2: + .size foo, .-foo + .section .debug_frame,"",@progbits +.Lframe0: + .long .LECIE0-.LSCIE0 +.LSCIE0: + .long 0xffffffff + .byte 0x1 + .string "" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE0: +.LSFDE0: + .long .LEFDE0-.LASFDE0 +.LASFDE0: + .long .Lframe0 + .quad .LFB2 + .quad .LFE2-.LFB2 + .byte 0x4 + .long .LCFI0-.LFB2 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .align 8 +.LEFDE0: + .section .eh_frame,"a",@progbits +.Lframe1: + .long .LECIE1-.LSCIE1 +.LSCIE1: + .long 0x0 + .byte 0x1 + .string "zR" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .uleb128 0x1 + .byte 0x3 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE1: +.LSFDE1: + .long .LEFDE1-.LASFDE1 +.LASFDE1: + .long .LASFDE1-.Lframe1 + .long .LFB2 + .long .LFE2-.LFB2 + .uleb128 0x0 + .byte 0x4 + .long .LCFI0-.LFB2 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .align 8 +.LEFDE1: + .text +.Letext0: + .section .debug_loc,"",@progbits +.Ldebug_loc0: +.LLST0: + .quad .LFB2-.Ltext0 + .quad .LCFI0-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 8 + .quad .LCFI0-.Ltext0 + .quad .LCFI1-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 16 + .quad .LCFI1-.Ltext0 + .quad .LFE2-.Ltext0 + .value 0x2 + .byte 0x76 + .sleb128 16 + .quad 0x0 + .quad 0x0 + .section .debug_info + .long .Ldebug_end - .Ldebug_start +.Ldebug_start: + .value 0x2 + .long .Ldebug_abbrev0 + .byte 0x8 + .uleb128 0x1 + .long .LASF2 + .byte 0x1 + .long .LASF3 + .long .LASF4 + .quad .Ltext0 + .quad .Letext0 + .long .Ldebug_line0 + .uleb128 0x2 + .byte 0x1 + .string "foo" + .byte 0x1 + .byte 0x16 + .byte 0x1 + .quad .LFB2 + .quad .LFE2 + .long .LLST0 + .long 0x83 + .uleb128 0x3 + .long .LASF5 + .byte 0x1 + .byte 0x15 + .long 0x83 + .byte 0x2 + .byte 0x91 + .sleb128 -52 +.Ltag_typedef: + .uleb128 0x4 + .long .LASF6 + .byte 0x1 + .byte 0x17 + .long .Ltag_array_type - .debug_info + .uleb128 0x5 /* Abbrev Number: 5 (DW_TAG_variable) */ + .long .LASF0 + .byte 0x1 + .byte 0x18 +#if 1 + .long .Ltag_typedef - .debug_info +#else + /* Debugging only: Skip the typedef indirection. */ + .long .Ltag_array_type - .debug_info +#endif + /* DW_AT_location: DW_FORM_block1: start */ + .byte 0x3 + .byte 0x91 + .sleb128 -32 +#if 0 + .byte 0x6 /* DW_OP_deref */ +#else + .byte 0x96 /* DW_OP_nop */ +#endif + /* DW_AT_location: DW_FORM_block1: end */ + .uleb128 0x6 + .string "i" + .byte 0x1 + .byte 0x19 + .long 0x83 + .byte 0x2 + .byte 0x91 + .sleb128 -20 + .byte 0x0 + .uleb128 0x7 + .byte 0x4 + .byte 0x5 + .string "int" +.Ltag_array_type: + .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */ + .long 0xa0 + (2f - 1f) /* DW_AT_type: DW_FORM_ref4 */ + .long 0x9d + (2f - 1f) /* DW_AT_sibling: DW_FORM_ref4 */ +1: /* DW_AT_data_location: DW_FORM_block1: start */ + .byte 2f - 3f /* length */ +3: + .byte 0x97 /* DW_OP_push_object_address */ + .byte 0x6 /* DW_OP_deref */ +2: /* DW_AT_data_location: DW_FORM_block1: end */ + .uleb128 0x9 + .long 0x9d + (2b - 1b) /* DW_AT_type: DW_FORM_ref4 */ + .byte 0x3 + .byte 0x91 + .sleb128 -40 + .byte 0x6 + .byte 0x0 + .uleb128 0xa + .byte 0x8 + .byte 0x7 + .uleb128 0xb + .byte 0x1 + .byte 0x6 + .long .LASF1 + .byte 0x0 +.Ldebug_end: + .section .debug_abbrev + .uleb128 0x1 + .uleb128 0x11 + .byte 0x1 + .uleb128 0x25 + .uleb128 0xe + .uleb128 0x13 + .uleb128 0xb + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x1b + .uleb128 0xe + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x10 + .uleb128 0x6 + .byte 0x0 + .byte 0x0 + .uleb128 0x2 + .uleb128 0x2e + .byte 0x1 + .uleb128 0x3f + .uleb128 0xc + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x27 + .uleb128 0xc + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x40 + .uleb128 0x6 + .uleb128 0x1 + .uleb128 0x13 + .byte 0x0 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x5 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x4 + .uleb128 0x16 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .byte 0x0 + .byte 0x0 + .uleb128 0x5 + .uleb128 0x34 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x6 + .uleb128 0x34 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x7 + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .uleb128 0x3 + .uleb128 0x8 + .byte 0x0 + .byte 0x0 + .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */ + .uleb128 0x1 + .byte 0x1 + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x1 /* DW_AT_sibling */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x50 /* DW_AT_data_location */ + .uleb128 0xa /* DW_FORM_block1 */ + .byte 0x0 + .byte 0x0 + .uleb128 0x9 + .uleb128 0x21 + .byte 0x0 + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x2f + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0xa + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .byte 0x0 + .byte 0x0 + .uleb128 0xb + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .uleb128 0x3 + .uleb128 0xe + .byte 0x0 + .byte 0x0 + .byte 0x0 + .section .debug_pubnames,"",@progbits + .long 0x16 + .value 0x2 + .long .Ldebug_info0 + .long 0xa8 + .long 0x2d + .string "foo" + .long 0x0 + .section .debug_aranges,"",@progbits + .long 0x2c + .value 0x2 + .long .Ldebug_info0 + .byte 0x8 + .byte 0x0 + .value 0x0 + .value 0x0 + .quad .Ltext0 + .quad .Letext0-.Ltext0 + .quad 0x0 + .quad 0x0 + .section .debug_str,"MS",@progbits,1 +.LASF0: + .string "array" +.LASF5: + .string "size" +.LASF3: + .string "x86_64-vla-typedef.c" +.LASF6: + .string "array_t" +.LASF1: + .string "char" +.LASF4: + .string "gdb.arch" +.LASF2: + .string "GNU C 4.3.2 20081105 (Red Hat 4.3.2-7)" + .ident "GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c new file mode 100644 index 0000000..b809c4e --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c @@ -0,0 +1,43 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#if 0 + +void +foo (int size) +{ + typedef char array_t[size]; + array_t array; + int i; + + for (i = 0; i < size; i++) + array[i] = i; + + array[0] = 0; /* break-here */ +} + +#else + +int +main (void) +{ + foo (26); + foo (78); + return 0; +} + +#endif diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp new file mode 100644 index 0000000..534120a --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp @@ -0,0 +1,64 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test DW_AT_data_location accessed through DW_TAG_typedef intermediate. + +if ![istarget "x86_64-*-*"] then { + verbose "Skipping over gdb.arch/x86_64-vla-typedef.exp test made only for x86_64." + return +} + +set testfile x86_64-vla-typedef +set srcasmfile ${testfile}-foo.S +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +set binobjfile ${objdir}/${subdir}/${testfile}-foo.o +if { [gdb_compile "${srcdir}/${subdir}/${srcasmfile}" "${binobjfile}" object {}] != "" } { + untested "Couldn't compile test program" + return -1 +} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile} ${binobjfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] { + untested x86_64-vla-typedef + return -1 +} + +gdb_breakpoint "break_here" + +gdb_continue_to_breakpoint "break_here" + +gdb_test "whatis array" "type = array_t" "first: whatis array" + +gdb_test "ptype array" "type = char \\\[26\\\]" "first: ptype array" + +gdb_test "p array\[1\]" "\\$\[0-9\] = 1 '\\\\1'" +gdb_test "p array\[2\]" "\\$\[0-9\] = 2 '\\\\2'" +gdb_test "p array\[3\]" "\\$\[0-9\] = 3 '\\\\3'" +gdb_test "p array\[4\]" "\\$\[0-9\] = 4 '\\\\4'" + +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/Makefile.in b/gdb/testsuite/gdb.base/Makefile.in index 9f382db..12db521 100644 --- a/gdb/testsuite/gdb.base/Makefile.in +++ b/gdb/testsuite/gdb.base/Makefile.in @@ -12,7 +12,7 @@ EXECUTABLES = all-types annota1 bitfields break \ scope section_command setshow setvar shmain sigall signals \ solib solib_sl so-impl-ld so-indr-cl \ step-line step-test structs structs2 \ - twice-tmp varargs vforked-prog watchpoint whatis + twice-tmp varargs vforked-prog watchpoint whatis catch-syscall MISCELLANEOUS = coremmap.data ../foobar.baz \ shr1.sl shr2.sl solib_sl.sl solib1.sl solib2.sl diff --git a/gdb/testsuite/gdb.base/call-rt-st.exp b/gdb/testsuite/gdb.base/call-rt-st.exp index 3359c70..f73dd7f 100644 --- a/gdb/testsuite/gdb.base/call-rt-st.exp +++ b/gdb/testsuite/gdb.base/call-rt-st.exp @@ -186,7 +186,7 @@ if {![gdb_skip_float_test "print print_two_floats(*f3)"] && \ if ![gdb_skip_stdio_test "print print_bit_flags_char(*cflags)"] { print_struct_call "print_bit_flags_char(*cflags)" \ - ".*alpha\[ \r\n\]+gamma\[ \r\n\]+epsilon\[ \r\n\]+.\[0-9\]+ = \\{alpha = 1 '\\\\001', beta = 0 '\\\\0', gamma = 1 '\\\\001', delta = 0 '\\\\0', epsilon = 1 '\\\\001', omega = 0 '\\\\0'\\}" + ".*alpha\[ \r\n\]+gamma\[ \r\n\]+epsilon\[ \r\n\]+.\[0-9\]+ = \\{alpha = 1 '\\\\1', beta = 0 '\\\\0', gamma = 1 '\\\\1', delta = 0 '\\\\0', epsilon = 1 '\\\\1', omega = 0 '\\\\0'\\}" } if ![gdb_skip_stdio_test "print print_bit_flags_short(*sflags)"] { diff --git a/gdb/testsuite/gdb.base/callfuncs.exp b/gdb/testsuite/gdb.base/callfuncs.exp index 6d8aa45..be6a872 100644 --- a/gdb/testsuite/gdb.base/callfuncs.exp +++ b/gdb/testsuite/gdb.base/callfuncs.exp @@ -437,7 +437,7 @@ gdb_test "print t_small_values(1,3,5,7,9,11,13,15,17,19)" \ "The program being debugged stopped while.*" \ "stop at nested call level 4" gdb_test "backtrace" \ - "\#0 t_small_values \\(arg1=1 '.001', arg2=3, arg3=5, arg4=7 '.a', arg5=9, arg6=11 '.v', arg7=13, arg8=15, arg9=17, arg10=19\\).*\#2 sum10 \\(i0=2, i1=4, i2=6, i3=8, i4=10, i5=12, i6=14, i7=16, i8=18, i9=20\\).*\#3 .*\#4 add \\(a=4, b=5\\).*\#5 .*\#6 add \\(a=2, b=3\\).*\#7 .*\#8 main.*" \ + "\#0 t_small_values \\(arg1=1 '.1', arg2=3, arg3=5, arg4=7 '.a', arg5=9, arg6=11 '.v', arg7=13, arg8=15, arg9=17, arg10=19\\).*\#2 sum10 \\(i0=2, i1=4, i2=6, i3=8, i4=10, i5=12, i6=14, i7=16, i8=18, i9=20\\).*\#3 .*\#4 add \\(a=4, b=5\\).*\#5 .*\#6 add \\(a=2, b=3\\).*\#7 .*\#8 main.*" \ "backtrace at nested call level 4" gdb_test "finish" "Value returned is .* = 100" \ "Finish from nested call level 4" diff --git a/gdb/testsuite/gdb.base/catch-syscall.c b/gdb/testsuite/gdb.base/catch-syscall.c new file mode 100644 index 0000000..64850de --- /dev/null +++ b/gdb/testsuite/gdb.base/catch-syscall.c @@ -0,0 +1,25 @@ +/* This file is used to test the 'catch syscall' feature on GDB. + + Please, if you are going to edit this file DO NOT change the syscalls + being called (nor the order of them). If you really must do this, then + take a look at catch-syscall.exp and modify there too. + + Written by Sergio Durigan Junior + September, 2008 */ + +#include +#include +#include + +int +main (void) +{ + /* A close() with a wrong argument. We are only + interested in the syscall. */ + close (-1); + + chroot ("."); + + /* The last syscall. Do not change this. */ + _exit (0); +} diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp new file mode 100644 index 0000000..a9f6937 --- /dev/null +++ b/gdb/testsuite/gdb.base/catch-syscall.exp @@ -0,0 +1,386 @@ +# Copyright 1997, 1999, 2007, 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# This program tests the 'catch syscall' functionality. +# +# It was written by Sergio Durigan Junior +# on September/2008. + +if { [is_remote target] || ![isnative] } then { + continue +} + +set prms_id 0 +set bug_id 0 + +global srcfile +set testfile "catch-syscall" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +# All (but the last) syscalls from the example code +# They are ordered according to the file, so do not change this. +set all_syscalls { "close" "chroot" } +# The last syscall (exit()) does not return, so +# we cannot expect the catchpoint to be triggered +# twice. It is a special case. +set last_syscall "exit_group" + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested catch-syscall.exp + return -1 +} + +# Until "catch syscall" is implemented on other targets... +if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-linux*"]} then { + continue +} + +# This shall be updated whenever 'catch syscall' is implemented +# on some architecture. +#if { ![istarget "x86_64-*-linux*"] && ![istarget "i\[34567\]86-*-linux*"] +if { ![istarget "i\[34567\]86-*-linux*"] + && ![istarget "powerpc-*-linux*"] && ![istarget "powerpc64-*-linux*"] } { + continue +} + +# Internal procedure used to check if, before any syscall is caught, +# the command 'info breakpoints' correctly lists the catchpoints AND +# says that nothing was caught yet. +proc check_init_info_breakpoints {} { + global gdb_prompt + + # Verifying that the catchpoint appears in the 'info breakpoints' + # command, but with "". + set thistest "catch syscall appears in 'info breakpoints'" + gdb_test "info breakpoints" ".*catchpoint.*keep y.*syscall \"\".*" $thistest +} + +# This procedure checks if, after a syscall catchpoint is hit, the +# command 'info breakpoints' correctly lists the syscall name. +proc check_info_breakpoints { syscall } { + global gdb_prompt + + set thistest "syscall $syscall appears in 'info breakpoints'" + gdb_test "info breakpoints" ".*catchpoint.*keep y.*syscall (.)?${syscall}(.)?.*" $thistest +} + +# This procedure checks if there was a call to a syscall. +proc check_call_to_syscall { syscall } { + global gdb_prompt + + set thistest "program has called $syscall" + gdb_test "continue" "Catchpoint .*(call to syscall .?${syscall}.?).*" $thistest + + # Checking if the syscall is reported to be caught in + # 'info breakpoints'. + check_info_breakpoints "$syscall" +} + +# This procedure checks if the syscall returned. +proc check_return_from_syscall { syscall } { + global gdb_prompt + + set thistest "syscall $syscall has returned" + gdb_test "continue" "Catchpoint .*(returned from syscall (.)?${syscall}(.)?).*" $thistest + + # Checking if the syscall is reported to be caught in + # 'info breakpoints'. + check_info_breakpoints "$syscall" +} + +# Internal procedure that performs two 'continue' commands and checks if +# a syscall call AND return occur. +proc check_continue { syscall } { + global gdb_prompt + + # Testing if the 'continue' stops at the + # specified syscall_name. If it does, then it should + # first print that the infeior has called the syscall, + # and after print that the syscall has returned. + + # Testing if the inferiorr has called the syscall. + check_call_to_syscall $syscall + # And now, that the syscall has returned. + check_return_from_syscall $syscall +} + +# Inserts a syscall catchpoint with an argument. +proc insert_catch_syscall_with_arg { syscall } { + global gdb_prompt + + # Trying to set the syscall + set thistest "catch syscall with arguments ($syscall)" + gdb_test "catch syscall $syscall" "Catchpoint .*(syscall\[(\]s\[)\] (.)?${syscall}(.)?).*" $thistest +} + +proc check_for_program_end {} { + global gdb_prompt + + # Deleting the catchpoints + delete_breakpoints + + set thistest "successful program end" + gdb_test "continue" "Program exited normally.*" $thistest + +} + +proc test_catch_syscall_without_args {} { + global gdb_prompt all_syscalls last_syscall + + # Trying to set the syscall + set thistest "setting catch syscall without arguments" + gdb_test "catch syscall" "Catchpoint .*(syscall).*" $thistest + + check_init_info_breakpoints + + # We have to check every syscall + foreach name $all_syscalls { + check_continue $name + } + + # At last but not least, we check if the inferior + # has called the last (exit) syscall. + check_call_to_syscall $last_syscall + + # Now let's see if the inferior correctly finishes. + check_for_program_end +} + +proc test_catch_syscall_with_args {} { + global gdb_prompt + set syscall_name "close" + + insert_catch_syscall_with_arg $syscall_name + check_init_info_breakpoints + + # Can we continue until we catch the syscall? + check_continue $syscall_name + + # Now let's see if the inferior correctly finishes. + check_for_program_end +} + +proc test_catch_syscall_with_wrong_args {} { + global gdb_prompt + # mlock is not called from the source + set syscall_name "mlock" + + insert_catch_syscall_with_arg $syscall_name + check_init_info_breakpoints + + # Now, we must verify if the program stops with a continue. + # If it doesn't, everything is right (since we don't have + # a syscall named "mlock" in it). Otherwise, this is a failure. + set thistest "catch syscall with unused syscall ($syscall_name)" + gdb_test "continue" "Program exited normally.*" $thistest +} + +proc test_catch_syscall_restarting_inferior {} { + global gdb_prompt + set syscall_name "chroot" + + insert_catch_syscall_with_arg $syscall_name + check_init_info_breakpoints + + # Let's first reach the call of the syscall. + check_call_to_syscall $syscall_name + + # Now, restart the program + rerun_to_main + + # And check for call/return + check_continue $syscall_name + + # Can we finish? + check_for_program_end +} + +proc do_syscall_tests {} { + global gdb_prompt srcdir + + # First, we need to set GDB datadir. + send_gdb "maintenance set gdb_datadir $srcdir/..\n" + gdb_expect 10 { + -re "$gdb_prompt $" { + verbose "Setting GDB datadir to $srcdir/..." 2 + } + timeout { + error "Couldn't set GDB datadir." + } + } + + # Verify that the 'catch syscall' help is available + set thistest "help catch syscall" + gdb_test "help catch syscall" "Catch system calls.*" $thistest + + # Try to set a catchpoint to a nonsense syscall + set thistest "catch syscall to a nonsense syscall is prohibited" + gdb_test "catch syscall nonsense_syscall" "Unknown syscall name .*" $thistest + + # Testing the 'catch syscall' command without arguments. + # This test should catch any syscalls. + if [runto_main] then { test_catch_syscall_without_args } + + # Testing the 'catch syscall' command with arguments. + # This test should only catch the specified syscall. + if [runto_main] then { test_catch_syscall_with_args } + + # Testing the 'catch syscall' command with WRONG arguments. + # This test should not trigger any catchpoints. + if [runto_main] then { test_catch_syscall_with_wrong_args } + + # Testing the 'catch' syscall command during a restart of + # the inferior. + if [runto_main] then { test_catch_syscall_restarting_inferior } +} + +proc test_catch_syscall_fail_noxml {} { + global gdb_prompt + + # Sanitizing. + delete_breakpoints + + # Testing to see if we receive a warning when calling "catch syscall" + # without XML support. + set thistest "Catch syscall displays a warning when there is no XML support" + gdb_test "catch syscall" "warning: Could not open .*warning: Could not load the syscall XML file .*GDB will not be able to display syscall names.*Catchpoint .*(syscall).*" $thistest + + # Since the catchpoint was set, we must check if it's present at + # "info breakpoints" + check_init_info_breakpoints + + # Sanitizing. + delete_breakpoints +} + +proc test_catch_syscall_without_args_noxml {} { + # We will need the syscall names even not using it + # because we need to know know many syscalls are in + # the example file. + global gdb_prompt all_syscalls last_syscall + + delete_breakpoints + + set thistest "Catch syscall without arguments and without XML support" + gdb_test "catch syscall" "Catchpoint .*(syscall).*" + + # Now, we should be able to set a catchpoint, + # and GDB shall not display the warning anymore. + foreach name $all_syscalls { + # Unfortunately, we don't know the syscall number + # that will be caught because this information is + # arch-dependent. Thus, we try to catch anything + # similar to a number. + check_continue "\[0-9\]*" + } + + # At last but not least, we check if the inferior + # has called the last (exit) syscall. + check_call_to_syscall "\[0-9\]*" + + delete_breakpoints +} + +proc test_catch_syscall_with_args_noxml {} { + global gdb_prompt + + # The number of the "close" syscall. This is our + # options for a "long-estabilished" syscall in all + # Linux architectures, but unfortunately x86_64 and + # a few other platforms don't "follow the convention". + # Because of this, we need this ugly check :-(. + set close_number "" + if { [istarget "x86_64-*-linux*"] } { + set close_number "3" + } else { + set close_number "6" + } + + delete_breakpoints + + insert_catch_syscall_with_arg $close_number + check_init_info_breakpoints + + check_continue $close_number + + delete_breakpoints +} + +proc test_catch_syscall_with_wrong_args_noxml {} { + global gdb_prompt + + delete_breakpoints + + # Even without XML support, GDB should not accept unknown + # syscall names for the catchpoint. + set thistest "Catch a nonsense syscall without XML support" + gdb_test "catch syscall nonsense_syscall" "Unknown syscall name .nonsense_syscall.*" $thistest + + delete_breakpoints +} + +proc do_syscall_tests_without_xml {} { + global gdb_prompt srcdir + + # In this case, we don't need to set GDB's datadir because + # we want GDB to display only numbers, not names. So, let's + # begin with the tests. + + # The first test is to see if GDB displays a warning when we + # try to catch syscalls without the XML support. + test_catch_syscall_fail_noxml + + # Now, let's test if we can catch syscalls without XML support. + # We should succeed, but GDB is not supposed to print syscall names. + if [runto_main] then { test_catch_syscall_without_args_noxml } + + # The only valid argument "catch syscall" should accept is the + # syscall number, and not the name (since it can't translate a + # name to a number). + # + # It's worth mentioning that we only try to catch the syscall + # close(). This is because the syscall number is an arch-dependent + # information, so we can't assume that we know every syscall number + # in this system. Therefore, we have decided to use a "long-estabilished" + # system call, and close() just sounded the right choice :-). + if [runto_main] then { test_catch_syscall_with_args_noxml } + + # Now, we'll try to provide a syscall name (valid or not) to the command, + # and expect it to fail. + if [runto_main] then { test_catch_syscall_with_wrong_args_noxml } +} + +# Start with a fresh gdb + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# Execute the tests, using XML support +do_syscall_tests + +# Restart gdb + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# Execute the tests, without XML support. In this case, GDB will +# only display syscall numbers, and not syscall names. +do_syscall_tests_without_xml diff --git a/gdb/testsuite/gdb.base/charset.c b/gdb/testsuite/gdb.base/charset.c index b640702..55a50ce 100644 --- a/gdb/testsuite/gdb.base/charset.c +++ b/gdb/testsuite/gdb.base/charset.c @@ -20,11 +20,6 @@ Please email any bugs, comments, and/or additions to this file to: bug-gdb@gnu.org */ -#include -#include -#include - - /* X_string is a null-terminated string in the X charset whose elements are as follows. X should be the name the `set charset' command uses for the character set, in lower-case, with any @@ -54,6 +49,21 @@ char iso_8859_1_string[NUM_CHARS]; char ebcdic_us_string[NUM_CHARS]; char ibm1047_string[NUM_CHARS]; +/* We make a phony wchar_t and then pretend that this platform uses + UCS-4 (or UCS-2, depending on the size -- same difference for the + purposes of this test). */ +typedef unsigned int wchar_t; +wchar_t ucs_4_string[NUM_CHARS]; + +/* We also define a couple phony types for testing the u'' and U'' + support. It is ok if these have the wrong size on some platforms + -- the test case will skip the tests in that case. */ +typedef unsigned short char16_t; +typedef unsigned int char32_t; + +/* Make sure to use the typedefs. */ +char16_t uvar; +char32_t Uvar; void init_string (char string[], @@ -62,7 +72,10 @@ init_string (char string[], char line_feed, char carriage_return, char horizontal_tab, char vertical_tab, char cent, char misc_ctrl) { - memset (string, x, NUM_CHARS); + int i; + + for (i = 0; i < NUM_CHARS; ++i) + string[i] = x; string[0] = alert; string[1] = backspace; string[2] = form_feed; @@ -85,13 +98,21 @@ fill_run (char string[], int start, int len, int first) } +void +init_ucs4 () +{ + int i; + + for (i = 0; i < NUM_CHARS; ++i) + ucs_4_string[i] = iso_8859_1_string[i] & 0xff; +} + int main () { #ifdef usestubs set_debug_traps(); breakpoint(); #endif - (void) malloc (1); /* Initialize ascii_string. */ init_string (ascii_string, 120, @@ -146,5 +167,7 @@ int main () /* The digits, at least, are contiguous. */ fill_run (ibm1047_string, 59, 10, 240); - puts ("All set!"); /* all strings initialized */ + init_ucs4 (); + + return 0; /* all strings initialized */ } diff --git a/gdb/testsuite/gdb.base/charset.exp b/gdb/testsuite/gdb.base/charset.exp index fa26521..93f66c0 100644 --- a/gdb/testsuite/gdb.base/charset.exp +++ b/gdb/testsuite/gdb.base/charset.exp @@ -47,13 +47,7 @@ proc parse_show_charset_output {testname} { global gdb_prompt gdb_expect { - -re "The current host and target character set is `(.*)'\\.\[\r\n\]+$gdb_prompt $" { - set host_charset $expect_out(1,string) - set target_charset $expect_out(1,string) - set retlist [list $host_charset $target_charset] - pass $testname - } - -re "The current host character set is `(.*)'\\.\[\r\n\]+The current target character set is `(.*)'\\.\[\r\n\]+$gdb_prompt $" { + -re "The host character set is \"(.*)\"\\.\[\r\n\]+The target character set is \"(.*)\"\\.\[\r\n\]+The target wide character set is \"(.*)\"\\.\[\r\n\]+$gdb_prompt $" { set host_charset $expect_out(1,string) set target_charset $expect_out(2,string) set retlist [list $host_charset $target_charset] @@ -81,79 +75,35 @@ proc parse_show_charset_output {testname} { } -# Try the various `show charset' commands. These are all aliases of each -# other; `show target-charset' and `show host-charset' actually print -# both the host and target charsets. +# Try the various `show charset' commands. send_gdb "show charset\n" set show_charset [parse_show_charset_output "show charset"] send_gdb "show target-charset\n" -set show_target_charset [parse_show_charset_output "show target-charset"] +set show_target_charset \ + [lindex [parse_show_charset_output "show target-charset"] 0] -if {[lsearch $show_charset $show_target_charset] >= 0} { +if {[lsearch -exact $show_charset $show_target_charset] >= 0} { pass "check `show target-charset' against `show charset'" } else { fail "check `show target-charset' against `show charset'" } send_gdb "show host-charset\n" -set show_host_charset [parse_show_charset_output "show host-charset"] +set show_host_charset \ + [lindex [parse_show_charset_output "show host-charset"] 0] -if {[lsearch $show_charset $show_host_charset] >= 0} { +if {[lsearch -exact $show_charset $show_host_charset] >= 0} { pass "check `show host-charset' against `show charset'" } else { fail "check `show host-charset' against `show charset'" } - -# Get the list of supported (host) charsets as possible completions. -send_gdb "set charset \t\t" - -# Check that we can at least use ASCII as a host character set. -sleep 1 -gdb_expect { - -re "^set charset .*\r\nASCII.*\r\n$gdb_prompt set charset " { - # We got the output that we wanted, including ASCII as possible - # charset. Send a newline to get us back to the prompt. This will - # also generate an error message. Let's not check here that the error - # message makes sense, we do that below, as a separate testcase. - send_gdb "\n" - gdb_expect { - -re ".*Requires an argument.*$gdb_prompt $" { - pass "get valid character sets" - } - -re ".*$gdb_prompt $" { - send_gdb "\n" - gdb_expect { - -re ".*$gdb_prompt $" { - fail "get valid character sets" - } - } - } - timeout { - fail "(timeout) get valid character sets" - } - } - } - -re ".*$gdb_prompt $" { - # We got some output that ended with a regular prompt - fail "get valid character sets" - } - -re ".*$gdb_prompt set charset.*$" { - # We got some other output, send a cntrl-c to gdb to get us back - # to the prompt. - send_gdb "\003" - fail "get valid character sets" - } - timeout { - fail "get valid character sets (timeout)" - } -} - # Try a malformed `set charset'. +# Also check that we can at least use ASCII as a host character set. gdb_test "set charset" \ - "Requires an argument. Valid arguments are.*" \ + "Requires an argument. Valid arguments are.* ASCII,.*" \ "try malformed `set charset'" # Try using `set host-charset' on an invalid character set. @@ -244,8 +194,10 @@ gdb_expect { } } -# Make sure that GDB supports every host/target charset combination. -foreach host_charset [all_charset_names] { +# We don't want to test all the charset names here, since that would +# be too many combinations. We we pick a subset. +set charset_subset {ASCII ISO-8859-1 EBCDIC-US IBM1047} +foreach host_charset $charset_subset { if {[valid_host_charset $host_charset]} { set testname "try `set host-charset $host_charset'" @@ -279,7 +231,7 @@ foreach host_charset [all_charset_names] { # Now try setting every possible target character set, # given that host charset. - foreach target_charset [all_charset_names] { + foreach target_charset $charset_subset { set testname "try `set target-charset $target_charset'" send_gdb "set target-charset $target_charset\n" gdb_expect { @@ -404,23 +356,42 @@ gdb_expect { } +# We only try the wide character tests on machines where the wchar_t +# typedef in the test case has the right size. +set wchar_size [get_sizeof wchar_t 99] +set wchar_ok 0 +if {$wchar_size == 2} { + lappend charset_subset UCS-2 + set wchar_ok 1 +} elseif {$wchar_size == 4} { + lappend charset_subset UCS-4 + set wchar_ok 1 +} + gdb_test "set host-charset ASCII" "" -foreach target_charset [all_charset_names] { - send_gdb "set target-charset $target_charset\n" +foreach target_charset $charset_subset { + if {$target_charset == "UCS-4" || $target_charset == "UCS-2"} { + set param target-wide-charset + set L L + } else { + set param target-charset + set L "" + } + send_gdb "set $param $target_charset\n" gdb_expect { -re "$gdb_prompt $" { - pass "set target-charset $target_charset" + pass "set $param $target_charset" } timeout { - fail "set target-charset $target_charset (timeout)" + fail "set $param $target_charset (timeout)" } } # Try printing the null character. There seems to be a bug in # gdb_test that requires us to use gdb_expect here. - send_gdb "print '\\0'\n" + send_gdb "print $L'\\0'\n" gdb_expect { - -re "\\\$${decimal} = 0 '\\\\0'\[\r\n\]+$gdb_prompt $" { + -re "\\\$${decimal} = 0 $L'\\\\0'\[\r\n\]+$gdb_prompt $" { pass "print the null character in ${target_charset}" } -re "$gdb_prompt $" { @@ -435,8 +406,14 @@ foreach target_charset [all_charset_names] { # a string in $target_charset. The variable's name is the # character set's name, in lower-case, with all non-identifier # characters replaced with '_', with "_string" stuck on the end. - set var_name [string tolower "${target_charset}_string"] - regsub -all -- "\[^a-z0-9_\]" $var_name "_" var_name + if {$target_charset == "UCS-2"} { + # We still use the ucs_4_string variable -- but the size is + # correct for UCS-2. + set var_name ucs_4_string + } else { + set var_name [string tolower "${target_charset}_string"] + regsub -all -- "\[^a-z0-9_\]" $var_name "_" var_name + } # Compute a regexp matching the results we expect. This is static, # but it's easier than writing it out. @@ -444,12 +421,12 @@ foreach target_charset [all_charset_names] { set uppercase "ABCDEFGHIJKLMNOPQRSTUVWXYZ" set lowercase "abcdefghijklmnopqrstuvwxyz" set digits "0123456789" - set octal_escape "\\\\\[0-9\]\[0-9\]\[0-9\]" + set octal_escape "\\\\\[0-9\]+" send_gdb "print $var_name\n" # ${escapes}${uppercase}${lowercase}${digits}${octal}${octal} gdb_expect { - -re ".* = \"(\\\\a|x)(\\\\b|x)(\\\\f|x)(\\\\n|x)(\\\\r|x)(\\\\t|x)(\\\\v|x)${uppercase}${lowercase}${digits}(\\\\\[0-9\]\[0-9\]\[0-9\]|x)(\\\\\[0-9\]\[0-9\]\[0-9\]|x).*\"\[\r\n\]+$gdb_prompt $" { + -re ".* = $L\"(\\\\a|x)(\\\\b|x)(\\\\f|x)(\\\\n|x)(\\\\r|x)(\\\\t|x)(\\\\v|x)${uppercase}${lowercase}${digits}(${octal_escape}|x)+\"\[\r\n\]+$gdb_prompt $" { pass "print string in $target_charset" } -re "$gdb_prompt $" { @@ -461,22 +438,22 @@ foreach target_charset [all_charset_names] { } # Try entering a character literal, and see if it comes back unchanged. - gdb_test "print 'A'" \ - " = \[0-9-\]+ 'A'" \ + gdb_test "print $L'A'" \ + " = \[0-9-\]+ $L'A'" \ "parse character literal in ${target_charset}" # Check that the character literal was encoded correctly. - gdb_test "print 'A' == $var_name\[7\]" \ + gdb_test "print $L'A' == $var_name\[7\]" \ " = 1" \ "check value of parsed character literal in ${target_charset}" # Try entering a string literal, and see if it comes back unchanged. - gdb_test "print \"abcdefABCDEF012345\"" \ - " = \"abcdefABCDEF012345\"" \ + gdb_test "print $L\"abcdefABCDEF012345\"" \ + " = $L\"abcdefABCDEF012345\"" \ "parse string literal in ${target_charset}" # Check that the string literal was encoded correctly. - gdb_test "print \"q\"\[0\] == $var_name\[49\]" \ + gdb_test "print $L\"q\"\[0\] == $var_name\[49\]" \ " = 1" \ "check value of parsed string literal in ${target_charset}" @@ -509,7 +486,7 @@ foreach target_charset [all_charset_names] { send_gdb "print $var_name\[$i\]\n" set have_escape 1 gdb_expect { - -re "= \[0-9-\]+ '\\\\${escape}'\[\r\n\]+$gdb_prompt $" { + -re "= \[0-9-\]+ $L'\\\\${escape}'\[\r\n\]+$gdb_prompt $" { pass "try printing '\\${escape}' in ${target_charset}" } -re "= \[0-9-\]+ 'x'\[\r\n\]+$gdb_prompt $" { @@ -527,12 +504,12 @@ foreach target_charset [all_charset_names] { if {$have_escape} { # Try parsing a backslash escape in a character literal. - gdb_test "print '\\${escape}' == $var_name\[$i\]" \ + gdb_test "print $L'\\${escape}' == $var_name\[$i\]" \ " = 1" \ "check value of '\\${escape}' in ${target_charset}" # Try parsing a backslash escape in a string literal. - gdb_test "print \"\\${escape}\"\[0\] == $var_name\[$i\]" \ + gdb_test "print $L\"\\${escape}\"\[0\] == $var_name\[$i\]" \ " = 1" \ "check value of \"\\${escape}\" in ${target_charset}" } @@ -540,10 +517,73 @@ foreach target_charset [all_charset_names] { # Try printing a character escape that doesn't exist. We should # get the unescaped character, in the target character set. - gdb_test "print '\\q'" " = \[0-9-\]+ 'q'" \ + gdb_test "print $L'\\q'" " = \[0-9-\]+ $L'q'" \ "print escape that doesn't exist in $target_charset" - gdb_test "print '\\q' == $var_name\[49\]" " = 1" \ + gdb_test "print $L'\\q' == $var_name\[49\]" " = 1" \ "check value of escape that doesn't exist in $target_charset" } +# Reset the target charset. +gdb_test "set target-charset UTF-8" "" + +# \242 is not a valid UTF-8 character. +gdb_test "print \"\\242\"" " = \"\\\\242\"" \ + "non-representable target character" + +gdb_test "print '\\x'" "\\\\x escape without a following hex digit." +gdb_test "print '\\u'" "\\\\u escape without a following hex digit." +gdb_test "print '\\9'" " = \[0-9\]+ '9'" + +# Tests for wide- or unicode- strings. L is the prefix letter to use, +# either "L" (for wide strings), "u" (for UCS-2), or "U" (for UCS-4). +# NAME is used in the test names and should be related to the prefix +# letter in some easy-to-undestand way. +proc test_wide_or_unicode {L name} { + gdb_test "print $L\"ab\" $L\"c\"" " = $L\"abc\"" \ + "basic $name string concatenation" + gdb_test "print $L\"ab\" \"c\"" " = $L\"abc\"" \ + "narrow and $name string concatenation" + gdb_test "print \"ab\" $L\"c\"" " = $L\"abc\"" \ + "$name and narrow string concatenation" + gdb_test "print $L\"\\xe\" $L\"c\"" " = $L\"\\\\16c\"" \ + "$name string concatenation with escape" + gdb_test "print $L\"\" \"abcdef\" \"g\"" \ + "$L\"abcdefg\"" \ + "concatenate three strings with empty $name string" + + gdb_test "print $L'a'" "= \[0-9\]+ $L'a'" \ + "basic $name character" +} + +if {$wchar_ok} { + test_wide_or_unicode L wide +} + +set ucs2_ok [expr {[get_sizeof char16_t 99] == 2}] +if {$ucs2_ok} { + test_wide_or_unicode u UCS-2 +} + +set ucs4_ok [expr {[get_sizeof char32_t 99] == 4}] +if {$ucs4_ok} { + test_wide_or_unicode U UCS-4 +} + +# Test an invalid string combination. +proc test_combination {L1 name1 L2 name2} { + gdb_test "print $L1\"abc\" $L2\"def\"" \ + "Undefined string concatenation." \ + "undefined concatenation of $name1 and $name2" +} + +if {$wchar_ok && $ucs2_ok} { + test_combination L wide u UCS-2 +} +if {$wchar_ok && $ucs4_ok} { + test_combination L wide U UCS-4 +} +if {$ucs2_ok && $ucs4_ok} { + test_combination u UCS-2 U UCS-4 +} + gdb_exit diff --git a/gdb/testsuite/gdb.base/constvars.exp b/gdb/testsuite/gdb.base/constvars.exp index d53a826..6d1bd12 100644 --- a/gdb/testsuite/gdb.base/constvars.exp +++ b/gdb/testsuite/gdb.base/constvars.exp @@ -161,7 +161,7 @@ proc do_constvar_tests {} { gdb_test "print laconic" " = 65 'A'" local_compiler_xfail_check gdb_test "ptype laconic" "type = const char" - gdb_test "print laggard" " = 1 '.001'" + gdb_test "print laggard" " = 1 '.1'" local_compiler_xfail_check gdb_test "ptype laggard" "type = const unsigned char" gdb_test "print lagoon" " = 2" @@ -209,7 +209,7 @@ proc do_constvar_tests {} { gdb_test "print *lewd" " = 65 'A'" local_compiler_xfail_check gdb_test "ptype lewd" "type = const char \\* const" - gdb_test "print *lexicographer" " = 1 '.001'" + gdb_test "print *lexicographer" " = 1 '.1'" local_compiler_xfail_check gdb_test "ptype lexicographer" "type = const unsigned char \\* const" gdb_test "print *lexicon" " = 2" @@ -233,7 +233,7 @@ proc do_constvar_tests {} { gdb_test "print *languish" " = 65 'A'" local_compiler_xfail_check gdb_test "ptype languish" "type = const char \\*" - gdb_test "print *languor" " = 1 '.001'" + gdb_test "print *languor" " = 1 '.1'" local_compiler_xfail_check gdb_test "ptype languor" "type = const unsigned char \\*" gdb_test "print *lank" " = 2" diff --git a/gdb/testsuite/gdb.base/display.exp b/gdb/testsuite/gdb.base/display.exp index d62e8bf..aa65373 100644 --- a/gdb/testsuite/gdb.base/display.exp +++ b/gdb/testsuite/gdb.base/display.exp @@ -180,8 +180,12 @@ gdb_test "printf \"%p\\n\", 1" "0x1" # play with "print", too # -gdb_test "print/r j" ".*Undefined output format.*" -gdb_test "print j" ".*" "debug test output" +gdb_test "print/z j" ".*Undefined output format.*" +gdb_test "print/d j" " = 0\[\\r\\n\]+" "debug test output 1" +gdb_test "print/r j" " = 0\[\\r\\n\]+" "debug test output 1a" +gdb_test "print/x j" " = 0x0\[\\r\\n\]+" "debug test output 2" +gdb_test "print/r j" " = 0x0\[\\r\\n\]+" "debug test output 2a" +gdb_test "print j" " = 0\[\\r\\n\]+" "debug test output 3" # x/0 j doesn't produce any output and terminates PA64 process when testing if [istarget "hppa2.0w-hp-hpux11*"] { diff --git a/gdb/testsuite/gdb.base/help.exp b/gdb/testsuite/gdb.base/help.exp index 4618a2c..40830c3 100644 --- a/gdb/testsuite/gdb.base/help.exp +++ b/gdb/testsuite/gdb.base/help.exp @@ -603,7 +603,7 @@ gdb_test "help stepi" "Step one instruction exactly\.\[\r\n\]+Argument N means d gdb_test "help signal" "Continue program giving it signal.*" "help signal" # test help source # vxgdb reads .vxgdbinit -gdb_test "help source" "Read commands from a file named FILE\.\[\r\n\]+Optional -v switch \\(before the filename\\) causes each command in\[\r\n\]+FILE to be echoed as it is executed\.\[\r\n\]+Note that the file \"\[^\"\]*\" is read automatically in this way\[\r\n\]+when GDB is started\." "help source" +gdb_test "help source" "Read commands from a file named FILE\.\[\r\n\]+Optional -v switch \\(before the filename\\) causes each command in\[\r\n\]+FILE to be echoed as it is executed\.\[\r\n\]+Note that the file \"\[^\"\]*\" is read automatically in this way\[\r\n\]+when GDB is started\.\[\r\n\]+Optional -p switch \\(before the filename\\) causes FILE to be evaluated\[\r\n\]+as Python code\." "help source" # test help stack test_class_help "stack" { "Examining the stack\..*\[\r\n\]+" diff --git a/gdb/testsuite/gdb.base/lineno-makeup-func.c b/gdb/testsuite/gdb.base/lineno-makeup-func.c new file mode 100644 index 0000000..1a0220e --- /dev/null +++ b/gdb/testsuite/gdb.base/lineno-makeup-func.c @@ -0,0 +1,21 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +void +func (void) +{ +} diff --git a/gdb/testsuite/gdb.base/lineno-makeup.c b/gdb/testsuite/gdb.base/lineno-makeup.c new file mode 100644 index 0000000..bb20e98 --- /dev/null +++ b/gdb/testsuite/gdb.base/lineno-makeup.c @@ -0,0 +1,35 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* DW_AT_low_pc-DW_AT_high_pc should cover the function without line number + information (.debug_line) so we cannot use an external object file. + + It must not be just a label as it would alias on the next function even for + correct GDB. Therefore some stub data must be placed there. + + We need to provide a real stub function body as at least s390 + (s390_analyze_prologue) would skip the whole body till reaching `main'. */ + +extern void func (void); +asm ("func: .incbin \"gdb.base/lineno-makeup-func.bin\""); + +int +main (void) +{ + func (); + return 0; +} diff --git a/gdb/testsuite/gdb.base/lineno-makeup.exp b/gdb/testsuite/gdb.base/lineno-makeup.exp new file mode 100644 index 0000000..0c75b84 --- /dev/null +++ b/gdb/testsuite/gdb.base/lineno-makeup.exp @@ -0,0 +1,78 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set testfile "lineno-makeup" +set srcfuncfile ${testfile}-func.c +set srcfile ${testfile}.c +set objfuncfile ${objdir}/${subdir}/${testfile}-func.o +set binfuncfile ${objdir}/${subdir}/${testfile}-func.bin +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfuncfile}" "${objfuncfile}" object {}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +set objcopy [catch "exec objcopy -O binary --only-section .text ${objfuncfile} ${binfuncfile}" output] +verbose -log "objcopy=$objcopy: $output" +if { $objcopy != 0 } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} +set binfuncfilesize [file size $binfuncfile] +verbose -log "file size $binfuncfile = $binfuncfilesize" + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +set b_addr "" +set test "break func" +gdb_test_multiple $test $test { + -re "Breakpoint \[0-9\]+ at (0x\[0-9a-f\]+)\r\n$gdb_prompt $" { + set b_addr $expect_out(1,string) + pass $test + } + -re "Breakpoint \[0-9\]+ at (0x\[0-9a-f\]+): .*\r\n$gdb_prompt $" { + set b_addr $expect_out(1,string) + fail $test + } +} +verbose -log "b_addr=<$b_addr>" + +set p_addr "" +set test "print func" +gdb_test_multiple $test $test { + -re "\\$\[0-9\]+ = {} (0x\[0-9a-f\]+) \r\n$gdb_prompt $" { + set p_addr $expect_out(1,string) + pass $test + } +} +verbose -log "p_addr=<$p_addr>" + +set test "break address belongs to func" +if {$b_addr == $p_addr} { + pass "$test (exact match)" +} else { + set skip [expr $b_addr - $p_addr] + if {$skip > 0 && $skip < $binfuncfilesize} { + pass "$test (prologue skip by $skip bytes)" + } else { + fail $test + } +} diff --git a/gdb/testsuite/gdb.base/long_long.exp b/gdb/testsuite/gdb.base/long_long.exp index d0ad5ba..5189324 100644 --- a/gdb/testsuite/gdb.base/long_long.exp +++ b/gdb/testsuite/gdb.base/long_long.exp @@ -210,7 +210,7 @@ gdb_test_char "p/o *(char *)c" "01" gdb_test_char "p/t *(char *)c" "1" gdb_test_char "p/a *(char *)c" "0x1( <.*>)?" gdb_test_char "p/f *(char *)c" "1" -gdb_test_char "p/c *(char *)c" "1 '.001'" +gdb_test_char "p/c *(char *)c" "1 '.1'" gdb_test_short "p/x *(short *)s" "" "0x123" "" gdb_test_short "p/d *(short *)s" "" "291" "" @@ -257,7 +257,7 @@ gdb_test "x/u w" "19088743" gdb_test "x/o w" "0110642547" gdb_test "x/t w" "00000001001000110100010101100111" gdb_test_xptr "x/a" { b "" } { h "" } { w "0x1234567" } { g "0x123456789abcdef" } -gdb_test "x/c b" "1 '.001'" +gdb_test "x/c b" "1 '.1'" if { $sizeof_double == 8 || $sizeof_long_double == 8 } { gdb_test "x/f &val.oct" "-5.9822653797615723e-120" } else { @@ -273,7 +273,7 @@ gdb_test "x/2u g" "81985529216486895.*12046818088235383159" gdb_test "x/2o g" "04432126361152746757.*01234567123456701234567" gdb_test "x/2t g" "0000000100100011010001010110011110001001101010111100110111101111.*1010011100101110111001010011100101110111000001010011100101110111" gdb_test_xptr "x/2a" { b "" } { h "" } { w "0x1234567.*0xa72ee539" } { g "0x123456789abcdef.*0xa72ee53977053977" } -gdb_test "x/2c b" "1 '.001'.*-89 '.'" +gdb_test "x/2c b" "1 '.1'.*-89 '.\[0-9\]*'" if { $sizeof_double == 8 || $sizeof_long_double == 8 } { gdb_test "x/2f &val.oct" "-5.9822653797615723e-120.*-5.9041889495880968e-100" } else { @@ -288,7 +288,7 @@ gdb_test "x/2bu b" "1.*167" gdb_test "x/2bo b" "01.*0247" gdb_test "x/2bt b" "00000001.*10100111" gdb_test_ptr "x/2ba b" "" "" "0x1.*0xffffffa7" "0x1.*0xffffffffffffffa7" -gdb_test "x/2bc b" "1 '.001'.*-89 '.'" +gdb_test "x/2bc b" "1 '.1'.*-89 '.\[0-9\]*'" gdb_test "x/2bf b" "1.*-89" gdb_test "x/2hx h" "0x0123.*0xa72e" @@ -315,7 +315,7 @@ gdb_test "x/2gu g" "81985529216486895.*12046818088235383159" gdb_test "x/2go g" "04432126361152746757.*01234567123456701234567" gdb_test "x/2gt g" "0000000100100011010001010110011110001001101010111100110111101111.*1010011100101110111001010011100101110111000001010011100101110111" gdb_test_ptr "x/2ga g" "" "" "0x89abcdef.*0x77053977" "0x123456789abcdef.*0xa72ee53977053977" -gdb_test "x/2gc g" "-17 '.'.*119 'w'" +gdb_test "x/2gc g" "-17 '.\[0-9\]*'.*119 'w'" gdb_test "x/2gf g" "3.5127005640885037e-303.*-5.9822653797615723e-120" gdb_exit diff --git a/gdb/testsuite/gdb.base/macscp.exp b/gdb/testsuite/gdb.base/macscp.exp index 7086e90..dd196d7 100644 --- a/gdb/testsuite/gdb.base/macscp.exp +++ b/gdb/testsuite/gdb.base/macscp.exp @@ -26,13 +26,21 @@ set testfile "macscp" set objfile ${objdir}/${subdir}/${testfile}.o set binfile ${objdir}/${subdir}/${testfile} -set options { debug } +set options { debug additional_flags=-DFROM_COMMANDLINE=ARG} get_compiler_info ${binfile} if [test_compiler_info gcc*] { lappend options additional_flags=-g3 } +# Workaround ccache making lineno non-zero for command-line definitions. +if {[find_gcc] == "gcc" && [file executable "/usr/bin/gcc"]} { + set result [catch "exec which gcc" output] + if {$result == 0 && [string first "/ccache/" $output] >= -1} { + lappend options "compiler=/usr/bin/gcc" + } +} + # Generate the intermediate object file. This is required by Darwin to # have access to the .debug_macinfo section. if {[gdb_compile "${srcdir}/${subdir}/macscp1.c" "${objfile}" \ @@ -79,11 +87,15 @@ proc info_macro {macro} { if {$debug_me} {exp_internal 1} gdb_expect { - -re "Defined at \[^\r\n\]*(${filepat}):${decimal}\[\r\n\]" { + -re "Defined at \[^\r\n\]*(${filepat}):(${decimal})\[\r\n\]" { # `location' and `definition' should be empty when we see # this message. if {[llength $location] == 0 && [llength $definition] == 0} { set location $expect_out(1,string) + # Definitions from gcc command-line get suffixed by the lineno. + if {$expect_out(2,string) == "0" } { + set location "$location:$expect_out(2,string)" + } exp_continue } else { # Exit this expect loop, with a result indicating failure. @@ -198,6 +210,8 @@ proc list_and_check_macro {func macro expected} { } +list_and_check_macro main FROM_COMMANDLINE "macscp1.c:0 ARG" + if {[list_and_check_macro main WHERE {macscp1.c {before macscp1_3}}]} { return 0 } diff --git a/gdb/testsuite/gdb.base/nodebug.exp b/gdb/testsuite/gdb.base/nodebug.exp index 4c01be4..31fb88e 100644 --- a/gdb/testsuite/gdb.base/nodebug.exp +++ b/gdb/testsuite/gdb.base/nodebug.exp @@ -215,5 +215,12 @@ if [runto inner] then { if [runto middle] then { gdb_test "backtrace 10" "#0.*middle.*#1.*top.*#2.*main.*" \ "backtrace from middle in nodebug.exp" + + # Test return from a function with no debug info (symbol; still it may + # have a minimal-symbol). In gdb.base/return*.exp we would need to + # build a separate executable with no "debug" option. + gdb_test "return 0" "#0 .* top \\(.*" \ + "return from function with no debug info" \ + "Make selected stack frame return now\\? \\(y or n\\) " "y" } } diff --git a/gdb/testsuite/gdb.base/pointers.exp b/gdb/testsuite/gdb.base/pointers.exp index 91838a2..2d0a70e 100644 --- a/gdb/testsuite/gdb.base/pointers.exp +++ b/gdb/testsuite/gdb.base/pointers.exp @@ -389,7 +389,7 @@ gdb_expect { send_gdb "print *pUC\n" gdb_expect { - -re ".\[0-9\]* = 21 \'.025\'.*$gdb_prompt $" { + -re ".\[0-9\]* = 21 \'.25\'.*$gdb_prompt $" { pass "print value of *pUC" } -re ".*$gdb_prompt $" { fail "print value of *pUC" } diff --git a/gdb/testsuite/gdb.base/printcmds.exp b/gdb/testsuite/gdb.base/printcmds.exp index 1e17da4..b6f8a1f 100644 --- a/gdb/testsuite/gdb.base/printcmds.exp +++ b/gdb/testsuite/gdb.base/printcmds.exp @@ -137,12 +137,12 @@ proc test_print_all_chars {} { global gdb_prompt gdb_test "p ctable1\[0\]" " = 0 '\\\\0'" - gdb_test "p ctable1\[1\]" " = 1 '\\\\001'" - gdb_test "p ctable1\[2\]" " = 2 '\\\\002'" - gdb_test "p ctable1\[3\]" " = 3 '\\\\003'" - gdb_test "p ctable1\[4\]" " = 4 '\\\\004'" - gdb_test "p ctable1\[5\]" " = 5 '\\\\005'" - gdb_test "p ctable1\[6\]" " = 6 '\\\\006'" + gdb_test "p ctable1\[1\]" " = 1 '\\\\1'" + gdb_test "p ctable1\[2\]" " = 2 '\\\\2'" + gdb_test "p ctable1\[3\]" " = 3 '\\\\3'" + gdb_test "p ctable1\[4\]" " = 4 '\\\\4'" + gdb_test "p ctable1\[5\]" " = 5 '\\\\5'" + gdb_test "p ctable1\[6\]" " = 6 '\\\\6'" gdb_test "p ctable1\[7\]" " = 7 '\\\\a'" gdb_test "p ctable1\[8\]" " = 8 '\\\\b'" gdb_test "p ctable1\[9\]" " = 9 '\\\\t'" @@ -150,24 +150,24 @@ proc test_print_all_chars {} { gdb_test "p ctable1\[11\]" " = 11 '\\\\v'" gdb_test "p ctable1\[12\]" " = 12 '\\\\f'" gdb_test "p ctable1\[13\]" " = 13 '\\\\r'" - gdb_test "p ctable1\[14\]" " = 14 '\\\\016'" - gdb_test "p ctable1\[15\]" " = 15 '\\\\017'" - gdb_test "p ctable1\[16\]" " = 16 '\\\\020'" - gdb_test "p ctable1\[17\]" " = 17 '\\\\021'" - gdb_test "p ctable1\[18\]" " = 18 '\\\\022'" - gdb_test "p ctable1\[19\]" " = 19 '\\\\023'" - gdb_test "p ctable1\[20\]" " = 20 '\\\\024'" - gdb_test "p ctable1\[21\]" " = 21 '\\\\025'" - gdb_test "p ctable1\[22\]" " = 22 '\\\\026'" - gdb_test "p ctable1\[23\]" " = 23 '\\\\027'" - gdb_test "p ctable1\[24\]" " = 24 '\\\\030'" - gdb_test "p ctable1\[25\]" " = 25 '\\\\031'" - gdb_test "p ctable1\[26\]" " = 26 '\\\\032'" - gdb_test "p ctable1\[27\]" " = 27 '\\\\033'" - gdb_test "p ctable1\[28\]" " = 28 '\\\\034'" - gdb_test "p ctable1\[29\]" " = 29 '\\\\035'" - gdb_test "p ctable1\[30\]" " = 30 '\\\\036'" - gdb_test "p ctable1\[31\]" " = 31 '\\\\037'" + gdb_test "p ctable1\[14\]" " = 14 '\\\\16'" + gdb_test "p ctable1\[15\]" " = 15 '\\\\17'" + gdb_test "p ctable1\[16\]" " = 16 '\\\\20'" + gdb_test "p ctable1\[17\]" " = 17 '\\\\21'" + gdb_test "p ctable1\[18\]" " = 18 '\\\\22'" + gdb_test "p ctable1\[19\]" " = 19 '\\\\23'" + gdb_test "p ctable1\[20\]" " = 20 '\\\\24'" + gdb_test "p ctable1\[21\]" " = 21 '\\\\25'" + gdb_test "p ctable1\[22\]" " = 22 '\\\\26'" + gdb_test "p ctable1\[23\]" " = 23 '\\\\27'" + gdb_test "p ctable1\[24\]" " = 24 '\\\\30'" + gdb_test "p ctable1\[25\]" " = 25 '\\\\31'" + gdb_test "p ctable1\[26\]" " = 26 '\\\\32'" + gdb_test "p ctable1\[27\]" " = 27 '\\\\33'" + gdb_test "p ctable1\[28\]" " = 28 '\\\\34'" + gdb_test "p ctable1\[29\]" " = 29 '\\\\35'" + gdb_test "p ctable1\[30\]" " = 30 '\\\\36'" + gdb_test "p ctable1\[31\]" " = 31 '\\\\37'" gdb_test "p ctable1\[32\]" " = 32 ' '" gdb_test "p ctable1\[33\]" " = 33 '!'" gdb_test "p ctable1\[34\]" " = 34 '\"'" @@ -475,13 +475,13 @@ proc test_print_strings {} { gdb_test "p &ctable1\[0\]" \ " = \\(unsigned char \\*\\) \"\"" gdb_test "p &ctable1\[1\]" \ - " = \\(unsigned char \\*\\) \"\\\\001\\\\002\\\\003\\\\004\\\\005\\\\006\\\\a\\\\b\"..." + " = \\(unsigned char \\*\\) \"\\\\1\\\\2\\\\3\\\\4\\\\5\\\\6\\\\a\\\\b\"..." gdb_test "p &ctable1\[1*8\]" \ - " = \\(unsigned char \\*\\) \"\\\\b\\\\t\\\\n\\\\v\\\\f\\\\r\\\\016\\\\017\"..." + " = \\(unsigned char \\*\\) \"\\\\b\\\\t\\\\n\\\\v\\\\f\\\\r\\\\16\\\\17\"..." gdb_test "p &ctable1\[2*8\]" \ - " = \\(unsigned char \\*\\) \"\\\\020\\\\021\\\\022\\\\023\\\\024\\\\025\\\\026\\\\027\"..." + " = \\(unsigned char \\*\\) \"\\\\20\\\\21\\\\22\\\\23\\\\24\\\\25\\\\26\\\\27\"..." gdb_test "p &ctable1\[3*8\]" \ - " = \\(unsigned char \\*\\) \"\\\\030\\\\031\\\\032\\\\033\\\\034\\\\035\\\\036\\\\037\"..." + " = \\(unsigned char \\*\\) \"\\\\30\\\\31\\\\32\\\\33\\\\34\\\\35\\\\36\\\\37\"..." gdb_test "p &ctable1\[4*8\]" \ " = \\(unsigned char \\*\\) \" !\\\\\"#\\\$%&'\"..." gdb_test "p &ctable1\[5*8\]" \ @@ -622,7 +622,7 @@ proc test_print_string_constants {} { set timeout 60; gdb_test "p \"a string\"" " = \"a string\"" - gdb_test "p \"embedded \\000 null\"" " = \"embedded \\\\000 null\"" + gdb_test "p \"embedded \\000 null\"" " = \"embedded \\\\0 null\"" gdb_test "p \"abcd\"\[2\]" " = 99 'c'" gdb_test "p sizeof (\"abcdef\")" " = 7" gdb_test "ptype \"foo\"" " = char \\\[4\\\]" diff --git a/gdb/testsuite/gdb.base/return-nodebug.c b/gdb/testsuite/gdb.base/return-nodebug.c new file mode 100644 index 0000000..e1211b3 --- /dev/null +++ b/gdb/testsuite/gdb.base/return-nodebug.c @@ -0,0 +1,49 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +static TYPE +init (void) +{ + return 0; +} + +static TYPE +func (void) +{ + return 31; +} + +static void +marker (void) +{ +} + +int +main (void) +{ + /* Preinitialize registers to 0 to avoid false PASS by leftover garbage. */ + init (); + + printf ("result=" FORMAT "\n", CAST func ()); + + /* Cannot `next' with no debug info. */ + marker (); + + return 0; +} diff --git a/gdb/testsuite/gdb.base/return-nodebug.exp b/gdb/testsuite/gdb.base/return-nodebug.exp new file mode 100644 index 0000000..6f32aa9 --- /dev/null +++ b/gdb/testsuite/gdb.base/return-nodebug.exp @@ -0,0 +1,54 @@ +# 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 . + +proc do_test {type} { + set typenospace [string map {{ } -} $type] + + global pf_prefix + set old_prefix $pf_prefix + lappend pf_prefix "$typenospace:" + + if {[runto "func"]} { + # Test return from a function with no debug info (symbol; still it may + # have a minimal-symbol) if it does not crash. + gdb_test "return -1" "#0 .* main \\(.*" \ + "return from function with no debug info" \ + "Make selected stack frame return now\\? \\(y or n\\) " "y" + + # And if it returned the full width of the result. + gdb_test "adv marker" "\r\nresult=-1\r\n.* in marker \\(.*" \ + "full width of the returned result" + } + + set pf_prefix $old_prefix +} + +foreach case {{{signed char} %d (int)} \ + {{short} %d (int)} \ + {{int} %d} \ + {{long} %ld} \ + {{long long} %lld}} { + set type [lindex $case 0] + set format [lindex $case 1] + set cast [lindex $case 2] + + set typeesc [string map {{ } {\ }} $type] + set typenospace [string map {{ } -} $type] + + if {[prepare_for_testing return-nodebug.exp "return-nodebug-$typenospace" "return-nodebug.c" \ + [list "additional_flags=-DFORMAT=\"$format\" -DTYPE=$typeesc -DCAST=$cast"]] == 0} { + do_test $type + } +} diff --git a/gdb/testsuite/gdb.base/setvar.exp b/gdb/testsuite/gdb.base/setvar.exp index 2350a33..3be8424 100644 --- a/gdb/testsuite/gdb.base/setvar.exp +++ b/gdb/testsuite/gdb.base/setvar.exp @@ -121,7 +121,7 @@ proc test_set { args } { # test_set "set variable v_char=0" "print v_char" ".\[0-9\]* = 0 \'.0\'" "set variable char=0" -test_set "set variable v_char=1" "print v_char" ".\[0-9\]* = 1 \'.001\'" "set variable char=1" +test_set "set variable v_char=1" "print v_char" ".\[0-9\]* = 1 \'.1\'" "set variable char=1" test_set "set variable v_char=7" "print v_char" ".\[0-9\]* = 7 \'.a\'" "set variable char=7 (Bel)" test_set "set variable v_char=32" "print v_char" ".\[0-9\]* = 32 \' \'" "set variable char=32 (SPC)" test_set "set variable v_char=65" "print v_char" ".\[0-9\]* = 65 \'A\'" "set variable char=65 ('A')" @@ -132,7 +132,7 @@ test_set "set variable v_char=127" "print v_char" ".\[0-9\]* = 127 \'.177\'" # test "set variable" for type "signed char" # test_set "set variable v_char=0" "print v_signed_char" ".\[0-9\]* = 0 \'.0\'" "set variable signed char=0" -test_set "set variable v_signed_char=1" "print v_signed_char" ".\[0-9\]* = 1 \'.001\'" "set variable signed char=1" +test_set "set variable v_signed_char=1" "print v_signed_char" ".\[0-9\]* = 1 \'.1\'" "set variable signed char=1" test_set "set variable v_signed_char=7" "print v_signed_char" ".\[0-9\]* = 7 \'.a\'" "set variable signed char=7 (Bel)" test_set "set variable v_signed_char=32" "print v_signed_char" ".\[0-9\]* = 32 \' \'" "set variable signed char=32 (SPC)" test_set "set variable v_signed_char=65" "print v_signed_char" ".\[0-9\]* = 65 \'A\'" "set variable signed char=65 ('A')" @@ -151,7 +151,7 @@ gdb_test "print v_signed_char" ".\[0-9\]* = -1 \'.377\'" \ # test "set variable" for type "unsigned char" # test_set "set variable v_unsigned_char=0" "print v_unsigned_char" ".\[0-9\]* = 0 \'.0\'" "set variable unsigned char=0" -test_set "set variable v_unsigned_char=1" "print v_unsigned_char" ".\[0-9\]* = 1 \'.001\'" "set variable unsigned char=1" +test_set "set variable v_unsigned_char=1" "print v_unsigned_char" ".\[0-9\]* = 1 \'.1\'" "set variable unsigned char=1" test_set "set variable v_unsigned_char=7" "print v_unsigned_char" ".\[0-9\]* = 7 \'.a\'" "set variable unsigned char=7 (Bel)" test_set "set variable v_unsigned_char=32" "print v_unsigned_char" ".\[0-9\]* = 32 \' \'" "set variable unsigned char=32 (SPC)" test_set "set variable v_unsigned_char=65" "print v_unsigned_char" ".\[0-9\]* = 65 \'A\'" "set variable unsigned char=65 ('A')" diff --git a/gdb/testsuite/gdb.base/store.exp b/gdb/testsuite/gdb.base/store.exp index 963bb19..feab6bd 100644 --- a/gdb/testsuite/gdb.base/store.exp +++ b/gdb/testsuite/gdb.base/store.exp @@ -74,7 +74,7 @@ proc check_set { t l r new add } { "${prefix}; print incremented l, expecting ${add}" } -check_set "charest" "-1 .*" "-2 .*" "4 ..004." "2 ..002." +check_set "charest" "-1 .*" "-2 .*" "4 ..4." "2 ..2." check_set "short" "-1" "-2" "4" "2" check_set "int" "-1" "-2" "4" "2" check_set "long" "-1" "-2" "4" "2" @@ -102,7 +102,7 @@ proc up_set { t l r new } { "${prefix}; print new l, expecting ${new}" } -up_set "charest" "-1 .*" "-2 .*" "4 ..004." +up_set "charest" "-1 .*" "-2 .*" "4 ..4." up_set "short" "-1" "-2" "4" up_set "int" "-1" "-2" "4" up_set "long" "-1" "-2" "4" diff --git a/gdb/testsuite/gdb.base/valgrind-attach.c b/gdb/testsuite/gdb.base/valgrind-attach.c new file mode 100644 index 0000000..84b57db --- /dev/null +++ b/gdb/testsuite/gdb.base/valgrind-attach.c @@ -0,0 +1,28 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +int +main (void) +{ + int *a = malloc (1); + + a[10] = 0; /* crash-here */ + + return 0; +} diff --git a/gdb/testsuite/gdb.base/valgrind-attach.exp b/gdb/testsuite/gdb.base/valgrind-attach.exp new file mode 100644 index 0000000..1f9b26e --- /dev/null +++ b/gdb/testsuite/gdb.base/valgrind-attach.exp @@ -0,0 +1,94 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set testfile valgrind-attach +set shfile ${testfile}.sh +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_stop_suppressing_tests; + +set VALGRIND "valgrind" + +# Syntax for ${shfile} is: +set VALGRIND_SPAWN "sh ${srcdir}/${subdir}/${shfile} $binfile $VALGRIND $GDB $INTERNAL_GDBFLAGS $GDBFLAGS [host_info gdb_opts]" + +set test "spawn valgrind" +verbose "Spawning $VALGRIND_SPAWN" + +if [info exists gdb_spawn_id] { + fail $test + return -1 +} + +if ![is_remote host] { + if { [which $VALGRIND] == 0 } then { + untested "Couldn't find $VALGRIND" + return -1 + } +} +set res [remote_spawn host "$VALGRIND_SPAWN"] +if { $res < 0 || $res == "" } { + perror "Spawning $VALGRIND_SPAWN failed." + return -1 +} +set gdb_spawn_id -1; + +gdb_expect { + -re "---- Attach to debugger \\? --- \\\[Return/N/n/Y/y/C/c\\\] ---- $" { + pass $test + } + eof { + perror "(eof) $VALGRIND never initialized" + remote_close host + return -1 + } + timeout { + perror "(timeout) $VALGRIND never initialized" + remote_close host + return -1 + } +} +send_gdb "y\n" + +set test "spawn gdb" +set test2 "crash line caught" +gdb_expect { + -re "starting debugger with cmd:.* in main .* crash-here .*\[\r\n\]$gdb_prompt $" { + pass $test + pass $test2 + } + -re "starting debugger with cmd:.*\[\r\n\]$gdb_prompt $" { + pass $test + fail $test2 + } + eof { + perror "(eof) $GDB never initialized" + remote_close host + return -1 + } + timeout { + perror "(timeout) $GDB never initialized" + remote_close host + return -1 + } +} + +remote_close host diff --git a/gdb/testsuite/gdb.base/valgrind-attach.sh b/gdb/testsuite/gdb.base/valgrind-attach.sh new file mode 100755 index 0000000..f02c6f7 --- /dev/null +++ b/gdb/testsuite/gdb.base/valgrind-attach.sh @@ -0,0 +1,20 @@ +#! /bin/sh + +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +BINFILE="$1"; shift +VALGRIND="$1"; shift +"$VALGRIND" --db-attach=yes --db-command="$* %f %p" "$BINFILE" diff --git a/gdb/testsuite/gdb.base/vla-overflow.c b/gdb/testsuite/gdb.base/vla-overflow.c new file mode 100644 index 0000000..c5d5ee0 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla-overflow.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +int +main (int argc, char **argv) +{ + int array[argc]; + + array[0] = array[0]; + + abort (); + + return 0; +} diff --git a/gdb/testsuite/gdb.base/vla-overflow.exp b/gdb/testsuite/gdb.base/vla-overflow.exp new file mode 100644 index 0000000..7203a48 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla-overflow.exp @@ -0,0 +1,108 @@ +# Copyright 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# We could crash in: +# #0 block_linkage_function (bl=0x0) at ../../gdb/block.c:69 +# #1 in dwarf_block_get_frame_base (...) at ../../gdb/dwarf2block.c:97 +# 97 framefunc = block_linkage_function (get_frame_block (frame, NULL)); +# #2 in execute_stack_op (...) at ../../gdb/dwarf2expr.c:496 +# #3 in dwarf_block_exec_core () at ../../gdb/dwarf2block.c:156 +# #4 dwarf_block_exec (...) at ../../gdb/dwarf2block.c:206 +# #5 in range_type_count_bound_internal (...) at ../../gdb/gdbtypes.c:1430 +# #6 in create_array_type (...) at ../../gdb/gdbtypes.c:840 +# ... +# #21 in psymtab_to_symtab (...) at ../../gdb/symfile.c:292 +# ... +# #29 in backtrace_command_1 () at ../../gdb/stack.c:1273 + +set testfile vla-overflow +set shfile ${objdir}/${subdir}/${testfile}-gdb.sh +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +set f [open "|getconf PAGESIZE" "r"] +gets $f pagesize +close $f + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +set pid_of_gdb [exp_pid -i [board_info host fileid]] + +if { [runto_main] < 0 } { + untested vla-overflow + return -1 +} + +# Get the GDB memory size when we stay at main. + +proc memory_v_pages_get {} { + global pid_of_gdb pagesize + set fd [open "/proc/$pid_of_gdb/statm"] + gets $fd line + close $fd + # number of pages of virtual memory + scan $line "%d" drs + return $drs +} + +set pages_found [memory_v_pages_get] + +set mb_reserve 10 +verbose -log "pages_found = $pages_found, mb_reserve = $mb_reserve" +set kb_found [expr $pages_found * $pagesize / 1024] +set kb_permit [expr $kb_found + 1 * 1024 + $mb_reserve * 1024] +verbose -log "kb_found = $kb_found, kb_permit = $kb_permit" + +# Create the ulimit wrapper. +set f [open $shfile "w"] +puts $f "#! /bin/sh" +puts $f "ulimit -v $kb_permit" +puts $f "exec $GDB \"\$@\"" +close $f +remote_exec host "chmod +x $shfile" + +gdb_exit +set GDBold $GDB +set GDB "$shfile" +gdb_start +set GDB $GDBold + +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +set pid_of_gdb [exp_pid -i [board_info host fileid]] + +# Check the size again after the second run. +# We must not stop in main as it would cache `array' and never crash later. + +gdb_run_cmd + +verbose -log "kb_found before abort() = [expr [memory_v_pages_get] * $pagesize / 1024]" + +gdb_test "" "Program received signal SIGABRT, Aborted..*" "Enter abort()" + +verbose -log "kb_found in abort() = [expr [memory_v_pages_get] * $pagesize / 1024]" + +# `abort' can get expressed as `*__GI_abort'. +gdb_test "bt" "in \[^ \]*abort \\(.* in main \\(.*" "Backtrace after abort()" + +verbose -log "kb_found in bt after abort() = [expr [memory_v_pages_get] * $pagesize / 1024]" diff --git a/gdb/testsuite/gdb.base/vla.c b/gdb/testsuite/gdb.base/vla.c new file mode 100644 index 0000000..e1f3ed1 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla.c @@ -0,0 +1,55 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +void +marker (void) +{ +} + +void +bar (char *a, char *b, char *c, int size) +{ + memset (a, '1', size); + memset (b, '2', size); + memset (c, '3', 48); +} + +void +foo (int size) +{ + char temp1[size]; + char temp3[48]; + + temp1[size - 1] = '\0'; + { + char temp2[size]; + + bar (temp1, temp2, temp3, size); + + marker (); /* break-here */ + } +} + +int +main (void) +{ + foo (26); + foo (78); + return 0; +} diff --git a/gdb/testsuite/gdb.base/vla.exp b/gdb/testsuite/gdb.base/vla.exp new file mode 100644 index 0000000..5da7378 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla.exp @@ -0,0 +1,62 @@ +# Copyright 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set testfile vla +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] { + untested vla + return -1 +} + +gdb_breakpoint [gdb_get_line_number "break-here"] + +gdb_continue_to_breakpoint "break-here" + +gdb_test "whatis temp1" "type = char \\\[variable\\\]" "first: whatis temp1" +gdb_test "whatis temp2" "type = char \\\[variable\\\]" "first: whatis temp2" +gdb_test "whatis temp3" "type = char \\\[48\\\]" "first: whatis temp3" + +gdb_test "ptype temp1" "type = char \\\[26\\\]" "first: ptype temp1" +gdb_test "ptype temp2" "type = char \\\[26\\\]" "first: ptype temp2" +gdb_test "ptype temp3" "type = char \\\[48\\\]" "first: ptype temp3" + +gdb_test "p temp1" " = '1' " "first: print temp1" +gdb_test "p temp2" " = '2' " "first: print temp2" +gdb_test "p temp3" " = '3' " "first: print temp3" + +gdb_continue_to_breakpoint "break-here" + +gdb_test "whatis temp1" "type = char \\\[variable\\\]" "second: whatis temp1" +gdb_test "whatis temp2" "type = char \\\[variable\\\]" "second: whatis temp2" +gdb_test "whatis temp3" "type = char \\\[48\\\]" "second: whatis temp3" + +gdb_test "ptype temp1" "type = char \\\[78\\\]" "second: ptype temp1" +gdb_test "ptype temp2" "type = char \\\[78\\\]" "second: ptype temp2" +gdb_test "ptype temp3" "type = char \\\[48\\\]" "second: ptype temp3" + +gdb_test "p temp1" " = '1' " "second: print temp1" +gdb_test "p temp2" " = '2' " "second: print temp2" +gdb_test "p temp3" " = '3' " "second: print temp3" diff --git a/gdb/testsuite/gdb.cp/Makefile.in b/gdb/testsuite/gdb.cp/Makefile.in index 1787ad5..391bfc2 100644 --- a/gdb/testsuite/gdb.cp/Makefile.in +++ b/gdb/testsuite/gdb.cp/Makefile.in @@ -4,7 +4,7 @@ srcdir = @srcdir@ EXECUTABLES = ambiguous annota2 anon-union cplusfuncs cttiadd \ derivation inherit local member-ptr method misc \ overload ovldbreak ref-typ ref-typ2 templates userdef virtfunc namespace \ - ref-types ref-params method2 pr9594 + ref-types ref-params method2 pr9594 gdb2495 all info install-info dvi install uninstall installcheck check: @echo "Nothing to be done for $@..." diff --git a/gdb/testsuite/gdb.cp/abstract-origin.cc b/gdb/testsuite/gdb.cp/abstract-origin.cc new file mode 100644 index 0000000..e2de3fb --- /dev/null +++ b/gdb/testsuite/gdb.cp/abstract-origin.cc @@ -0,0 +1,42 @@ +/* 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 . + */ + +extern void f (int *); + +class A +{ +public: + A(int i); +}; + +A::A(int i) +{ + static int *problem = new int(i); + f (problem); /* break-here */ +} + +void f (int *) +{ +} + +int +main (void) +{ + A a(42); + return 0; +} diff --git a/gdb/testsuite/gdb.cp/abstract-origin.exp b/gdb/testsuite/gdb.cp/abstract-origin.exp new file mode 100644 index 0000000..92cc23c --- /dev/null +++ b/gdb/testsuite/gdb.cp/abstract-origin.exp @@ -0,0 +1,40 @@ +# Copyright 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set testfile abstract-origin +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +# Get things started. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] { + untested abstract-origin + return -1 +} + +gdb_breakpoint [gdb_get_line_number "break-here"] +gdb_continue_to_breakpoint "break-here" + +# The Bug was: No symbol "problem" in current context. +gdb_test "p problem" " = \\(int \\*\\) 0x.*" diff --git a/gdb/testsuite/gdb.cp/cplusfuncs.cc b/gdb/testsuite/gdb.cp/cplusfuncs.cc index 7f033d6..1a50a32 100644 --- a/gdb/testsuite/gdb.cp/cplusfuncs.cc +++ b/gdb/testsuite/gdb.cp/cplusfuncs.cc @@ -191,6 +191,12 @@ char * dm_type_char_star (char * p) { return p; } int dm_type_foo_ref (foo & foo) { return foo.ifoo; } int * dm_type_int_star (int * p) { return p; } long * dm_type_long_star (long * p) { return p; } +int dm_type_short (short i) { return i; } +int dm_type_long (long i) { return i; } int dm_type_unsigned_int (unsigned int i) { return i; } +int dm_type_unsigned_short (unsigned short i) { return i; } +int dm_type_unsigned_long (unsigned long i) { return i; } int dm_type_void (void) { return 0; } void * dm_type_void_star (void * p) { return p; } +typedef int myint; +int dm_type_typedef (myint i) { return i; } diff --git a/gdb/testsuite/gdb.cp/cplusfuncs.exp b/gdb/testsuite/gdb.cp/cplusfuncs.exp index 5e08768..8c8e038 100644 --- a/gdb/testsuite/gdb.cp/cplusfuncs.exp +++ b/gdb/testsuite/gdb.cp/cplusfuncs.exp @@ -66,9 +66,25 @@ set dm_type_unsigned_int "unsigned" set dm_type_void "" set dm_type_void_star "void*" +# Some other vagaries of GDB's type printing machinery. The integer types +# may have unsigned before or after their length, and may have "int" +# appended. The char* conversion operator may have name "char*" even if +# the type is "char *", because the name comes from the debug information +# and the type from GDB. Function types may not see through typedefs. + +set dm_type_short "short" +set dm_type_long "long" +set dm_type_unsigned_short "unsigned short" +set dm_type_unsigned_long "unsigned long" +set dm_operator_char_star "char*" +set dm_operator_char_star_quoted "char\\*" +set dm_type_typedef 0 + proc probe_demangler { } { global gdb_prompt global dm_operator_comma + global dm_operator_char_star + global dm_operator_char_star_quoted global dm_type_char_star global dm_type_char_star_quoted global dm_type_foo_ref @@ -77,6 +93,11 @@ proc probe_demangler { } { global dm_type_unsigned_int global dm_type_void global dm_type_void_star + global dm_type_short + global dm_type_unsigned_short + global dm_type_long + global dm_type_unsigned_long + global dm_type_typedef send_gdb "print &'foo::operator,(foo&)'\n" gdb_expect { @@ -97,6 +118,26 @@ proc probe_demangler { } { } } + send_gdb "print &'foo::operator char*()'\n" + gdb_expect { + -re ".*foo::operator char \\*\\(void\\).*\r\n$gdb_prompt $" { + # v2 demangler or GDB type printer + set dm_operator_char_star "char *" + set dm_operator_char_star_quoted "char \\*" + pass "detect dm_operator_char_star" + } + -re ".*foo::operator char\\*\\(\\).*\r\n$gdb_prompt $" { + # v3 demangler + pass "detect dm_operator_char_star" + } + -re ".*$gdb_prompt $" { + fail "detect dm_operator_char_star" + } + timeout { + fail "detect dm_operator_char_star" + } + } + send_gdb "print &'dm_type_char_star'\n" gdb_expect { -re ".*dm_type_char_star\\(char \\*\\).*\r\n$gdb_prompt $" { @@ -166,6 +207,11 @@ proc probe_demangler { } { # v3 demangler pass "detect dm_type_long_star" } + -re ".*dm_type_long_star\\(long int \\*\\).*\r\n$gdb_prompt $" { + # GCC v3 and GDB's type printer + set dm_type_long_star "long int *" + pass "detect dm_type_long_star" + } -re ".*$gdb_prompt $" { fail "detect dm_type_long_star" } @@ -230,6 +276,101 @@ proc probe_demangler { } { fail "detect dm_type_void_star (timeout)" } } + + send_gdb "print &'dm_type_short'\n" + gdb_expect { + -re ".*dm_type_short\\(short\\).*\r\n$gdb_prompt $" { + # v2 and v3 demanglers + pass "detect dm_type_short" + } + -re ".*dm_type_short\\(short int\\).*\r\n$gdb_prompt $" { + # GDB type printer + set dm_type_short "short int" + pass "detect dm_type_short" + } + -re ".*$gdb_prompt $" { + fail "detect dm_type_short" + } + timeout { + fail "detect dm_type_short (timeout)" + } + } + + send_gdb "print &'dm_type_unsigned_short'\n" + gdb_expect { + -re ".*dm_type_unsigned_short\\(unsigned short\\).*\r\n$gdb_prompt $" { + # v2 and v3 demanglers + pass "detect dm_type_unsigned_short" + } + -re ".*dm_type_unsigned_short\\(short unsigned int\\).*\r\n$gdb_prompt $" { + # GDB type printer + set dm_type_unsigned_short "short unsigned int" + pass "detect dm_type_unsigned_short" + } + -re ".*$gdb_prompt $" { + fail "detect dm_type_unsigned_short" + } + timeout { + fail "detect dm_type_unsigned_short (timeout)" + } + } + + send_gdb "print &'dm_type_long'\n" + gdb_expect { + -re ".*dm_type_long\\(long\\).*\r\n$gdb_prompt $" { + # v2 and v3 demanglers + pass "detect dm_type_long" + } + -re ".*dm_type_long\\(long int\\).*\r\n$gdb_prompt $" { + # GDB type printer + set dm_type_long "long int" + pass "detect dm_type_long" + } + -re ".*$gdb_prompt $" { + fail "detect dm_type_long" + } + timeout { + fail "detect dm_type_long (timeout)" + } + } + + send_gdb "print &'dm_type_unsigned_long'\n" + gdb_expect { + -re ".*dm_type_unsigned_long\\(unsigned long\\).*\r\n$gdb_prompt $" { + # v2 and v3 demanglers + pass "detect dm_type_unsigned_long" + } + -re ".*dm_type_unsigned_long\\(long unsigned int\\).*\r\n$gdb_prompt $" { + # GDB type printer + set dm_type_unsigned_long "long unsigned int" + pass "detect dm_type_unsigned_long" + } + -re ".*$gdb_prompt $" { + fail "detect dm_type_unsigned_long" + } + timeout { + fail "detect dm_type_unsigned_long (timeout)" + } + } + + send_gdb "print &'dm_type_typedef'\n" + gdb_expect { + -re ".*dm_type_typedef\\(int\\).*\r\n$gdb_prompt $" { + # v2 and v3 demanglers + pass "detect dm_type_typedef" + } + -re ".*dm_type_typedef\\(myint\\).*\r\n$gdb_prompt $" { + # GDB type printer + set dm_type_typedef 1 + pass "detect dm_type_typedef" + } + -re ".*$gdb_prompt $" { + fail "detect dm_type_typedef" + } + timeout { + fail "detect dm_type_typedef (timeout)" + } + } } # @@ -345,8 +486,9 @@ proc print_addr { name } { proc test_lookup_operator_functions {} { global dm_operator_comma + global dm_operator_char_star global dm_type_char_star - global dm_type_char_star_quoted + global dm_operator_char_star_quoted global dm_type_foo_ref global dm_type_void global dm_type_void_star @@ -404,8 +546,8 @@ proc test_lookup_operator_functions {} { info_func "operator int(" "int foo::operator int($dm_type_void);" info_func "operator()(" "void foo::operator()($dm_type_foo_ref);" - info_func "operator $dm_type_char_star_quoted\(" \ - "char *foo::operator $dm_type_char_star\($dm_type_void);" + info_func "operator $dm_operator_char_star_quoted\(" \ + "char *foo::operator $dm_operator_char_star\($dm_type_void);" } @@ -420,6 +562,7 @@ proc test_paddr_operator_functions {} { global dm_type_unsigned_int global dm_type_void global dm_type_void_star + global dm_operator_char_star print_addr "foo::operator*($dm_type_foo_ref)" print_addr "foo::operator%($dm_type_foo_ref)" @@ -470,7 +613,7 @@ proc test_paddr_operator_functions {} { } print_addr "foo::operator int($dm_type_void)" - print_addr "foo::operator $dm_type_char_star\($dm_type_void)" + print_addr "foo::operator $dm_operator_char_star\($dm_type_void)" } # @@ -480,17 +623,21 @@ proc test_paddr_operator_functions {} { proc test_paddr_overloaded_functions {} { global dm_type_unsigned_int global dm_type_void + global dm_type_short + global dm_type_unsigned_short + global dm_type_long + global dm_type_unsigned_long print_addr "overload1arg($dm_type_void)" print_addr "overload1arg(char)" print_addr "overload1arg(signed char)" print_addr "overload1arg(unsigned char)" - print_addr "overload1arg(short)" - print_addr "overload1arg(unsigned short)" + print_addr "overload1arg($dm_type_short)" + print_addr "overload1arg($dm_type_unsigned_short)" print_addr "overload1arg(int)" print_addr "overload1arg($dm_type_unsigned_int)" - print_addr "overload1arg(long)" - print_addr "overload1arg(unsigned long)" + print_addr "overload1arg($dm_type_long)" + print_addr "overload1arg($dm_type_unsigned_long)" print_addr "overload1arg(float)" print_addr "overload1arg(double)" @@ -513,17 +660,31 @@ proc test_paddr_hairy_functions {} { global dm_type_char_star global dm_type_int_star global dm_type_long_star + global dm_type_typedef print_addr_2 "hairyfunc1" "hairyfunc1(int)" - print_addr_2 "hairyfunc2" "hairyfunc2(int (*)($dm_type_char_star))" - print_addr_2 "hairyfunc3" "hairyfunc3(int (*)(short (*)($dm_type_long_star)))" - print_addr_2 "hairyfunc4" "hairyfunc4(int (*)(short (*)($dm_type_char_star)))" - - # gdb-gnats bug gdb/19: - # "gdb v3 demangler fails on hairyfunc5 hairyfunc6 hairyfunc7" - print_addr_2_kfail "hairyfunc5" "hairyfunc5(int (*(*)($dm_type_char_star))(long))" "hairyfunc5(int (*)(long) (*)(char*))" "gdb/19" - print_addr_2_kfail "hairyfunc6" "hairyfunc6(int (*(*)($dm_type_int_star))(long))" "hairyfunc6(int (*)(long) (*)(int*))" "gdb/19" - print_addr_2_kfail "hairyfunc7" "hairyfunc7(int (*(*)(int (*)($dm_type_char_star)))(long))" "hairyfunc7(int (*)(long) (*)(int (*)(char*)))" "gdb/19" + + if {$dm_type_typedef == 0} { + print_addr_2 "hairyfunc2" "hairyfunc2(int (*)($dm_type_char_star))" + print_addr_2 "hairyfunc3" "hairyfunc3(int (*)(short (*)($dm_type_long_star)))" + print_addr_2 "hairyfunc4" "hairyfunc4(int (*)(short (*)($dm_type_char_star)))" + + # gdb-gnats bug gdb/19: + # "gdb v3 demangler fails on hairyfunc5 hairyfunc6 hairyfunc7" + print_addr_2_kfail "hairyfunc5" "hairyfunc5(int (*(*)($dm_type_char_star))(long))" "hairyfunc5(int (*)(long) (*)(char*))" "gdb/19" + print_addr_2_kfail "hairyfunc6" "hairyfunc6(int (*(*)($dm_type_int_star))(long))" "hairyfunc6(int (*)(long) (*)(int*))" "gdb/19" + print_addr_2_kfail "hairyfunc7" "hairyfunc7(int (*(*)(int (*)($dm_type_char_star)))(long))" "hairyfunc7(int (*)(long) (*)(int (*)(char*)))" "gdb/19" + } else { + print_addr_2 "hairyfunc2" "hairyfunc2(PFPc_i)" + print_addr_2 "hairyfunc3" "hairyfunc3(PFPFPl_s_i)" + print_addr_2 "hairyfunc4" "hairyfunc4(PFPFPc_s_i)" + + # gdb-gnats bug gdb/19: + # "gdb v3 demangler fails on hairyfunc5 hairyfunc6 hairyfunc7" + print_addr_2 "hairyfunc5" "hairyfunc5(PFPc_PFl_i)" + print_addr_2 "hairyfunc6" "hairyfunc6(PFPi_PFl_i)" + print_addr_2 "hairyfunc7" "hairyfunc7(PFPFPc_i_PFl_i)" + } } proc do_tests {} { diff --git a/gdb/testsuite/gdb.cp/gdb1355.exp b/gdb/testsuite/gdb.cp/gdb1355.exp index 77687a6..66d16cf 100644 --- a/gdb/testsuite/gdb.cp/gdb1355.exp +++ b/gdb/testsuite/gdb.cp/gdb1355.exp @@ -68,11 +68,11 @@ set s_tail ".*" set f_i "${ws}int m_int;" set f_c "${ws}char m_char;" -set f_li "${ws}long int m_long_int;" +set f_li "${ws}long m_long_int;" set f_ui "${ws}unsigned int m_unsigned_int;" -set f_lui "${ws}long unsigned int m_long_unsigned_int;" -set f_si "${ws}short int m_short_int;" -set f_sui "${ws}short unsigned int m_short_unsigned_int;" +set f_lui "${ws}unsigned long m_long_unsigned_int;" +set f_si "${ws}short m_short_int;" +set f_sui "${ws}unsigned short m_short_unsigned_int;" set f_uc "${ws}unsigned char m_unsigned_char;" set f_f "${ws}float m_float;" set f_d "${ws}double m_double;" diff --git a/gdb/testsuite/gdb.cp/gdb2495.cc b/gdb/testsuite/gdb.cp/gdb2495.cc new file mode 100644 index 0000000..4df265f --- /dev/null +++ b/gdb/testsuite/gdb.cp/gdb2495.cc @@ -0,0 +1,90 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include +#include + +using namespace std; + +class SimpleException +{ + +public: + + void raise_signal (int dummy) + { + if (dummy > 0) + raise(SIGABRT); + } + + int no_throw_function () + { + return 1; + } + + void throw_function () + { + throw 1; + } + + int throw_function_with_handler () + { + try + { + throw 1; + } + catch (...) + { + cout << "Handled" << endl; + } + + return 2; + } + + void call_throw_function_no_handler () + { + throw_function (); + } + + void call_throw_function_handler () + { + throw_function_with_handler (); + } +}; +SimpleException exceptions; + +int +main() +{ + // Have to call all these functions + // so not optimized away. + exceptions.raise_signal (-1); + exceptions.no_throw_function (); + exceptions.throw_function_with_handler (); + exceptions.call_throw_function_handler (); + try + { + exceptions.throw_function (); + exceptions.call_throw_function_no_handler (); + } + catch (...) + { + } + return 0; +} + diff --git a/gdb/testsuite/gdb.cp/gdb2495.exp b/gdb/testsuite/gdb.cp/gdb2495.exp new file mode 100644 index 0000000..62c09c2 --- /dev/null +++ b/gdb/testsuite/gdb.cp/gdb2495.exp @@ -0,0 +1,160 @@ +# 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 . + + +# In gdb inferior function calls, if a C++ exception is raised in the +# dummy-frame, and the exception handler is (normally, and expected to +# be) out-of-frame, the default C++ handler will (wrongly) be called +# in an inferior function call. +# This is incorrect as an exception can normally and legally be handled +# out-of-frame. The confines of the dummy frame prevent the unwinder +# from finding the correct handler (or any handler, unless it is +# in-frame). The default handler calls std::terminate. This will kill +# the inferior. Assert that terminate should never be called in an +# inferior function call. These tests test the functionality around +# unwinding that sequence and also tests the flag behaviour gating this +# functionality. + +# This test is largley based off gdb.base/callfuncs.exp. + +if $tracelevel then { + strace $tracelevel +} + +if { [skip_cplus_tests] } { continue } + +set prms_id 2495 +set bug_id 0 + +set testfile "gdb2495" +set srcfile ${testfile}.cc +set binfile $objdir/$subdir/$testfile + +# Create and source the file that provides information about the compiler +# used to compile the test case. +if [get_compiler_info ${binfile} "c++"] { + return -1 +} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested gdb2495.exp + return -1 +} + +# Some targets can't do function calls, so don't even bother with this +# test. +if [target_info exists gdb,cannot_call_functions] { + setup_xfail "*-*-*" 2416 + fail "This target can not call functions" + continue +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] then { + perror "couldn't run to main" + continue +} + +# See http://sources.redhat.com/gdb/bugs/2495 + +# Test normal baseline behaviour. Call a function that +# does not raise an exception ... +gdb_test "p exceptions.no_throw_function()" " = 1" +# And one that does but handles it in-frame ... +gdb_test "p exceptions.throw_function_with_handler()" " = 2" +# Both should return normally. + +# Test basic unwind. Call a function that raises an exception but +# does not handle it. It should be rewound ... +gdb_test "p exceptions.throw_function()" \ + "The program being debugged entered a std::terminate call .*" \ + "Call a function that raises an exception without a handler." + +# Make sure that after rewinding we are back at the call parent. +gdb_test "bt" \ + "#0 main.*" \ + "bt after returning from a popped frame" + +# Make sure the only breakpoint is the one set via the runto_main +# call and that the std::terminate breakpoint has evaporated and +# cleaned-up. +gdb_test "info breakpoints" \ + "gdb.cp/gdb2495\.cc.*" + +# Turn off this new behaviour ... +send_gdb "set unwind-on-terminating-exception off\n" +gdb_expect { + -re "$gdb_prompt $" {pass "set unwind-on-terminating-exception"} + timeout {fail "(timeout) set unwind-on-terminating-exception"} +} + +# Check that it is turned off ... +gdb_test "show unwind-on-terminating-exception" \ + "exception is unhandled while in a call dummy is off.*" \ + "Turn off unwind on terminating exception flag" + +# Check that the old behaviour is restored. +gdb_test "p exceptions.throw_function()" \ + "The program being debugged stopped while in a function called .*" \ + "Call a function that raises an exception with unwinding off.." + + +# Restart back at main +if ![runto_main] then { + perror "couldn't run to main" + continue +} + + +# Check to see if our new behaviour alters the unwind signal +# behaviour. It should not. Test both on and off states. + +# Turn on unwind on signal behaviour ... +send_gdb "set unwindonsignal on\n" +gdb_expect { + -re "$gdb_prompt $" {pass "set unwindonsignal on"} + timeout {fail "(timeout) set unwindonsignal on"} +} + +# Check that it is turned on ... +gdb_test "show unwindonsignal" \ + "signal is received while in a call dummy is on.*" \ + "Turn on unwind on signal" + +# Check to see if new behaviour interferes with +# normal signal handling in inferior function calls. +gdb_test "p exceptions.raise_signal(1)" \ + "To change this behavior use \"set unwindonsignal off\".*" + +# And reverse. Turn off +send_gdb "set unwindonsignal off\n" +gdb_expect { + -re "$gdb_prompt $" {pass "set unwindonsignal off"} + timeout {fail "(timeout) set unwindonsignal off"} +} + +# Check that it is turned off ... +gdb_test "show unwindonsignal" \ + "signal is received while in a call dummy is off.*" \ + "Turn off unwind on signal" + +# Check to see if new behaviour interferes with +# normal signal handling in inferior function calls. +gdb_test "p exceptions.raise_signal(1)" \ + "To change this behavior use \"set unwindonsignal on\".*" diff --git a/gdb/testsuite/gdb.cp/member-ptr.cc b/gdb/testsuite/gdb.cp/member-ptr.cc index 1dff70a..648b2af 100644 --- a/gdb/testsuite/gdb.cp/member-ptr.cc +++ b/gdb/testsuite/gdb.cp/member-ptr.cc @@ -138,6 +138,7 @@ class Diamond : public Padding, public Left, public Right { public: virtual int vget_base (); + int (*func_ptr) (int); }; int Diamond::vget_base () @@ -145,6 +146,12 @@ int Diamond::vget_base () return this->Left::x + 2000; } +int +func (int x) +{ + return 19 + x; +} + int main () { A a; @@ -162,6 +169,7 @@ int main () int (Diamond::*right_vpmf) (); int (Base::*base_vpmf) (); int Diamond::*diamond_pmi; + int (* Diamond::*diamond_pfunc_ptr) (int); PMI null_pmi; PMF null_pmf; @@ -179,6 +187,7 @@ int main () diamond.Left::x = 77; diamond.Right::x = 88; + diamond.func_ptr = func; /* Some valid pointer to members from a base class. */ left_pmf = (int (Diamond::*) ()) (int (Left::*) ()) (&Base::get_x); @@ -193,11 +202,19 @@ int main () /* A pointer to data member from a base class. */ diamond_pmi = (int Diamond::*) (int Left::*) &Base::x; + /* A pointer to data member, where the member is itself a pointer to + a function. */ + diamond_pfunc_ptr = (int (* Diamond::*) (int)) &Diamond::func_ptr; + null_pmi = NULL; null_pmf = NULL; pmi = NULL; /* Breakpoint 1 here. */ + // Invalid (uses diamond_pfunc_ptr as a function): + // diamond.*diamond_pfunc_ptr (20); + (diamond.*diamond_pfunc_ptr) (20); + k = (a.*pmf)(3); pmi = &A::jj; diff --git a/gdb/testsuite/gdb.cp/member-ptr.exp b/gdb/testsuite/gdb.cp/member-ptr.exp index b69d4ad..476711f 100644 --- a/gdb/testsuite/gdb.cp/member-ptr.exp +++ b/gdb/testsuite/gdb.cp/member-ptr.exp @@ -390,6 +390,33 @@ gdb_test_multiple "print ((int) pmi) == ((char *) &a.j - (char *) & a)" $name { } } +# Check pointers to data members, which are themselves pointers to +# functions. These behave like data members, not like pointers to +# member functions. + +gdb_test "ptype diamond_pfunc_ptr" \ + "type = int \\(\\*Diamond::\\*\\)\\(int\\)" + +gdb_test "ptype diamond.*diamond_pfunc_ptr" \ + "type = int \\(\\*\\)\\(int\\)" + +# This one is invalid; () binds more tightly than .*, so it tries to +# call the member pointer as a normal pointer-to-function. + +gdb_test "print diamond.*diamond_pfunc_ptr (20)" \ + "Invalid data type for function to be called." + +# With parentheses, it is valid. + +gdb_test "print (diamond.*diamond_pfunc_ptr) (20)" \ + "$vhn = 39" + +# Make sure that we do not interpret this as either a member pointer +# call or a member function call. + +gdb_test "print diamond.func_ptr (20)" \ + "$vhn = 39" + # ========================== # pointer to member function # ========================== @@ -608,6 +635,9 @@ gdb_test_multiple "print (a.*pmf)(3)" $name { } } +gdb_test "ptype a.*pmf" "type = int \\(A \\*, int\\)" +gdb_test "ptype (a.*pmf)(3)" "type = int" + # Print out a pointer to data member which requires looking into # a base class. gdb_test "print diamond_pmi" "$vhn = &Base::x" diff --git a/gdb/testsuite/gdb.cp/namespace-multiple-imports.cc b/gdb/testsuite/gdb.cp/namespace-multiple-imports.cc new file mode 100644 index 0000000..6b180d6 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-multiple-imports.cc @@ -0,0 +1,20 @@ +namespace A { + int x = 11; + namespace{ + int xx = 22; + } +} + +using namespace A; + +namespace{ + int xxx = 33; +}; + +int main() +{ + x; + xx; + xxx; + return 0; +} diff --git a/gdb/testsuite/gdb.cp/namespace-multiple-imports.exp b/gdb/testsuite/gdb.cp/namespace-multiple-imports.exp new file mode 100644 index 0000000..e4bb9f8 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-multiple-imports.exp @@ -0,0 +1,49 @@ +# Copyright 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +if $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile namespace-multiple-imports +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +# Get things started. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +############################################ +# test printing of namespace imported within +# the function. + +if ![runto_main] then { + perror "couldn't run to breakpoint main" + continue +} + +gdb_test "print x" "\\$\[0-9\].* = 11" +gdb_test "print xx" "\\$\[0-9\].* = 22" +gdb_test "print xxx" "\\$\[0-9\].* = 33" diff --git a/gdb/testsuite/gdb.cp/namespace-using.cc b/gdb/testsuite/gdb.cp/namespace-using.cc new file mode 100644 index 0000000..97af850 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-using.cc @@ -0,0 +1,131 @@ +//-------------------------- +namespace M{ + int x = 911; +} + +namespace N{ + int x = 912; +} + +int marker10(){ + using namespace M; + int y = x+1; // marker10 stop + using namespace N; + return y; +} +//-------------------------- +namespace J { + int jx = 44; +} + +namespace K{ + int marker9(){ + //x; + return marker10(); + } +} + +namespace L{ + using namespace J; + int marker8(){ + jx; + return K::marker9(); + } +} +//-------------------------- + +//-------------------------- +namespace G{ + namespace H { + int ghx = 6; + } +} + +namespace I{ + + int marker7(){ + using namespace G::H; + ghx; + return L::marker8(); + } +} +//-------------------------- + +//-------------------------- +namespace E{ + namespace F{ + int efx = 5; + } +} +using namespace E::F; +int marker6(){ + efx; + return I::marker7(); +} +//-------------------------- + +namespace A +{ + int _a = 1; + int x = 2; + +} + +namespace C +{ + int cc = 3; +} + +namespace D +{ + int dx = 4; +} + +using namespace C; +int marker5() +{ + cc; + return marker6(); +} + +int marker4() +{ + using D::dx; + return marker5(); +} + +int marker3() +{ + return marker4(); +} + +int marker2() +{ + namespace B = A; + B::_a; + return marker3(); +} + +int marker1() +{ + int total = 0; + { + int b = 1; + { + using namespace A; + int c = 2; + { + int d = 3; + total = _a + b + c + d + marker2(); // marker1 stop + } + } + } + return total; +} + +int main() +{ + using namespace A; + _a; + return marker1(); +} diff --git a/gdb/testsuite/gdb.cp/namespace-using.exp b/gdb/testsuite/gdb.cp/namespace-using.exp new file mode 100644 index 0000000..f73fa67 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-using.exp @@ -0,0 +1,186 @@ +# Copyright 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +if $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile namespace-using +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +# Get things started. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +############################################ +# test printing of namespace imported within +# the function. + +if ![runto_main] then { + perror "couldn't run to breakpoint main" + continue +} + +gdb_test "print _a" "= 1" + +# Test that names are not printed when they +# are not imported + +gdb_breakpoint marker3 +gdb_continue_to_breakpoint "marker3" + +#send_gdb "break marker3\n" +#send_gdb "continue\n" + +gdb_test "print _a" "No symbol \"_a\" in current context." "Print _a without import" + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + + +############################################ +# test printing of namespace imported into +# a scope containing the pc. + +if ![runto_main] then { + perror "couldn't run to breakpoint main" + continue +} + +gdb_breakpoint [gdb_get_line_number "marker1 stop"] +gdb_continue_to_breakpoint "marker1 stop" + +gdb_test "print _a" "= 1" "print _a in a nested scope" + + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +############################################ +# test printing of namespace imported into +# file scope. + + +if ![runto marker5] then { + perror "couldn't run to breakpoint marker5" + continue +} + +gdb_test "print cc" "= 3" + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + + +############################################ +# Test printing of namespace aliases + +if ![runto marker2] then { + perror "couldn't run to breakpoint marker2" + continue +} + +gdb_test "print B::_a" "= 1" + +gdb_test "print _a" "No symbol \"_a\" in current context." "print _a in namespace alias scope" +gdb_test "print x" "No symbol \"x\" in current context." "print x in namespace alias scope" + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + + +############################################ +# Test printing of namespace aliases + +if ![runto marker4] then { + perror "couldn't run to breakpoint marker4" + continue +} + +gdb_test "print dx" "= 4" + +############################################ +# Test printing of namespace aliases + +if ![runto marker6] then { + perror "couldn't run to breakpoint marker6" + continue +} + +gdb_test "print efx" "= 5" + +############################################ +# Test printing of variables imported from +# nested namespaces + +if ![runto I::marker7] then { + perror "couldn't run to breakpoint I::marker7" + continue +} + +gdb_test "print ghx" "= 6" + +############################################ +# Test that variables are not printed in a namespace +# that is sibling to the namespace containing an import + +if ![runto L::marker8] then { + perror "couldn't run to breakpoint L::marker8" + continue +} + +gdb_test "print jx" "= 44" + +gdb_breakpoint "K::marker9" +gdb_continue_to_breakpoint "K::marker9" + +gdb_test "print jx" "No symbol \"jx\" in current context." + +############################################ +# Test that variables are only printed after the line +# containing the import + +if ![runto_main] then { + perror "couldn't run to breakpoint main" + continue +} + +gdb_breakpoint [gdb_get_line_number "marker10 stop"] +gdb_continue_to_breakpoint "marker10 stop" + +gdb_test "print x" "= 911" "print x (from M::x)" + +gdb_test "next" "" + +gdb_test "print x" "= 912" "print x (from M::x)" diff --git a/gdb/testsuite/gdb.cp/namespace.exp b/gdb/testsuite/gdb.cp/namespace.exp index 76b1b82..2042db2 100644 --- a/gdb/testsuite/gdb.cp/namespace.exp +++ b/gdb/testsuite/gdb.cp/namespace.exp @@ -24,6 +24,7 @@ # for namespaces. # Note: As of 2000-06-03, they passed under g++ - djb +load_lib "cp-support.exp" if $tracelevel then { strace $tracelevel @@ -259,11 +260,16 @@ gdb_test "ptype E" "type = namespace C::D::E" gdb_test "ptype CClass" "type = (class C::CClass \{\r\n public:|struct C::CClass \{)\r\n int x;\r\n\}" gdb_test "ptype CClass::NestedClass" "type = (class C::CClass::NestedClass \{\r\n public:|struct C::CClass::NestedClass \{)\r\n int y;\r\n\}" gdb_test "ptype NestedClass" "No symbol \"NestedClass\" in current context." -setup_kfail "gdb/1448" "*-*-*" -gdb_test "ptype ::C::CClass" "type = class C::CClass \{\r\n public:\r\n int x;\r\n\}" -setup_kfail "gdb/1448" "*-*-*" -gdb_test "ptype ::C::CClass::NestedClass" "type = class C::CClass::NestedClass \{\r\n public:\r\n int y;\r\n\}" -setup_kfail "gdb/1448" "*-*-*" +cp_test_ptype_class \ + "ptype ::C::CClass" "" "class" "C::CClass" \ + { + { field public "int x;" } + } +cp_test_ptype_class \ + "ptype ::C::CClass::NestedClass" "" "class" "C::CClass::NestedClass" \ + { + { field public "int y;" } + } gdb_test "ptype ::C::NestedClass" "No symbol \"NestedClass\" in namespace \"C\"." gdb_test "ptype C::CClass" "No symbol \"CClass\" in namespace \"C::C\"." gdb_test "ptype C::CClass::NestedClass" "No type \"CClass\" within class or namespace \"C::C\"." @@ -273,8 +279,11 @@ gdb_test "ptype C::NestedClass" "No symbol \"NestedClass\" in namespace \"C::C\" gdb_test "print cOtherFile" "\\$\[0-9\].* = 316" gdb_test "ptype OtherFileClass" "type = (class C::OtherFileClass \{\r\n public:|struct C::OtherFileClass \{)\r\n int z;\r\n\}" -setup_kfail "gdb/1448" "*-*-*" -gdb_test "ptype ::C::OtherFileClass" "type = class C::OtherFileClass \{\r\n public:\r\n int z;\r\n\}" +cp_test_ptype_class \ + "ptype ::C::OtherFileClass" "" "class" "C::OtherFileClass" \ + { + { field public "int z;" } + } gdb_test "ptype C::OtherFileClass" "No symbol \"OtherFileClass\" in namespace \"C::C\"." # Some anonymous namespace tests. diff --git a/gdb/testsuite/gdb.cp/overload.exp b/gdb/testsuite/gdb.cp/overload.exp index 24025a2..a72932e 100644 --- a/gdb/testsuite/gdb.cp/overload.exp +++ b/gdb/testsuite/gdb.cp/overload.exp @@ -74,12 +74,12 @@ set re_methods "${re_methods}${ws}int overload1arg\\((void|)\\);" set re_methods "${re_methods}${ws}int overload1arg\\(char\\);" set re_methods "${re_methods}${ws}int overload1arg\\(signed char\\);" set re_methods "${re_methods}${ws}int overload1arg\\(unsigned char\\);" -set re_methods "${re_methods}${ws}int overload1arg\\(short\\);" -set re_methods "${re_methods}${ws}int overload1arg\\(unsigned short\\);" +set re_methods "${re_methods}${ws}int overload1arg\\(short( int)?\\);" +set re_methods "${re_methods}${ws}int overload1arg\\((unsigned short|short unsigned)( int)?\\);" set re_methods "${re_methods}${ws}int overload1arg\\(int\\);" set re_methods "${re_methods}${ws}int overload1arg\\(unsigned int\\);" -set re_methods "${re_methods}${ws}int overload1arg\\(long\\);" -set re_methods "${re_methods}${ws}int overload1arg\\(unsigned long\\);" +set re_methods "${re_methods}${ws}int overload1arg\\(long( int)?\\);" +set re_methods "${re_methods}${ws}int overload1arg\\((unsigned long|long unsigned)( int)?\\);" set re_methods "${re_methods}${ws}int overload1arg\\(float\\);" set re_methods "${re_methods}${ws}int overload1arg\\(double\\);" set re_methods "${re_methods}${ws}int overloadfnarg\\((void|)\\);" diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp index 8a6b795..897171c 100644 --- a/gdb/testsuite/gdb.cp/ovldbreak.exp +++ b/gdb/testsuite/gdb.cp/ovldbreak.exp @@ -127,10 +127,24 @@ proc set_bp_overloaded {name expectedmenu mychoice bpnumber linenumber} { } # This is the expected menu for overload1arg. -# Note the arg type variations on lines 6 and 13. +# Note the arg type variations for void and integer types. # This accommodates different versions of g++. -set menu_overload1arg "\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] foo::overload1arg\\(double\\) at.*$srcfile:121\r\n\\\[3\\\] foo::overload1arg\\(float\\) at.*$srcfile:120\r\n\\\[4\\\] foo::overload1arg\\(unsigned long\\) at.*$srcfile:119\r\n\\\[5\\\] foo::overload1arg\\(long\\) at.*$srcfile:118\r\n\\\[6\\\] foo::overload1arg\\((unsigned int|unsigned)\\) at.*$srcfile:117\r\n\\\[7\\\] foo::overload1arg\\(int\\) at.*$srcfile:116\r\n\\\[8\\\] foo::overload1arg\\(unsigned short\\) at.*$srcfile:115\r\n\\\[9\\\] foo::overload1arg\\(short\\) at.*$srcfile:114\r\n\\\[10\\\] foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r\n\\\[11\\\] foo::overload1arg\\(signed char\\) at.*$srcfile:112\r\n\\\[12\\\] foo::overload1arg\\(char\\) at.*$srcfile:111\r\n\\\[13\\\] foo::overload1arg\\((void|)\\) at.*$srcfile:110\r\n> $" +set menu_overload1arg "\\\[0\\\] cancel\r\n" +append menu_overload1arg "\\\[1\\\] all\r\n" +append menu_overload1arg "\\\[2\\\] foo::overload1arg\\(double\\) at.*$srcfile:121\r\n" +append menu_overload1arg "\\\[3\\\] foo::overload1arg\\(float\\) at.*$srcfile:120\r\n" +append menu_overload1arg "\\\[4\\\] foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r\n" +append menu_overload1arg "\\\[5\\\] foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r\n" +append menu_overload1arg "\\\[6\\\] foo::overload1arg\\((unsigned int|unsigned)\\) at.*$srcfile:117\r\n" +append menu_overload1arg "\\\[7\\\] foo::overload1arg\\(int\\) at.*$srcfile:116\r\n" +append menu_overload1arg "\\\[8\\\] foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r\n" +append menu_overload1arg "\\\[9\\\] foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r\n" +append menu_overload1arg "\\\[10\\\] foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r\n" +append menu_overload1arg "\\\[11\\\] foo::overload1arg\\(signed char\\) at.*$srcfile:112\r\n" +append menu_overload1arg "\\\[12\\\] foo::overload1arg\\(char\\) at.*$srcfile:111\r\n" +append menu_overload1arg "\\\[13\\\] foo::overload1arg\\((void|)\\) at.*$srcfile:110\r\n" +append menu_overload1arg "> $" # Set multiple-symbols to "ask", to allow us to test the use # of the multiple-choice menu when breaking on an overloaded method. @@ -157,17 +171,17 @@ set_bp_overloaded "foo::overload1arg" "$menu_overload1arg" 13 13 110 gdb_test "info break" \ "Num Type\[\t \]+Disp Enb Address\[\t \]+What.* -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in main at.*$srcfile:49\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in main(\\(void\\))? at.*$srcfile:49\r \[\t \]+breakpoint already hit 1 time\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short\\) at.*$srcfile:114\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned short\\) at.*$srcfile:115\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long\\) at.*$srcfile:118\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned long\\) at.*$srcfile:119\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \ @@ -215,17 +229,17 @@ gdb_expect { gdb_test "info break" \ "Num Type\[\t \]+Disp Enb Address\[\t \]+What.* -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in main at.*$srcfile:49\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in main(\\(void\\))? at.*$srcfile:49\r \[\t \]+breakpoint already hit 1 time\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short\\) at.*$srcfile:114\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned short\\) at.*$srcfile:115\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long\\) at.*$srcfile:118\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned long\\) at.*$srcfile:119\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \ @@ -296,12 +310,12 @@ gdb_test "info break" \ "Num Type\[\t \]+Disp Enb Address\[\t \]+What.* \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned long\\) at.*$srcfile:119\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long\\) at.*$srcfile:118\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned short\\) at.*$srcfile:115\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short\\) at.*$srcfile:114\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r diff --git a/gdb/testsuite/gdb.cp/ref-types.exp b/gdb/testsuite/gdb.cp/ref-types.exp index 4784cb2..b2e55cf 100644 --- a/gdb/testsuite/gdb.cp/ref-types.exp +++ b/gdb/testsuite/gdb.cp/ref-types.exp @@ -284,7 +284,7 @@ gdb_expect { send_gdb "print UC\n" gdb_expect { - -re ".\[0-9\]* = 21 '\.025'\.*$gdb_prompt $" { + -re ".\[0-9\]* = 21 '\.25'\.*$gdb_prompt $" { pass "print value of UC" } -re ".*$gdb_prompt $" { fail "print value of UC" } @@ -557,7 +557,7 @@ gdb_expect { send_gdb "print rUC\n" gdb_expect { - -re ".\[0-9\]* = \\(unsigned char &\\) @$hex: 21 \'.025\'.*$gdb_prompt $" { + -re ".\[0-9\]* = \\(unsigned char &\\) @$hex: 21 \'.25\'.*$gdb_prompt $" { pass "print value of rUC" } -re ".*$gdb_prompt $" { fail "print value of rUC" } diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp index cd9b770..f49caff 100644 --- a/gdb/testsuite/gdb.cp/templates.exp +++ b/gdb/testsuite/gdb.cp/templates.exp @@ -329,13 +329,11 @@ gdb_expect { send_gdb "print Foo::foo\n" gdb_expect { - -re "\\$\[0-9\]* = \\{.*char \\*\\((class |)Foo \\*(| const), int, .*char \\*\\)\\} $hex ::foo\\(int, .*char.*\\*\\)>\r\n$gdb_prompt $" { pass "print Foo::foo" } + -re "\\$\[0-9\]* = \\{.*char \\*\\((class |)Foo<(volatile char|char volatile) ?\\*> \\*(| const), int, .*char \\*\\)\\} $hex ::foo\\(int, .*char.*\\*\\)>\r\n$gdb_prompt $" { pass "print Foo::foo" } -re "No symbol \"Foo\" in current context.\r\n$gdb_prompt $" { - # This used to be a kfail gdb/33. That problem has been - # fixed, but now gdb/931 and gdb/1512 are rearing their ugly - # heads. - kfail "gdb/931" "print Foo::foo" + # This used to be a kfail gdb/33 and then kfail gdb/931. + fail "print Foo::foo" } -re "$gdb_prompt $" { fail "print Foo::foo" } timeout { fail "(timeout) print Foo::foo" } @@ -343,13 +341,11 @@ gdb_expect { send_gdb "print Foo::foo\n" gdb_expect { - -re "\\$\[0-9\]* = \\{.*char \\*\\((class |)Foo \\*(| const), int, .*char \\*\\)\\} $hex ::foo\\(int, .*char.*\\*\\)>\r\n$gdb_prompt $" { pass "print Foo::foo" } + -re "\\$\[0-9\]* = \\{.*char \\*\\((class |)Foo<(volatile char|char volatile) ?\\*> \\*(| const), int, .*char \\*\\)\\} $hex ::foo\\(int, .*char.*\\*\\)>\r\n$gdb_prompt $" { pass "print Foo::foo" } -re "No symbol \"Foo\" in current context.\r\n$gdb_prompt $" { - # This used to be a kfail gdb/33. That problem has been - # fixed, but now gdb/931 and gdb/1512 are rearing their ugly - # heads. - kfail "gdb/931" "print Foo::foo" + # This used to be a kfail gdb/33 and then kfail gdb/931. + fail "print Foo::foo" } -re "$gdb_prompt $" { fail "print Foo::foo" } timeout { fail "(timeout) print Foo::foo" } @@ -459,7 +455,7 @@ send_gdb "ptype quxint\n" gdb_expect { -re "type = class Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int qux\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" { pass "ptype quxint" } -re "type = class Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int qux\\(int, int\\);.*\r\n\\}\r\n$gdb_prompt $" { pass "ptype quxint" } - -re "type = class Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int qux\\(int, int\\);.*\r\n\\}\r\n$gdb_prompt $" { pass "ptype quxint" } + -re "type = class Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int qux\\(int, int\\);.*\r\n\\}\r\n$gdb_prompt $" { pass "ptype quxint" } -re "type = class Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*int qux\\(int, int\\);.*\r\n\\}\r\n$gdb_prompt $" { kfail "gdb/1512" "ptype quxint" } 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.fortran/common-block.exp b/gdb/testsuite/gdb.fortran/common-block.exp new file mode 100644 index 0000000..888f6c3 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/common-block.exp @@ -0,0 +1,101 @@ +# Copyright 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file was written by Jan Kratochvil . + +set testfile "common-block" +set srcfile ${testfile}.f90 +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto MAIN__] then { + perror "couldn't run to breakpoint MAIN__" + continue +} + +gdb_breakpoint [gdb_get_line_number "stop-here-out"] +gdb_continue_to_breakpoint "stop-here-out" + +# Common block naming with source name /foo/: +# .symtab DW_TAG_common_block's DW_AT_name +# Intel Fortran foo_ foo_ +# GNU Fortran foo_ foo +#set suffix "_" +set suffix "" + +set int4 {(integer\(kind=4\)|INTEGER\(4\))} +set real4 {(real\(kind=4\)|REAL\(4\))} +set real8 {(real\(kind=8\)|REAL\(8\))} + +gdb_test "whatis foo$suffix" "No symbol \"foo$suffix\" in current context." +gdb_test "ptype foo$suffix" "No symbol \"foo$suffix\" in current context." +gdb_test "p foo$suffix" "No symbol \"foo$suffix\" in current context." +gdb_test "whatis fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." +gdb_test "ptype fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." +gdb_test "p fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." + +gdb_test "info locals" "ix_x = 11\r\niy_y = 22\r\niz_z = 33\r\nix = 1\r\niy = 2\r\niz = 3" "info locals out" +gdb_test "info common" "Contents of F77 COMMON block 'fo_o':\r\nix_x = 11\r\niy_y = 22\r\niz_z = 33\r\n\r\nContents of F77 COMMON block 'foo':\r\nix = 1\r\niy = 2\r\niz = 3" "info common out" + +gdb_test "ptype ix" "type = $int4" "ptype ix out" +gdb_test "ptype iy" "type = $real4" "ptype iy out" +gdb_test "ptype iz" "type = $real8" "ptype iz out" +gdb_test "ptype ix_x" "type = $int4" "ptype ix_x out" +gdb_test "ptype iy_y" "type = $real4" "ptype iy_y out" +gdb_test "ptype iz_z" "type = $real8" "ptype iz_z out" + +gdb_test "p ix" " = 1 *" "p ix out" +gdb_test "p iy" " = 2 *" "p iy out" +gdb_test "p iz" " = 3 *" "p iz out" +gdb_test "p ix_x" " = 11 *" "p ix_x out" +gdb_test "p iy_y" " = 22 *" "p iy_y out" +gdb_test "p iz_z" " = 33 *" "p iz_z out" + +gdb_breakpoint [gdb_get_line_number "stop-here-in"] +gdb_continue_to_breakpoint "stop-here-in" + +gdb_test "whatis foo$suffix" "No symbol \"foo$suffix\" in current context." "whatis foo$suffix in" +gdb_test "ptype foo$suffix" "No symbol \"foo$suffix\" in current context." "ptype foo$suffix in" +gdb_test "p foo$suffix" "No symbol \"foo$suffix\" in current context." "p foo$suffix in" +gdb_test "whatis fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." "whatis fo_o$suffix in" +gdb_test "ptype fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." "ptype fo_o$suffix in" +gdb_test "p fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." "p fo_o$suffix in" + +gdb_test "info locals" "ix = 11\r\niy2 = 22\r\niz = 33\r\nix_x = 1\r\niy_y = 2\r\niz_z2 = 3\r\niy = 5\r\niz_z = 55" "info locals in" +gdb_test "info common" "Contents of F77 COMMON block 'fo_o':\r\nix = 11\r\niy2 = 22\r\niz = 33\r\n\r\nContents of F77 COMMON block 'foo':\r\nix_x = 1\r\niy_y = 2\r\niz_z2 = 3" "info common in" + +gdb_test "ptype ix" "type = $int4" "ptype ix in" +gdb_test "ptype iy2" "type = $real4" "ptype iy2 in" +gdb_test "ptype iz" "type = $real8" "ptype iz in" +gdb_test "ptype ix_x" "type = $int4" "ptype ix_x in" +gdb_test "ptype iy_y" "type = $real4" "ptype iy_y in" +gdb_test "ptype iz_z2" "type = $real8" "ptype iz_z2 in" + +gdb_test "p ix" " = 11 *" "p ix in" +gdb_test "p iy2" " = 22 *" "p iy2 in" +gdb_test "p iz" " = 33 *" "p iz in" +gdb_test "p ix_x" " = 1 *" "p ix_x in" +gdb_test "p iy_y" " = 2 *" "p iy_y in" +gdb_test "p iz_z2" " = 3 *" "p iz_z2 in" diff --git a/gdb/testsuite/gdb.fortran/common-block.f90 b/gdb/testsuite/gdb.fortran/common-block.f90 new file mode 100644 index 0000000..b614e8a --- /dev/null +++ b/gdb/testsuite/gdb.fortran/common-block.f90 @@ -0,0 +1,67 @@ +! Copyright 2008 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 2 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +! +! Ihis file is the Fortran source file for dynamic.exp. +! Original file written by Jakub Jelinek . +! Modified for the GDB testcase by Jan Kratochvil . + +subroutine in + + INTEGER*4 ix + REAL*4 iy2 + REAL*8 iz + + INTEGER*4 ix_x + REAL*4 iy_y + REAL*8 iz_z2 + + common /fo_o/ix,iy2,iz + common /foo/ix_x,iy_y,iz_z2 + + iy = 5 + iz_z = 55 + + if (ix .ne. 11 .or. iy2 .ne. 22.0 .or. iz .ne. 33.0) call abort + if (ix_x .ne. 1 .or. iy_y .ne. 2.0 .or. iz_z2 .ne. 3.0) call abort + + ix = 0 ! stop-here-in + +end subroutine in + +program common_test + + INTEGER*4 ix + REAL*4 iy + REAL*8 iz + + INTEGER*4 ix_x + REAL*4 iy_y + REAL*8 iz_z + + common /foo/ix,iy,iz + common /fo_o/ix_x,iy_y,iz_z + + ix = 1 + iy = 2.0 + iz = 3.0 + + ix_x = 11 + iy_y = 22.0 + iz_z = 33.0 + + call in ! stop-here-out + +end program common_test diff --git a/gdb/testsuite/gdb.fortran/dynamic.exp b/gdb/testsuite/gdb.fortran/dynamic.exp new file mode 100644 index 0000000..77a1203 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/dynamic.exp @@ -0,0 +1,156 @@ +# Copyright 2007 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file was written by Jan Kratochvil . + +# This file is part of the gdb testsuite. It contains tests for dynamically +# allocated Fortran arrays. +# It depends on the GCC dynamic Fortran arrays DWARF support: +# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22244 + +set testfile "dynamic" +set srcfile ${testfile}.f90 +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto MAIN__] then { + perror "couldn't run to breakpoint MAIN__" + continue +} + +gdb_breakpoint [gdb_get_line_number "varx-init"] +gdb_continue_to_breakpoint "varx-init" +gdb_test "p varx" "\\$\[0-9\]* = <(object|the array) is not allocated>" "p varx unallocated" +gdb_test "ptype varx" "type = <(object|the array) is not allocated>" "ptype varx unallocated" +gdb_test "p varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17) unallocated" +gdb_test "p varx(1,5,17)=1" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17)=1 unallocated" +gdb_test "ptype varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "ptype varx(1,5,17) unallocated" + +gdb_breakpoint [gdb_get_line_number "varx-allocated"] +gdb_continue_to_breakpoint "varx-allocated" +# $1 = (( ( 0, 0, 0, 0, 0, 0) ( 0, 0, 0, 0, 0, 0) --- , 0) ) ( ( 0, 0, ...) ...) ...) +gdb_test "ptype varx" "type = real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)" "ptype varx allocated" +# Intel Fortran Compiler 10.1.008 uses -1 there, GCC uses 1. +gdb_test "p l" "\\$\[0-9\]* = (\\.TRUE\\.|4294967295)" "p l if varx allocated" + +gdb_breakpoint [gdb_get_line_number "varx-filled"] +gdb_continue_to_breakpoint "varx-filled" +gdb_test "p varx(2, 5, 17)" "\\$\[0-9\]* = 6" +gdb_test "p varx(1, 5, 17)" "\\$\[0-9\]* = 7" +gdb_test "p varx(2, 6, 18)" "\\$\[0-9\]* = 8" +gdb_test "p varx(6, 15, 28)" "\\$\[0-9\]* = 9" +# The latter one is for the Intel Fortran Compiler 10.1.008 pointer type. +gdb_test "p varv" "\\$\[0-9\]* = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "p varv unassociated" +gdb_test "ptype varv" "type = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "ptype varv unassociated" + +gdb_breakpoint [gdb_get_line_number "varv-associated"] +gdb_continue_to_breakpoint "varv-associated" +gdb_test "p varx(3, 7, 19)" "\\$\[0-9\]* = 6" "p varx(3, 7, 19) with varv associated" +gdb_test "p varv(3, 7, 19)" "\\$\[0-9\]* = 6" "p varv(3, 7, 19) associated" +# Intel Fortran Compiler 10.1.008 uses -1 there, GCC uses 1. +gdb_test "p l" "\\$\[0-9\]* = (\\.TRUE\\.|4294967295)" "p l if varv associated" +gdb_test "ptype varx" "type = real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)" "ptype varx with varv associated" +# Intel Fortran Compiler 10.1.008 uses the pointer type. +gdb_test "ptype varv" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)\\)?" "ptype varv associated" + +gdb_breakpoint [gdb_get_line_number "varv-filled"] +gdb_continue_to_breakpoint "varv-filled" +gdb_test "p varx(3, 7, 19)" "\\$\[0-9\]* = 10" "p varx(3, 7, 19) with varv filled" +gdb_test "p varv(3, 7, 19)" "\\$\[0-9\]* = 10" "p varv(3, 7, 19) filled" + +gdb_breakpoint [gdb_get_line_number "varv-deassociated"] +gdb_continue_to_breakpoint "varv-deassociated" +# The latter one is for the Intel Fortran Compiler 10.1.008 pointer type. +gdb_test "p varv" "\\$\[0-9\]* = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "p varv deassociated" +gdb_test "ptype varv" "type = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "ptype varv deassociated" +gdb_test "p l" "\\$\[0-9\]* = \\.FALSE\\." "p l if varv deassociated" +gdb_test "p varv(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not associated\\." +gdb_test "ptype varv(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not associated\\." + +gdb_breakpoint [gdb_get_line_number "varx-deallocated"] +gdb_continue_to_breakpoint "varx-deallocated" +gdb_test "p varx" "\\$\[0-9\]* = <(object|the array) is not allocated>" "p varx deallocated" +gdb_test "ptype varx" "type = <(object|the array) is not allocated>" "ptype varx deallocated" +gdb_test "p l" "\\$\[0-9\]* = \\.FALSE\\." "p l if varx deallocated" +gdb_test "p varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17) deallocated" +gdb_test "ptype varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "ptype varx(1,5,17) deallocated" + +gdb_breakpoint [gdb_get_line_number "vary-passed"] +gdb_continue_to_breakpoint "vary-passed" +# $1 = (( ( 1, 1, 1, 1, 1, 1) ( 1, 1, 1, 1, 1, 1) --- , 1) ) ( ( 1, 1, ...) ...) ...) +gdb_test "p vary" "\\$\[0-9\]* = \\(\[()1, .\]*\\)" + +gdb_breakpoint [gdb_get_line_number "vary-filled"] +gdb_continue_to_breakpoint "vary-filled" +gdb_test "ptype vary" "type = real(\\(kind=4\\)|\\*4) \\(10,10\\)" +gdb_test "p vary(1, 1)" "\\$\[0-9\]* = 8" +gdb_test "p vary(2, 2)" "\\$\[0-9\]* = 9" +gdb_test "p vary(1, 3)" "\\$\[0-9\]* = 10" +# $1 = (( ( 3, 3, 3, 3, 3, 3) ( 3, 3, 3, 3, 3, 3) --- , 3) ) ( ( 3, 3, ...) ...) ...) +gdb_test "p varw" "\\$\[0-9\]* = \\(\[()3, .\]*\\)" + +gdb_breakpoint [gdb_get_line_number "varw-almostfilled"] +gdb_continue_to_breakpoint "varw-almostfilled" +gdb_test "ptype varw" "type = real(\\(kind=4\\)|\\*4) \\(5,4,3\\)" +gdb_test "p varw(3,1,1)=1" "\\$\[0-9\]* = 1" +# $1 = (( ( 6, 5, 1, 5, 5, 5) ( 5, 5, 5, 5, 5, 5) --- , 5) ) ( ( 5, 5, ...) ...) ...) +gdb_test "p varw" "\\$\[0-9\]* = \\( *\\( *\\( *6, *5, *1,\[()5, .\]*\\)" "p varw filled" +# "up" works with GCC but other Fortran compilers may copy the values into the +# outer function only on the exit of the inner function. +gdb_test "finish" ".*call bar \\(y, x\\)" +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" + +set test "quit #1" +gdb_test_multiple "quit" $test { + -re "The program is running. Quit anyway \\(and kill it\\)\\? \\(y or n\\) " { + pass $test + } +} +set test "quit #2" +gdb_test_multiple "y" $test { + eof { + pass $test + } +} diff --git a/gdb/testsuite/gdb.fortran/dynamic.f90 b/gdb/testsuite/gdb.fortran/dynamic.f90 new file mode 100644 index 0000000..0f43564 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/dynamic.f90 @@ -0,0 +1,98 @@ +! Copyright 2007 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 2 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +! +! Ihis file is the Fortran source file for dynamic.exp. +! Original file written by Jakub Jelinek . +! Modified for the GDB testcase by Jan Kratochvil . + +subroutine baz + real, target, allocatable :: varx (:, :, :) + real, pointer :: varv (:, :, :) + real, target :: varu (1, 2, 3) + logical :: l + allocate (varx (1:6, 5:15, 17:28)) ! varx-init + l = allocated (varx) + varx(:, :, :) = 6 ! varx-allocated + varx(1, 5, 17) = 7 + varx(2, 6, 18) = 8 + varx(6, 15, 28) = 9 + varv => varx ! varx-filled + l = associated (varv) + varv(3, 7, 19) = 10 ! varv-associated + varv => null () ! varv-filled + l = associated (varv) + deallocate (varx) ! varv-deassociated + l = allocated (varx) + varu(:, :, :) = 10 ! varx-deallocated + allocate (varv (1:6, 5:15, 17:28)) + l = associated (varv) + varv(:, :, :) = 6 + varv(1, 5, 17) = 7 + varv(2, 6, 18) = 8 + varv(6, 15, 28) = 9 + deallocate (varv) + l = associated (varv) + varv => varu + varv(1, 1, 1) = 6 + varv(1, 2, 3) = 7 + l = associated (varv) +end subroutine baz +subroutine foo (vary, varw) + real :: vary (:, :) + real :: varw (:, :, :) + vary(:, :) = 4 ! vary-passed + vary(1, 1) = 8 + vary(2, 2) = 9 + vary(1, 3) = 10 + varw(:, :, :) = 5 ! vary-filled + varw(1, 1, 1) = 6 + varw(2, 2, 2) = 7 ! varw-almostfilled +end subroutine foo +subroutine bar (varz, vart) + real :: varz (*) + real :: vart (2:11, 7:*) + varz(1:3) = 4 + varz(2) = 5 ! varz-almostfilled + vart(2,7) = vart(2,7) +end subroutine bar +program test + interface + subroutine foo (vary, varw) + real :: vary (:, :) + real :: varw (:, :, :) + end subroutine + end interface + interface + subroutine bar (varz, vart) + real :: varz (*) + real :: vart (2:11, 7:*) + end subroutine + end interface + real :: x (10, 10), y (5), z(8, 8, 8) + x(:,:) = 1 + y(:) = 2 + z(:,:,:) = 3 + call baz + call foo (x, z(2:6, 4:7, 6:8)) + call bar (y, x) + if (x (1, 1) .ne. 8 .or. x (2, 2) .ne. 9 .or. x (1, 2) .ne. 4) call abort + if (x (1, 3) .ne. 10) call abort + if (z (2, 4, 6) .ne. 6 .or. z (3, 5, 7) .ne. 7 .or. z (2, 4, 7) .ne. 5) call abort + if (any (y .ne. (/4, 5, 4, 2, 2/))) call abort + call foo (transpose (x), z) + if (x (1, 1) .ne. 8 .or. x (2, 2) .ne. 9 .or. x (1, 2) .ne. 4) call abort + if (x (3, 1) .ne. 10) call abort +end diff --git a/gdb/testsuite/gdb.fortran/logical.exp b/gdb/testsuite/gdb.fortran/logical.exp new file mode 100644 index 0000000..ef76f43 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/logical.exp @@ -0,0 +1,44 @@ +# Copyright 2007 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file was written by Jan Kratochvil . + +set testfile "logical" +set srcfile ${testfile}.f90 +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto MAIN__] then { + perror "couldn't run to breakpoint MAIN__" + continue +} + +gdb_breakpoint [gdb_get_line_number "stop-here"] +gdb_continue_to_breakpoint "stop-here" +gdb_test "p l" " = \\.TRUE\\." +gdb_test "p l1" " = \\.TRUE\\." +gdb_test "p l2" " = \\.TRUE\\." +gdb_test "p l4" " = \\.TRUE\\." +gdb_test "p l8" " = \\.TRUE\\." diff --git a/gdb/testsuite/gdb.fortran/logical.f90 b/gdb/testsuite/gdb.fortran/logical.f90 new file mode 100644 index 0000000..4229304 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/logical.f90 @@ -0,0 +1,33 @@ +! Copyright 2008 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 2 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +! +! Ihis file is the Fortran source file for dynamic.exp. +! Original file written by Jakub Jelinek . +! Modified for the GDB testcase by Jan Kratochvil . + +program test + logical :: l + logical (kind=1) :: l1 + logical (kind=2) :: l2 + logical (kind=4) :: l4 + logical (kind=8) :: l8 + l = .TRUE. + l1 = .TRUE. + l2 = .TRUE. + l4 = .TRUE. + l8 = .TRUE. + l = .FALSE. ! stop-here +end diff --git a/gdb/testsuite/gdb.fortran/string.exp b/gdb/testsuite/gdb.fortran/string.exp new file mode 100644 index 0000000..ab72206 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/string.exp @@ -0,0 +1,72 @@ +# Copyright 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file was written by Jan Kratochvil . + +# This file is part of the gdb testsuite. It contains tests for Fortran +# strings with dynamic length. + +set testfile "string" +set srcfile ${testfile}.f90 +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto MAIN__] then { + perror "couldn't run to breakpoint MAIN__" + continue +} + +gdb_breakpoint [gdb_get_line_number "var-init"] +gdb_continue_to_breakpoint "var-init" +gdb_test "ptype c" "type = character(\\(kind=1\\)|\\*1)" +gdb_test "ptype d" "type = character(\\(kind=8\\)|\\*8)" +gdb_test "ptype e" "type = character(\\(kind=4\\)|\\*4)" +gdb_test "ptype f" "type = character(\\(kind=4\\)|\\*4) \\(7,8:10\\)" +gdb_test "ptype *e" "Attempt to take contents of a non-pointer value." +gdb_test "ptype *f" "type = character(\\(kind=4\\)|\\*4) \\(7\\)" +gdb_test "p c" "\\$\[0-9\]* = 'c'" +gdb_test "p d" "\\$\[0-9\]* = 'd '" +gdb_test "p e" "\\$\[0-9\]* = 'g '" +gdb_test "p f" "\\$\[0-9\]* = \\(\\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\)" +gdb_test "p *e" "Attempt to take contents of a non-pointer value." +gdb_test "p *f" "Attempt to take contents of a non-pointer value." + +gdb_breakpoint [gdb_get_line_number "var-finish"] +gdb_continue_to_breakpoint "var-finish" +gdb_test "p e" "\\$\[0-9\]* = 'e '" "p e re-set" +gdb_test "p f" "\\$\[0-9\]* = \\(\\( 'f ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\( 'f2 ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\( 'f ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\)" "p *f re-set" + +set test "quit #1" +gdb_test_multiple "quit" $test { + -re "The program is running. Quit anyway \\(and kill it\\)\\? \\(y or n\\) " { + pass $test + } +} +set test "quit #2" +gdb_test_multiple "y" $test { + eof { + pass $test + } +} diff --git a/gdb/testsuite/gdb.fortran/string.f90 b/gdb/testsuite/gdb.fortran/string.f90 new file mode 100644 index 0000000..226dc5d --- /dev/null +++ b/gdb/testsuite/gdb.fortran/string.f90 @@ -0,0 +1,37 @@ +! Copyright 2008 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 2 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +! +! Ihis file is the Fortran source file for dynamic.exp. +! Original file written by Jakub Jelinek . +! Modified for the GDB testcase by Jan Kratochvil . + +subroutine foo (e, f) + character (len=1) :: c + character (len=8) :: d + character (len=*) :: e + character (len=*) :: f (1:7, 8:10) + c = 'c' + d = 'd' + e = 'e' ! var-init + f = 'f' + f(1,9) = 'f2' + c = 'c' ! var-finish +end subroutine foo + character (len=4) :: g, h (1:7, 8:10) + g = 'g' + h = 'h' + call foo (g, h) +end diff --git a/gdb/testsuite/gdb.gdb/selftest.exp b/gdb/testsuite/gdb.gdb/selftest.exp index 495ae45..d08d7a4 100644 --- a/gdb/testsuite/gdb.gdb/selftest.exp +++ b/gdb/testsuite/gdb.gdb/selftest.exp @@ -95,6 +95,10 @@ proc do_steps_and_nexts {} { set description "step over ttyarg initialization" set command "step" } + -re ".*python_script = 0.*$gdb_prompt $" { + set description "step over python_script initialization" + set command "step" + } -re ".*time_at_startup = get_run_time.*$gdb_prompt $" { set description "next over get_run_time and everything it calls" set command "next" diff --git a/gdb/testsuite/gdb.opt/array-from-register-func.c b/gdb/testsuite/gdb.opt/array-from-register-func.c new file mode 100644 index 0000000..729f457 --- /dev/null +++ b/gdb/testsuite/gdb.opt/array-from-register-func.c @@ -0,0 +1,22 @@ +/* This file is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +int +func (int *arr) +{ + return arr[0]; +} diff --git a/gdb/testsuite/gdb.opt/array-from-register.c b/gdb/testsuite/gdb.opt/array-from-register.c new file mode 100644 index 0000000..3090e7e --- /dev/null +++ b/gdb/testsuite/gdb.opt/array-from-register.c @@ -0,0 +1,28 @@ +/* This file is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +extern int func (int *arr); + +int +main (void) +{ + int arr[] = { 42 }; + + func (arr); + + return 0; +} diff --git a/gdb/testsuite/gdb.opt/array-from-register.exp b/gdb/testsuite/gdb.opt/array-from-register.exp new file mode 100644 index 0000000..f2de718 --- /dev/null +++ b/gdb/testsuite/gdb.opt/array-from-register.exp @@ -0,0 +1,33 @@ +# Copyright 2009 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# This file is part of the gdb testsuite. + +if { [prepare_for_testing array-from-register.exp "array-from-register" \ + {array-from-register.c array-from-register-func.c} \ + {debug optimize=-O2}] } { + return -1 +} + +if ![runto func] then { + return -1 +} + +gdb_test "p arr" "\\$\[0-9\]+ = \\(int \\*\\) *0x\[0-9a-f\]+" + +# Seen regression: +# Address requested for identifier "arr" which is in register $rdi +gdb_test "p arr\[0\]" "\\$\[0-9\]+ = 42" diff --git a/gdb/testsuite/gdb.python/Makefile.in b/gdb/testsuite/gdb.python/Makefile.in index 79be9e7..c49f713 100644 --- a/gdb/testsuite/gdb.python/Makefile.in +++ b/gdb/testsuite/gdb.python/Makefile.in @@ -1,7 +1,7 @@ VPATH = @srcdir@ srcdir = @srcdir@ -EXECUTABLES = python-value +EXECUTABLES = python-value python-prettyprint python-template all info install-info dvi install uninstall installcheck check: @echo "Nothing to be done for $@..." diff --git a/gdb/testsuite/gdb.python/find.c b/gdb/testsuite/gdb.python/find.c new file mode 100644 index 0000000..35ddd8c --- /dev/null +++ b/gdb/testsuite/gdb.python/find.c @@ -0,0 +1,64 @@ +/* Testcase for the search_memory Python function. + 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 . + + Please email any bugs, comments, and/or additions to this file to: + bug-gdb@gnu.org */ + +/* Based on the gdb.base/find.c testcase. */ + +#include +#include + +#define CHUNK_SIZE 16000 /* same as findcmd.c's */ +#define BUF_SIZE (2 * CHUNK_SIZE) /* at least two chunks */ + +static int8_t int8_search_buf[100]; +static int16_t int16_search_buf[100]; +static int32_t int32_search_buf[100]; +static int64_t int64_search_buf[100]; + +static char *search_buf; +static int search_buf_size; + +static int x; + +static void +stop_here () +{ + x = 1; // stop here +} + +static void +init_bufs () +{ + search_buf_size = BUF_SIZE; + search_buf = malloc (search_buf_size); + if (search_buf == NULL) + exit (1); + memset (search_buf, 'x', search_buf_size); +} + +int +main () +{ + init_bufs (); + + stop_here (); + + return 0; +} diff --git a/gdb/testsuite/gdb.python/find.exp b/gdb/testsuite/gdb.python/find.exp new file mode 100644 index 0000000..dd9aabc --- /dev/null +++ b/gdb/testsuite/gdb.python/find.exp @@ -0,0 +1,203 @@ +# 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 . + +# This tests the search_memory Python function. +# Based on the gdb.base/find.exp testcase. + +if $tracelevel then { + strace $tracelevel +} + +# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... +# Run a test named NAME, consisting of multiple lines of input. +# After each input line INPUT, search for result line RESULT. +# Succeed if all results are seen; fail otherwise. +proc gdb_py_test_multiple {name args} { + global gdb_prompt + foreach {input result} $args { + if {[gdb_test_multiple $input "$name - $input" { + -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { + pass "$name - $input" + } + }]} { + return 1 + } + } + return 0 +} + +set testfile "find" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug nowarnings}] != "" } { + untested find.exp + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +gdb_test_multiple "python print 'hello, world!'" "verify python support" { + -re "not supported.*$gdb_prompt $" { + unsupported "python support is disabled" + return -1 + } + -re "$gdb_prompt $" {} +} + +gdb_test "break $srcfile:stop_here" \ + "Breakpoint.*at.* file .*$srcfile, line.*" \ + "breakpoint function in file" + +gdb_run_cmd +gdb_expect { + -re "Breakpoint \[0-9\]+,.*stop_here.* at .*$srcfile:.*$gdb_prompt $" { + pass "run until function breakpoint" + } + -re "$gdb_prompt $" { + fail "run until function breakpoint" + } + timeout { + fail "run until function breakpoint (timeout)" + } +} + +# We've now got the target program in a state where we can test "find". + +set hex_number {0x[0-9a-fA-F][0-9a-fA-F]*} +set dec_number {[0-9]+} +set history_prefix {[$][0-9]* = } +set newline {[\r\n]+} +set pattern_not_found "${newline}.]" +set one_pattern_found "${newline}.${dec_number}L]" +set two_patterns_found "${newline}.${dec_number}L, ${dec_number}L]" + +# Test string pattern. + +gdb_test "set *(int32_t*) &int8_search_buf\[10\] = 0x61616161" "" "" +gdb_test "py search_buf = gdb.selected_frame ().read_var ('int8_search_buf')" "" "" +gdb_test "py start_addr = search_buf.address ()" "" "" +gdb_test "py length = search_buf.type ().sizeof ()" "" "" + +gdb_test "py print gdb.search_memory (start_addr, length, 'aaa')" \ + "${two_patterns_found}" "find string pattern" + +# Test not finding pattern because search range too small, with +# potential find at the edge of the range. + +gdb_test "py print gdb.search_memory (start_addr, 10+3, 'aaaa')" \ + "${pattern_not_found}" "pattern not found at end of range" + +# Increase the search range by 1 and we should find the pattern. + +gdb_test "py print gdb.search_memory (start_addr, 10+3+1, \['a', 'a', 'a', 'a'\])" \ + "${one_pattern_found}" "pattern found at end of range" + +# Test max-count with size, with different parameter position + +gdb_test "py print gdb.search_memory (start_addr, length, \[0x61, 0x61\], 1, 1)" \ + "${one_pattern_found}" "size = 1, max_count = 1" + +gdb_test "py print gdb.search_memory (start_addr, length, \[0x61, 0x61\], 1, 2)" \ + "${two_patterns_found}" "size = 1, max_count = 2, normal ordering" + +gdb_test "py print gdb.search_memory (start_addr, length, \[0x61, 0x61\], size = 1, max_count = 2)" \ + "${two_patterns_found}" "size = 1, max_count = 2, normal ordering, with keywords" + +gdb_test "py print gdb.search_memory (start_addr, length, \[0x61, 0x61\], max_count = 2, size = 1)" \ + "${two_patterns_found}" "size = 1, max_count = 2, inverted ordering" + +gdb_test "py print gdb.search_memory (start_addr, length, \['a', 'a'\], max_count = 2)" \ + "${two_patterns_found}" "max_count = 2, with keyword" + +# Test 16-bit pattern. + +gdb_test "set int16_search_buf\[10\] = 0x1234" "" "" +gdb_test "py search_buf = gdb.selected_frame ().read_var ('int16_search_buf')" "" "" +gdb_test "py start_addr = search_buf.address ()" "" "" +gdb_test "py length = search_buf.type ().sizeof ()" "" "" +gdb_test "py pattern = gdb.parse_and_eval ('(int16_t) 0x1234')" "" "" + +gdb_test "py print gdb.search_memory (start_addr, length, 0x1234, 2)" \ + "${one_pattern_found}" "find 16-bit pattern, with python pattern" + +gdb_test "py print gdb.search_memory (start_addr, length, pattern)" \ + "${one_pattern_found}" "find 16-bit pattern, with value pattern" + +# Test 32-bit pattern. + +gdb_test "set int32_search_buf\[10\] = 0x12345678" "" "" +gdb_test "py search_buf = gdb.selected_frame ().read_var ('int32_search_buf')" "" "" +gdb_test "py start_addr = search_buf.address ()" "" "" +gdb_test "py length = search_buf.type ().sizeof ()" "" "" +gdb_test "py pattern = gdb.parse_and_eval ('(int32_t) 0x12345678')" "" "" + +gdb_test "py print gdb.search_memory (start_addr, length, 0x12345678, 4)" \ + "${one_pattern_found}" "find 32-bit pattern, with python pattern" +gdb_test "py print gdb.search_memory (start_addr, length, pattern)" \ + "${one_pattern_found}" "find 32-bit pattern, with value pattern" + +# Test 64-bit pattern. + +gdb_test "set int64_search_buf\[10\] = 0xfedcba9876543210LL" "" "" +gdb_test "py search_buf = gdb.selected_frame ().read_var ('int64_search_buf')" "" "" +gdb_test "py start_addr = search_buf.address ()" "" "" +gdb_test "py length = search_buf.type ().sizeof ()" "" "" +gdb_test "py pattern = gdb.parse_and_eval ('(int64_t) 0xfedcba9876543210LL')" "" "" + +gdb_test "py print gdb.search_memory (start_addr, length, 0xfedcba9876543210, 8)" \ + "${one_pattern_found}" "find 64-bit pattern, with python pattern" +gdb_test "py print gdb.search_memory (start_addr, length, pattern)" \ + "${one_pattern_found}" "find 64-bit pattern, with value pattern" + +# Test mixed-sized patterns. + +gdb_test "set *(int8_t*) &search_buf\[10\] = 0x62" "" "" +gdb_test "set *(int16_t*) &search_buf\[11\] = 0x6363" "" "" +gdb_test "set *(int32_t*) &search_buf\[13\] = 0x64646464" "" "" +gdb_test "py search_buf = gdb.selected_frame ().read_var ('search_buf')" "" "" +gdb_test "py start_addr = search_buf\[0\].address ()" "" "" +gdb_test "py pattern1 = gdb.parse_and_eval ('(int8_t) 0x62')" "" "" +gdb_test "py pattern2 = gdb.parse_and_eval ('(int16_t) 0x6363')" "" "" +gdb_test "py pattern3 = gdb.parse_and_eval ('(int32_t) 0x64646464')" "" "" + +gdb_test "py print gdb.search_memory (start_addr, 100, \[pattern1, pattern2, pattern3\])" \ + "${one_pattern_found}" "find mixed-sized pattern" + +# Test search spanning a large range, in the particular case of native +# targets, test the search spanning multiple chunks. +# Remote targets may implement the search differently. + +set CHUNK_SIZE 16000 ; + +gdb_test "set *(int32_t*) &search_buf\[0*${CHUNK_SIZE}+100\] = 0x12345678" "" "" +gdb_test "set *(int32_t*) &search_buf\[1*${CHUNK_SIZE}+100\] = 0x12345678" "" "" +gdb_test "py start_addr = gdb.selected_frame ().read_var ('search_buf')" "" "" +gdb_test "py length = gdb.selected_frame ().read_var ('search_buf_size')" "" "" + +gdb_test "py print gdb.search_memory (start_addr, length, 0x12345678, 4)" \ + "${two_patterns_found}" "search spanning large range" + +# For native targets, test a pattern straddling a chunk boundary. + +if [isnative] { + gdb_test "set *(int32_t*) &search_buf\[${CHUNK_SIZE}-1\] = 0xfdb97531" "" "" + + gdb_test "py print gdb.search_memory (start_addr, length, 0xfdb97531, 4)" \ + "${one_pattern_found}" "find pattern straddling chunk boundary" +} diff --git a/gdb/testsuite/gdb.python/python-cmd.exp b/gdb/testsuite/gdb.python/python-cmd.exp index 6c73ff2..f6ef938 100644 --- a/gdb/testsuite/gdb.python/python-cmd.exp +++ b/gdb/testsuite/gdb.python/python-cmd.exp @@ -92,6 +92,32 @@ gdb_py_test_multiple "input subcommand" \ gdb_test "prefix_cmd subcmd ugh" "subcmd output, arg = ugh" "call subcmd" +# Test prefix command using keyword arguments. + +gdb_py_test_multiple "input prefix command, keyword arguments" \ + "python" "" \ + "class prefix_cmd2 (gdb.Command):" "" \ + " def __init__ (self):" "" \ + " super (prefix_cmd2, self).__init__ (\"prefix_cmd2\", gdb.COMMAND_OBSCURE, prefix = True, completer_class = gdb.COMPLETE_FILENAME)" "" \ + " def invoke (self, arg, from_tty):" "" \ + " print \"prefix_cmd2 output, arg = %s\" % arg" "" \ + "prefix_cmd2 ()" "" \ + "end" "" + +gdb_test "prefix_cmd2 argh" "prefix_cmd2 output, arg = argh" "call prefix command, keyword arguments" + +gdb_py_test_multiple "input subcommand under prefix_cmd2" \ + "python" "" \ + "class subcmd (gdb.Command):" "" \ + " def __init__ (self):" "" \ + " super (subcmd, self).__init__ (\"prefix_cmd2 subcmd\", gdb.COMMAND_OBSCURE)" "" \ + " def invoke (self, arg, from_tty):" "" \ + " print \"subcmd output, arg = %s\" % arg" "" \ + "subcmd ()" "" \ + "end" "" + +gdb_test "prefix_cmd2 subcmd ugh" "subcmd output, arg = ugh" "call subcmd under prefix_cmd2" + # Test a subcommand in an existing GDB prefix. gdb_py_test_multiple "input new subcommand" \ diff --git a/gdb/testsuite/gdb.python/python-frame.c b/gdb/testsuite/gdb.python/python-frame.c new file mode 100644 index 0000000..22eb9f2 --- /dev/null +++ b/gdb/testsuite/gdb.python/python-frame.c @@ -0,0 +1,14 @@ +int f2 (int a) +{ + return ++a; +} + +int f1 (int a, int b) +{ + return f2(a) + b; +} + +int main (int argc, char *argv[]) +{ + return f1 (1, 2); +} diff --git a/gdb/testsuite/gdb.python/python-frame.exp b/gdb/testsuite/gdb.python/python-frame.exp new file mode 100644 index 0000000..674c25e --- /dev/null +++ b/gdb/testsuite/gdb.python/python-frame.exp @@ -0,0 +1,92 @@ +# Copyright (C) 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is part of the GDB testsuite. It tests the mechanism +# exposing values to Python. + +if $tracelevel then { + strace $tracelevel +} + +set testfile "python-frame" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +# Run a command in GDB, and report a failure if a Python exception is thrown. +# If report_pass is true, report a pass if no exception is thrown. +proc gdb_py_test_silent_cmd {cmd name report_pass} { + global gdb_prompt + + gdb_test_multiple $cmd $name { + -re "Traceback.*$gdb_prompt $" { fail $name } + -re "$gdb_prompt $" { if $report_pass { pass $name } } + } +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +gdb_test_multiple "python print 'hello, world!'" "verify python support" { + -re "not supported.*$gdb_prompt $" { + unsupported "python support is disabled" + return -1 + } + -re "$gdb_prompt $" {} +} + +# The following tests require execution. + +if ![runto_main] then { + fail "Can't run to main" + return 0 +} + +gdb_breakpoint "f2" +gdb_continue_to_breakpoint "breakpoint at f2" +gdb_test "up" "" "" + +gdb_py_test_silent_cmd "python frames = gdb.frames ()" "get frames list" 1 +gdb_test "python print frames" "\\(, , \\)" "verify frames list" +gdb_py_test_silent_cmd "python f0 = frames\[0\]" "get first frame" 0 +gdb_py_test_silent_cmd "python f1 = frames\[1\]" "get second frame" 0 + +gdb_test "python print 'result =', f0.equals (f1)" " = False" "test equals (false)" +gdb_test "python print 'result =', f0.equals (f0)" " = True" "test equals (true)" +gdb_test "python print 'result =', f0.is_valid ()" " = True" "test Frame.is_valid" +gdb_test "python print 'result =', f0.name ()" " = f2" "test Frame.name" +gdb_test "python print 'result =', f0.type () == gdb.NORMAL_FRAME" " = True" "test Frame.type" +gdb_test "python print 'result =', f0.unwind_stop_reason () == gdb.FRAME_UNWIND_NO_REASON" " = True" "test Frame.type" +gdb_test "python print 'result =', gdb.frame_stop_reason_string (gdb.FRAME_UNWIND_INNER_ID)" " = previous frame inner to this frame \\(corrupt stack\\?\\)" "test gdb.frame_stop_reason_string" +gdb_test "python print 'result =', f0.pc ()" " = \[0-9\]+" "test Frame.pc" +gdb_test "python print 'result =', f0.addr_in_block ()" " = \[0-9\]+" "test Frame.addr_in_block" +gdb_test "python print 'result =', f0.older ().equals (f1)" " = True" "test Frame.older" +gdb_test "python print 'result =', f1.newer ().equals (f0)" " = True" "test Frame.newer" +gdb_test "python print 'result =', f0.read_var ('variable_which_surely_doesnt_exist')" \ + "ValueError: variable 'variable_which_surely_doesnt_exist' not found.*Error while executing Python code." \ + "test Frame.read_var - error" +gdb_test "python print 'result =', f0.read_var ('a')" " = 1" "test Frame.read_var - success" + +gdb_test "python print 'result =', gdb.newest_frame ().equals (f0)" " = True" "test gdb.newest_frame" +gdb_test "python print 'result =', gdb.selected_frame ().equals (f1)" " = True" "test gdb.selected_frame" + +gdb_test "python print 'result =', f0.block ()" "" "test Frame.block" diff --git a/gdb/testsuite/gdb.python/python-function.exp b/gdb/testsuite/gdb.python/python-function.exp new file mode 100644 index 0000000..7feca2b --- /dev/null +++ b/gdb/testsuite/gdb.python/python-function.exp @@ -0,0 +1,79 @@ +# Copyright (C) 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is part of the GDB testsuite. It tests the mechanism +# exposing convenience functions to Python. + +if $tracelevel then { + strace $tracelevel +} + +# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... +# Run a test named NAME, consisting of multiple lines of input. +# After each input line INPUT, search for result line RESULT. +# Succeed if all results are seen; fail otherwise. +proc gdb_py_test_multiple {name args} { + global gdb_prompt + foreach {input result} $args { + if {[gdb_test_multiple $input "$name - $input" { + -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { + pass "$name - $input" + } + }]} { + return 1 + } + } + return 0 +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +gdb_test_multiple "python print 'hello, world!'" "verify python support" { + -re "not supported.*$gdb_prompt $" { + unsupported "python support is disabled" + return -1 + } + -re "$gdb_prompt $" {} +} + +gdb_py_test_multiple "input convenience function" \ + "python" "" \ + "class test_func (gdb.Function):" "" \ + " def __init__ (self):" "" \ + " super (test_func, self).__init__ (\"test_func\")" "" \ + " def invoke (self, arg):" "" \ + " return \"test_func output, arg = %s\" % arg.string ()" "" \ + "test_func ()" "" \ + "end" "" + +gdb_test "print \$test_func (\"ugh\")" "= \"test_func output, arg = ugh\"" "call function" + +# Test returning a gdb.Value from the function. This segfaulted GDB at one point. + +gdb_py_test_multiple "input value-returning convenience function" \ + "python" "" \ + "class Double (gdb.Function):" "" \ + " def __init__ (self):" "" \ + " super (Double, self).__init__ (\"double\")" "" \ + " def invoke (self, n):" "" \ + " return n*2" "" \ + "Double ()" "" \ + "end" "" + +gdb_test "print \$double (1)" "= 2" "call value-returning function" diff --git a/gdb/testsuite/gdb.python/python-mi.exp b/gdb/testsuite/gdb.python/python-mi.exp new file mode 100644 index 0000000..5c9f3c7 --- /dev/null +++ b/gdb/testsuite/gdb.python/python-mi.exp @@ -0,0 +1,124 @@ +# 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 . + +# This file is part of the GDB testsuite. It tests Python-based +# pretty-printing for MI. + +load_lib mi-support.exp +set MIFLAGS "-i=mi2" + +gdb_exit +if [mi_gdb_start] { + continue +} + +set testfile "python-prettyprint" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DMI}] != "" } { + untested mi2-var-child.exp + return -1 +} + +mi_delete_breakpoints +mi_gdb_reinitialize_dir $srcdir/$subdir +mi_gdb_load ${binfile} + +if {[lsearch -exact [mi_get_features] python] < 0} { + unsupported "python support is disabled" + return -1 +} + +mi_runto main + +mi_gdb_test "python execfile ('${srcdir}/${subdir}/${testfile}.py')" "" + +mi_continue_to_line [gdb_get_line_number {MI breakpoint here} ${testfile}.c] \ + "step to breakpoint" + +mi_create_floating_varobj container c "create container varobj" + +mi_list_varobj_children container { +} "examine container children=0" + +mi_next "next over update 1" + +mi_varobj_update_dynamic container { + { {container.\[0\]} {\[0\]} 0 int } +} "varobj update 1" + +mi_next "next over update 2" + +mi_varobj_update_dynamic container { + { {container.\[0\]} {\[0\]} 0 int } + { {container.\[1\]} {\[1\]} 0 int } +} "varobj update 2" + +mi_gdb_test "-var-set-visualizer container None" \ + "\\^done" \ + "clear visualizer" + +mi_gdb_test "-var-update container" \ + "\\^done,changelist=\\\[\\\]" \ + "varobj update after clearing" + +mi_gdb_test "-var-set-visualizer container gdb.default_visualizer" \ + "\\^done" \ + "choose default visualizer" + +mi_varobj_update_dynamic container { + { {container.\[0\]} {\[0\]} 0 int } + { {container.\[1\]} {\[1\]} 0 int } +} "varobj update after choosing default" + +mi_gdb_test "-var-set-visualizer container ContainerPrinter" \ + "\\^done" \ + "choose visualizer using expression" + +mi_varobj_update_dynamic container { + { {container.\[0\]} {\[0\]} 0 int } + { {container.\[1\]} {\[1\]} 0 int } +} "varobj update after choosing via expression" + +mi_gdb_test "-var-set-child-range container 1 2" \ + "\\^done" \ + "select child range" + +mi_gdb_test "-var-update container" \ + "\\^done,changelist=\\\[\\\]" \ + "varobj update after selecting child range" + +mi_list_varobj_children_range container 2 { + { {container.\[1\]} {\[1\]} 0 int } +} "list varobj children after selecting child range" + +mi_gdb_test "-var-set-child-range container -1 -1" \ + "\\^done" \ + "reset child range" + +mi_gdb_test "-var-update container" \ + "\\^done,changelist=\\\[\\\]" \ + "varobj update after resetting child range" + +mi_list_varobj_children container { + { {container.\[0\]} {\[0\]} 0 int } + { {container.\[1\]} {\[1\]} 0 int } +} "list varobj children after resetting child range" + +mi_continue_to_line \ + [gdb_get_line_number {Another MI breakpoint} ${testfile}.c] \ + "step to second breakpoint" + +mi_varobj_update_with_type_change container int 0 "update after type change" diff --git a/gdb/testsuite/gdb.python/python-prettyprint.c b/gdb/testsuite/gdb.python/python-prettyprint.c new file mode 100644 index 0000000..f8c2435 --- /dev/null +++ b/gdb/testsuite/gdb.python/python-prettyprint.c @@ -0,0 +1,159 @@ +/* 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 . */ + +struct s +{ + int a; + int *b; +}; + +struct ss +{ + struct s a; + struct s b; +}; + +#ifdef __cplusplus +struct S : public s { + int zs; +}; + +struct SS { + int zss; + S s; +}; + +struct SSS +{ + SSS (int x, const S& r); + int a; + const S &b; +}; +SSS::SSS (int x, const S& r) : a(x), b(r) { } +#endif + +typedef struct string_repr +{ + struct whybother + { + const char *contents; + } whybother; +} string; + +/* This lets us avoid malloc. */ +int array[100]; + +struct container +{ + string name; + int len; + int *elements; +}; + +typedef struct container zzz_type; + +string +make_string (const char *s) +{ + string result; + result.whybother.contents = s; + return result; +} + +zzz_type +make_container (const char *s) +{ + zzz_type result; + + result.name = make_string (s); + result.len = 0; + result.elements = 0; + + return result; +} + +void +add_item (zzz_type *c, int val) +{ + if (c->len == 0) + c->elements = array; + c->elements[c->len] = val; + ++c->len; +} + +void init_s(struct s *s, int a) +{ + s->a = a; + s->b = &s->a; +} + +void init_ss(struct ss *s, int a, int b) +{ + init_s(&s->a, a); + init_s(&s->b, b); +} + +void do_nothing(void) +{ + int c; + + c = 23; /* Another MI breakpoint */ +} + +int +main () +{ + struct ss ss; + struct ss ssa[2]; + string x = make_string ("this is x"); + zzz_type c = make_container ("container"); + const struct string_repr cstring = { { "const string" } }; + + init_ss(&ss, 1, 2); + init_ss(ssa+0, 3, 4); + init_ss(ssa+1, 5, 6); + +#ifdef __cplusplus + S cps; + + cps.zs = 7; + init_s(&cps, 8); + + SS cpss; + cpss.zss = 9; + init_s(&cpss.s, 10); + + SS cpssa[2]; + cpssa[0].zss = 11; + init_s(&cpssa[0].s, 12); + cpssa[1].zss = 13; + init_s(&cpssa[1].s, 14); + + SSS sss(15, cps); + + SSS& ref (sss); +#endif + + add_item (&c, 23); /* MI breakpoint here */ + add_item (&c, 72); + +#ifdef MI + do_nothing (); +#endif + + return 0; /* break to inspect struct and union */ +} diff --git a/gdb/testsuite/gdb.python/python-prettyprint.exp b/gdb/testsuite/gdb.python/python-prettyprint.exp new file mode 100644 index 0000000..b2ccb2b --- /dev/null +++ b/gdb/testsuite/gdb.python/python-prettyprint.exp @@ -0,0 +1,90 @@ +# 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 . + +# This file is part of the GDB testsuite. It tests Python-based +# pretty-printing for the CLI. + +if $tracelevel then { + strace $tracelevel +} + +set testfile "python-prettyprint" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +# Start with a fresh gdb. +gdb_exit +gdb_start +gdb_test_multiple "python print 'hello, world!'" "verify python support" { + -re "not supported.*$gdb_prompt $" { + unsupported "python support is disabled" + return -1 + } + -re "$gdb_prompt $" {} +} + +proc run_lang_tests {lang} { + global srcdir subdir srcfile binfile testfile hex + if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug $lang"] != "" } { + untested "Couldn't compile ${srcfile} in $lang mode" + return -1 + } + + set nl "\[\r\n\]+" + + # Start with a fresh gdb. + gdb_exit + gdb_start + gdb_reinitialize_dir $srcdir/$subdir + gdb_load ${binfile} + + + if ![runto_main ] then { + perror "couldn't run to breakpoint" + return + } + + gdb_test "set print pretty on" "" + + gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \ + ".*Breakpoint.*" + gdb_test "continue" ".*Breakpoint.*" + + gdb_test "python execfile ('${srcdir}/${subdir}/${testfile}.py')" "" + + gdb_test "print ss" " = a=< a=<1> b=<$hex>> b=< a=<2> b=<$hex>>" + gdb_test "print ssa\[1\]" " = a=< a=<5> b=<$hex>> b=< a=<6> b=<$hex>>" + gdb_test "print ssa" " = {a=< a=<3> b=<$hex>> b=< a=<4> b=<$hex>>, a=< a=<5> b=<$hex>> b=< a=<6> b=<$hex>>}" + + if {$lang == "c++"} { + gdb_test "print cps" "= a=<8> b=<$hex>" + gdb_test "print cpss" " = {$nl *zss = 9, *$nl *s = a=<10> b=<$hex>$nl}" + gdb_test "print cpssa\[0\]" " = {$nl *zss = 11, *$nl *s = a=<12> b=<$hex>$nl}" + gdb_test "print cpssa\[1\]" " = {$nl *zss = 13, *$nl *s = a=<14> b=<$hex>$nl}" + gdb_test "print cpssa" " = {{$nl *zss = 11, *$nl *s = a=<12> b=<$hex>$nl *}, {$nl *zss = 13, *$nl *s = a=<14> b=<$hex>$nl *}}" + gdb_test "print sss" "= a=<15> b=< a=<8> b=<$hex>>" + gdb_test "print ref" "= a=<15> b=< a=<8> b=<$hex>>" + } + + gdb_test "print x" " = $hex \"this is x\"" + gdb_test "print cstring" " = $hex \"const string\"" + + gdb_test "print c" " = container $hex \"container\" with 2 elements = {$nl *.0. = 23,$nl *.1. = 72$nl}" + + gdb_test "continue" "Program exited normally\." +} + +run_lang_tests "c" +run_lang_tests "c++" diff --git a/gdb/testsuite/gdb.python/python-prettyprint.py b/gdb/testsuite/gdb.python/python-prettyprint.py new file mode 100644 index 0000000..0d9cb87 --- /dev/null +++ b/gdb/testsuite/gdb.python/python-prettyprint.py @@ -0,0 +1,134 @@ +# 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 . + +# This file is part of the GDB testsuite. It tests python pretty +# printers. + +import re + +# Test returning a Value from a printer. +class string_print: + def __init__(self, val): + self.val = val + + def to_string(self): + return self.val['whybother']['contents'] + +# Test a class-based printer. +class ContainerPrinter: + class _iterator: + def __init__ (self, pointer, len): + self.start = pointer + self.pointer = pointer + self.end = pointer + len + + def __iter__(self): + return self + + def next(self): + if self.pointer == self.end: + raise StopIteration + result = self.pointer + self.pointer = self.pointer + 1 + return ('[%d]' % int (result - self.start), result.dereference()) + + def __init__(self, val): + self.val = val + + def to_string(self): + return 'container %s with %d elements' % (self.val['name'], self.val['len']) + + def children(self): + return self._iterator(self.val['elements'], self.val['len']) + +class pp_s: + def __init__(self, val): + self.val = val + + def to_string(self): + a = self.val["a"] + b = self.val["b"] + if a.address() != b: + raise Exception("&a(%s) != b(%s)" % (str(a.address()), str(b))) + return " a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">" + +class pp_ss: + def __init__(self, val): + self.val = val + + def to_string(self): + return "a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">" + +class pp_sss: + def __init__(self, val): + self.val = val + + def to_string(self): + return "a=<" + str(self.val['a']) + "> b=<" + str(self.val["b"]) + ">" + +def lookup_function (val): + "Look-up and return a pretty-printer that can print val." + + # Get the type. + type = val.type (); + + # If it points to a reference, get the reference. + if type.code () == gdb.TYPE_CODE_REF: + type = type.target () + + # Get the unqualified type, stripped of typedefs. + type = type.unqualified ().strip_typedefs () + + # Get the type name. + typename = type.tag () + + if typename == None: + return None + + # Iterate over local dictionary of types to determine + # if a printer is registered for that type. Return an + # instantiation of the printer if found. + for function in pretty_printers_dict: + if function.match (typename): + return pretty_printers_dict[function] (val) + + # Cannot find a pretty printer. Return None. + + return None + + +def register_pretty_printers (): + pretty_printers_dict[re.compile ('^struct s$')] = pp_s + pretty_printers_dict[re.compile ('^s$')] = pp_s + pretty_printers_dict[re.compile ('^S$')] = pp_s + + pretty_printers_dict[re.compile ('^struct ss$')] = pp_ss + pretty_printers_dict[re.compile ('^ss$')] = pp_ss + pretty_printers_dict[re.compile ('^const S &$')] = pp_s + pretty_printers_dict[re.compile ('^SSS$')] = pp_sss + + # Note that we purposely omit the typedef names here. + # Printer lookup is based on canonical name. + # However, we do need both tagged and untagged variants, to handle + # both the C and C++ cases. + pretty_printers_dict[re.compile ('^struct string_repr$')] = string_print + pretty_printers_dict[re.compile ('^struct container$')] = ContainerPrinter + pretty_printers_dict[re.compile ('^string_repr$')] = string_print + pretty_printers_dict[re.compile ('^container$')] = ContainerPrinter + +pretty_printers_dict = {} + +register_pretty_printers () +gdb.pretty_printers.append (lookup_function) diff --git a/gdb/testsuite/gdb.python/python-template.cc b/gdb/testsuite/gdb.python/python-template.cc new file mode 100644 index 0000000..bd6a212 --- /dev/null +++ b/gdb/testsuite/gdb.python/python-template.cc @@ -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 . */ + +template +struct Foo { +}; + +#ifndef TYPE +#define TYPE int +#endif + +int main() +{ + Foo foo; + return 0; // break here +} diff --git a/gdb/testsuite/gdb.python/python-template.exp b/gdb/testsuite/gdb.python/python-template.exp new file mode 100644 index 0000000..561ff73 --- /dev/null +++ b/gdb/testsuite/gdb.python/python-template.exp @@ -0,0 +1,75 @@ +# 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 . + +# This file is part of the GDB testsuite. It tests the mechanism +# exposing values to Python. + +if $tracelevel then { + strace $tracelevel +} + +set testfile "python-template" +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \ + {debug c++}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +gdb_test_multiple "python print 23" "verify python support" { + -re "not supported.*$gdb_prompt $" { + unsupported "python support is disabled" + return -1 + } + -re "$gdb_prompt $" {} +} + +proc test_template_arg {type} { + global testfile srcdir subdir srcfile binfile + if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ + executable \ + [list debug c++ additional_flags="-DTYPE=$type"]] != "" } { + untested $type + return -1 + } + gdb_load ${binfile} + if ![runto_main ] then { + perror "couldn't run to breakpoint" + return + } + # There is no executable code in main(), so we are where we want to be + gdb_test "print foo" "" + gdb_test "python foo = gdb.history(0)" "" + + # Replace '*' with '\*' in regex. + regsub -all {\*} $type {\*} t + gdb_test "python print foo.type().template_argument(0)" $t $type +} + +test_template_arg "const int" +test_template_arg "volatile int" +test_template_arg "const int &" +test_template_arg "volatile int &" +test_template_arg "volatile int * const" +test_template_arg "volatile int * const *" +test_template_arg "const int * volatile" +test_template_arg "const int * volatile * const * volatile *" diff --git a/gdb/testsuite/gdb.python/python-value.c b/gdb/testsuite/gdb.python/python-value.c index 17e5c62..9637fe9 100644 --- a/gdb/testsuite/gdb.python/python-value.c +++ b/gdb/testsuite/gdb.python/python-value.c @@ -33,13 +33,17 @@ enum e TWO = 2 }; +typedef struct s *PTR; + enum e evalue = TWO; int main (int argc, char *argv[]) { + char *cp = argv[0]; /* Prevent gcc from optimizing argv[] out. */ struct s s; union u u; + PTR x = &s; s.a = 3; s.b = 5; diff --git a/gdb/testsuite/gdb.python/python-value.exp b/gdb/testsuite/gdb.python/python-value.exp index 8f5e0ab..9ca9593 100644 --- a/gdb/testsuite/gdb.python/python-value.exp +++ b/gdb/testsuite/gdb.python/python-value.exp @@ -227,6 +227,37 @@ proc test_value_in_inferior {} { gdb_test "python print arg0" "0x.*$testfile\"" "verify dereferenced value" } +proc test_value_after_death {} { + # Construct a type while the inferior is still running. + gdb_py_test_silent_cmd "python ptrtype = gdb.Type('PTR')" \ + "create PTR type" 1 + + # Check the type has the expected name. + gdb_test "python print ptrtype" "PTR" \ + "check initial PTR type" + + # Kill the inferior and remove the symbols. + gdb_test "kill" "" "kill the inferior" \ + "Kill the program being debugged. .y or n. $" \ + "y" + gdb_test "file" "" "Discard the symbols" \ + "Discard symbol table from.*y or n. $" \ + "y" + + # Now create a value using that type. Relies on arg0, created by + # test_value_in_inferior. + gdb_py_test_silent_cmd "python castval = arg0.cast(ptrtype.pointer())" \ + "cast arg0 to PTR" 1 + + # Make sure the type is deleted. + gdb_py_test_silent_cmd "python ptrtype = None" \ + "delete PTR type" 1 + + # Now see if the value's type is still valid. + gdb_test "python print castval.type()" "PTR \\*" \ + "print value's type" +} + # Start with a fresh gdb. @@ -256,3 +287,4 @@ if ![runto_main] then { } test_value_in_inferior +test_value_after_death diff --git a/gdb/testsuite/lib/cp-support.exp b/gdb/testsuite/lib/cp-support.exp index dbd2f59..44e1b51 100644 --- a/gdb/testsuite/lib/cp-support.exp +++ b/gdb/testsuite/lib/cp-support.exp @@ -222,7 +222,7 @@ proc cp_test_ptype_class { in_command in_testname in_key in_tag in_class_table { set parse_okay 0 gdb_test_multiple "$in_command" "$in_testname // parse failed" { - -re "type = (struct|class)${wsopt}(\[A-Za-z0-9_\]*)${wsopt}((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" { + -re "type = (struct|class)${wsopt}(\[A-Za-z0-9_:\]*)${wsopt}((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" { set parse_okay 1 set actual_key $expect_out(1,string) set actual_tag $expect_out(2,string) @@ -231,6 +231,7 @@ proc cp_test_ptype_class { in_command in_testname in_key in_tag in_class_table { set actual_tail $expect_out(6,string) } } + if { ! $parse_okay } then { return } # Check the actual key. It would be nice to require that it match diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 820ab20..8b8e7c6 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -1162,9 +1162,12 @@ proc default_gdb_start { } { global gdb_prompt global timeout global gdb_spawn_id; + global env gdb_stop_suppressing_tests; + set env(LC_CTYPE) C + verbose "Spawning $GDB $INTERNAL_GDBFLAGS $GDBFLAGS" if [info exists gdb_spawn_id] { diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp index f62c240..bda7ea1 100644 --- a/gdb/testsuite/lib/mi-support.exp +++ b/gdb/testsuite/lib/mi-support.exp @@ -1237,6 +1237,21 @@ proc mi_varobj_update_with_type_change { name new_type new_children testname } { mi_gdb_test "-var-update $name" $er $testname } +# Update a dynamic varobj named NAME. CHILDREN is a list of children, +# in the same form as mi_list_varobj_children. TESTNAME is the name +# of the test. +proc mi_varobj_update_dynamic {name children testname} { + set children_exp_j [mi_child_regexp $children 0] + + set er "\\^done,changelist=\\\[" + + append er "{name=\"$name\",in_scope=\"true\",type_changed=\"false\"" + append er ",children=\\\[$children_exp_j.*\\\]}\\\]" + + verbose -log "Expecting: $er" + mi_gdb_test "-var-update $name" $er $testname +} + proc mi_check_varobj_value { name value testname } { mi_gdb_test "-var-evaluate-expression $name" \ @@ -1244,6 +1259,42 @@ proc mi_check_varobj_value { name value testname } { $testname } +# Helper proc which constructs a child regexp for +# mi_list_varobj_children and mi_varobj_update_dynamic. +proc mi_child_regexp {children add_child} { + set children_exp {} + set whatever "\"\[^\"\]+\"" + + if {$add_child} { + set pre "child=" + } else { + set pre "" + } + + foreach item $children { + + set name [lindex $item 0] + set exp [lindex $item 1] + set numchild [lindex $item 2] + if {[llength $item] == 5} { + set type [lindex $item 3] + set value [lindex $item 4] + + lappend children_exp\ + "$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",value=\"$value\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}" + } elseif {[llength $item] == 4} { + set type [lindex $item 3] + + lappend children_exp\ + "$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}" + } else { + lappend children_exp\ + "$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\"(,thread-id=\"\[0-9\]+\")?}" + } + } + return [join $children_exp ","] +} + # Check the results of the: # # -var-list-children VARNAME @@ -1265,39 +1316,23 @@ proc mi_check_varobj_value { name value testname } { # have no value. # proc mi_list_varobj_children { varname children testname } { + mi_list_varobj_children_range $varname [llength $children] $children \ + $testname +} +# Like mi_list_varobj_children, but assumes that a subrange has been +# selected with -var-set-child-range. NUMCHILDREN is the total number +# of children. +proc mi_list_varobj_children_range {varname numchildren children testname} { set options "" if {[llength $varname] == 2} { set options [lindex $varname 1] set varname [lindex $varname 0] } - set numchildren [llength $children] - set children_exp {} set whatever "\"\[^\"\]+\"" - foreach item $children { - - set name [lindex $item 0] - set exp [lindex $item 1] - set numchild [lindex $item 2] - if {[llength $item] == 5} { - set type [lindex $item 3] - set value [lindex $item 4] - - lappend children_exp\ - "child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",value=\"$value\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}" - } elseif {[llength $item] == 4} { - set type [lindex $item 3] - - lappend children_exp\ - "child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}" - } else { - lappend children_exp\ - "child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\"(,thread-id=\"\[0-9\]+\")?}" - } - } - set children_exp_j [join $children_exp ","] + set children_exp_j [mi_child_regexp $children 1] if {$numchildren} { set expected "\\^done,numchild=\".*\",children=\\\[$children_exp_j.*\\\]" } { @@ -1770,3 +1805,25 @@ proc mi_check_thread_states { xstates test } { verbose -log "expecting: $pattern" mi_gdb_test "-thread-info" $pattern $test } + +# Return a list of MI features supported by this gdb. +proc mi_get_features {} { + global expect_out mi_gdb_prompt + + send_gdb "-list-features\n" + + gdb_expect { + -re "\\^done,features=\\\[(.*)\\\]\r\n$mi_gdb_prompt$" { + regsub -all -- \" $expect_out(1,string) "" features + return [split $features ,] + } + -re ".*\r\n$mi_gdb_prompt$" { + verbose -log "got $expect_out(buffer)" + return "" + } + timeout { + verbose -log "timeout in mi_gdb_prompt" + return "" + } + } +} diff --git a/gdb/thread.c b/gdb/thread.c index 9dea7c2..326e44e 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -61,7 +61,6 @@ static int thread_alive (struct thread_info *); static void info_threads_command (char *, int); static void thread_apply_command (char *, int); static void restore_current_thread (ptid_t); -static void prune_threads (void); /* Frontend view of the thread state. Possible extensions: stepping, finishing, until(ling),... */ @@ -459,16 +458,23 @@ thread_alive (struct thread_info *tp) return 1; } -static void +void prune_threads (void) { - struct thread_info *tp, *next; + struct thread_info *tp; + struct thread_info **prevp = &thread_list; - for (tp = thread_list; tp; tp = next) + for (tp = *prevp; tp; tp = *prevp) { - next = tp->next; + /* If the thread has died, free it and unlink it from the list. + Otherwise, advance to the next thread. */ if (!thread_alive (tp)) - delete_thread (tp->ptid); + { + *prevp = tp->next; + free_thread (tp); + } + else + prevp = &tp->next; } } diff --git a/gdb/top.c b/gdb/top.c index d676f02..d6b17f0 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -377,6 +377,7 @@ execute_command (char *p, int from_tty) } free_all_values (); + free_all_types (); /* Force cleanup of any alloca areas if using C alloca instead of a builtin alloca. */ @@ -1246,7 +1247,8 @@ quit_target (void *arg) struct qt_args *qt = (struct qt_args *)arg; /* Kill or detach all inferiors. */ - iterate_over_inferiors (kill_or_detach, qt); + if (target_has_execution) + iterate_over_inferiors (kill_or_detach, qt); /* Give all pushed targets a chance to do minimal cleanup, and pop them all out. */ diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index 83df64e..003ef3a 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -1587,7 +1587,7 @@ encode_actions (struct tracepoint *t, char ***tdp_actions, case UNOP_MEMVAL: /* safe because we know it's a simple expression */ tempval = evaluate_expression (exp); - addr = VALUE_ADDRESS (tempval) + value_offset (tempval); + addr = value_address (tempval); len = TYPE_LENGTH (check_typedef (exp->elts[1].type)); add_memrange (collect, memrange_absolute, addr, len); break; diff --git a/gdb/typeprint.c b/gdb/typeprint.c index 1f824fa..4a92a13 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 extern void _initialize_typeprint (void); @@ -76,6 +77,9 @@ void type_print (struct type *type, char *varstring, struct ui_file *stream, int show) { + if (show >= 0) + type = check_typedef (type); + LA_PRINT_TYPE (type, varstring, stream, show, 0); } @@ -115,7 +119,8 @@ whatis_exp (char *exp, int show) { struct expression *expr; struct value *val; - struct cleanup *old_chain = NULL; + /* Required at least for the object_address_set call. */ + struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); struct type *real_type = NULL; struct type *type; int full = 0; @@ -126,12 +131,13 @@ whatis_exp (char *exp, int show) if (exp) { expr = parse_expression (exp); - old_chain = make_cleanup (free_current_contents, &expr); + make_cleanup (free_current_contents, &expr); val = evaluate_type (expr); } else val = access_value_history (0); + object_address_set (VALUE_ADDRESS (val)); type = value_type (val); get_user_print_options (&opts); @@ -168,8 +174,7 @@ whatis_exp (char *exp, int show) type_print (type, "", gdb_stdout, show); printf_filtered ("\n"); - if (exp) - do_cleanups (old_chain); + do_cleanups (old_chain); } static void @@ -236,7 +241,7 @@ print_type_scalar (struct type *type, LONGEST val, struct ui_file *stream) break; case TYPE_CODE_CHAR: - LA_PRINT_CHAR ((unsigned char) val, stream); + LA_PRINT_CHAR ((unsigned char) val, type, stream); break; case TYPE_CODE_BOOL: diff --git a/gdb/typeprint.h b/gdb/typeprint.h index f561310..b39fd17 100644 --- a/gdb/typeprint.h +++ b/gdb/typeprint.h @@ -26,4 +26,6 @@ void print_type_scalar (struct type * type, LONGEST, struct ui_file *); void c_type_print_varspec_suffix (struct type *, struct ui_file *, int, int, int); + +void c_type_print_args (struct type *, struct ui_file *, int); #endif diff --git a/gdb/ui-file.c b/gdb/ui-file.c index 02a0314..5c8c96e 100644 --- a/gdb/ui-file.c +++ b/gdb/ui-file.c @@ -22,6 +22,7 @@ #include "defs.h" #include "ui-file.h" +#include "gdb_obstack.h" #include "gdb_string.h" #include @@ -263,7 +264,7 @@ set_ui_file_data (struct ui_file *file, void *data, } /* ui_file utility function for converting a ``struct ui_file'' into - a memory buffer''. */ + a memory buffer. */ struct accumulated_ui_file { @@ -297,6 +298,23 @@ ui_file_xstrdup (struct ui_file *file, *length = acc.length; return acc.buffer; } + +static void +do_ui_file_obsavestring (void *context, const char *buffer, long length) +{ + struct obstack *obstack = (struct obstack *) context; + obstack_grow (obstack, buffer, length); +} + +char * +ui_file_obsavestring (struct ui_file *file, struct obstack *obstack, + long *length) +{ + ui_file_put (file, do_ui_file_obsavestring, obstack); + *length = obstack_object_size (obstack); + obstack_1grow (obstack, '\0'); + return obstack_finish (obstack); +} /* A pure memory based ``struct ui_file'' that can be used an output buffer. The buffers accumulated contents are available via diff --git a/gdb/ui-file.h b/gdb/ui-file.h index 1562d5a..d86a7eb 100644 --- a/gdb/ui-file.h +++ b/gdb/ui-file.h @@ -19,6 +19,7 @@ #ifndef UI_FILE_H #define UI_FILE_H +struct obstack; struct ui_file; /* Create a generic ui_file object with null methods. */ @@ -77,7 +78,10 @@ extern void ui_file_put (struct ui_file *src, ui_file_put_method_ftype *write, v appended NUL. */ extern char *ui_file_xstrdup (struct ui_file *file, long *length); - +/* Similar to ui_file_xstrdup, but return a new string allocated on + OBSTACK. */ +extern char *ui_file_obsavestring (struct ui_file *file, + struct obstack *obstack, long *length); extern long ui_file_read (struct ui_file *file, char *buf, long length_buf); diff --git a/gdb/utils.c b/gdb/utils.c index 9224839..88a9a39 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -272,6 +272,19 @@ make_cleanup_fclose (FILE *file) } static void +do_obstack_free (void *arg) +{ + struct obstack *ob = arg; + obstack_free (ob, NULL); +} + +struct cleanup * +make_cleanup_obstack_free (struct obstack *obstack) +{ + return make_cleanup (do_obstack_free, obstack); +} + +static void do_ui_file_delete (void *arg) { ui_file_delete (arg); @@ -1554,21 +1567,33 @@ query (const char *ctlstr, ...) va_end (args); } -/* Print an error message saying that we couldn't make sense of a - \^mumble sequence in a string or character constant. START and END - indicate a substring of some larger string that contains the - erroneous backslash sequence, missing the initial backslash. */ -static NORETURN int -no_control_char_error (const char *start, const char *end) +/* A helper for parse_escape that converts a host character to a + target character. C is the host character. If conversion is + possible, then the target character is stored in *TARGET_C and the + function returns 1. Otherwise, the function returns 0. */ + +static int +host_char_to_target (int c, int *target_c) { - int len = end - start; - char *copy = alloca (end - start + 1); + struct obstack host_data; + char the_char = c; + struct cleanup *cleanups; + int result = 0; + + obstack_init (&host_data); + cleanups = make_cleanup_obstack_free (&host_data); + + convert_between_encodings (target_charset (), host_charset (), + &the_char, 1, 1, &host_data, translit_none); - memcpy (copy, start, len); - copy[len] = '\0'; + if (obstack_object_size (&host_data) == 1) + { + result = 1; + *target_c = *(char *) obstack_base (&host_data); + } - error (_("There is no control character `\\%s' in the `%s' character set."), - copy, target_charset ()); + do_cleanups (cleanups); + return result; } /* Parse a C escape sequence. STRING_PTR points to a variable @@ -1591,53 +1616,13 @@ parse_escape (char **string_ptr) { int target_char; int c = *(*string_ptr)++; - if (c_parse_backslash (c, &target_char)) - return target_char; - else - switch (c) - { + switch (c) + { case '\n': return -2; case 0: (*string_ptr)--; return 0; - case '^': - { - /* Remember where this escape sequence started, for reporting - errors. */ - char *sequence_start_pos = *string_ptr - 1; - - c = *(*string_ptr)++; - - if (c == '?') - { - /* XXXCHARSET: What is `delete' in the host character set? */ - c = 0177; - - if (!host_char_to_target (c, &target_char)) - error (_("There is no character corresponding to `Delete' " - "in the target character set `%s'."), host_charset ()); - - return target_char; - } - else if (c == '\\') - target_char = parse_escape (string_ptr); - else - { - if (!host_char_to_target (c, &target_char)) - no_control_char_error (sequence_start_pos, *string_ptr); - } - - /* Now target_char is something like `c', and we want to find - its control-character equivalent. */ - if (!target_char_to_control_char (target_char, &target_char)) - no_control_char_error (sequence_start_pos, *string_ptr); - - return target_char; - } - - /* XXXCHARSET: we need to use isdigit and value-of-digit - methods of the host character set here. */ case '0': case '1': @@ -1648,16 +1633,16 @@ parse_escape (char **string_ptr) case '6': case '7': { - int i = c - '0'; + int i = host_hex_value (c); int count = 0; while (++count < 3) { c = (**string_ptr); - if (c >= '0' && c <= '7') + if (isdigit (c) && c != '8' && c != '9') { (*string_ptr)++; i *= 8; - i += c - '0'; + i += host_hex_value (c); } else { @@ -1666,14 +1651,39 @@ parse_escape (char **string_ptr) } return i; } - default: - if (!host_char_to_target (c, &target_char)) - error - ("The escape sequence `\%c' is equivalent to plain `%c', which" - " has no equivalent\n" "in the `%s' character set.", c, c, - target_charset ()); - return target_char; - } + + case 'a': + c = '\a'; + break; + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = '\v'; + break; + + default: + break; + } + + if (!host_char_to_target (c, &target_char)) + error + ("The escape sequence `\%c' is equivalent to plain `%c', which" + " has no equivalent\n" "in the `%s' character set.", c, c, + target_charset ()); + return target_char; } /* Print the character C on STREAM as part of the contents of a literal diff --git a/gdb/v850-tdep.c b/gdb/v850-tdep.c index 9850de4..285fe3f 100644 --- a/gdb/v850-tdep.c +++ b/gdb/v850-tdep.c @@ -705,7 +705,7 @@ v850_push_dummy_call (struct gdbarch *gdbarch, if (!v850_type_is_scalar (value_type (*args)) && TYPE_LENGTH (value_type (*args)) > E_MAX_RETTYPE_SIZE_IN_REGS) { - store_unsigned_integer (valbuf, 4, VALUE_ADDRESS (*args)); + store_unsigned_integer (valbuf, 4, value_address (*args)); len = 4; val = valbuf; } diff --git a/gdb/valarith.c b/gdb/valarith.c index f38cdb8..8e103cf 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -164,9 +164,9 @@ an integer nor a pointer of the same type.")); struct value * value_subscript (struct value *array, struct value *idx) { - struct value *bound; int c_style = current_language->c_style_arrays; struct type *tarray; + LONGEST index = value_as_long (idx); array = coerce_ref (array); tarray = check_typedef (value_type (array)); @@ -179,13 +179,26 @@ value_subscript (struct value *array, struct value *idx) get_discrete_bounds (range_type, &lowerbound, &upperbound); if (VALUE_LVAL (array) != lval_memory) - return value_subscripted_rvalue (array, idx, lowerbound); + { + if (index >= lowerbound && index <= upperbound) + { + CORE_ADDR element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (tarray)); + CORE_ADDR offset = (index - lowerbound) * element_size; + + return value_subscripted_rvalue (array, offset); + } + error (_("array or string index out of range")); + } if (c_style == 0) { - LONGEST index = value_as_long (idx); if (index >= lowerbound && index <= upperbound) - return value_subscripted_rvalue (array, idx, lowerbound); + { + CORE_ADDR element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (tarray)); + CORE_ADDR offset = (index - lowerbound) * element_size; + + return value_subscripted_rvalue (array, offset); + } /* Emit warning unless we have an array of unknown size. An array of unknown size has lowerbound 0 and upperbound -1. */ if (upperbound > -1) @@ -194,49 +207,52 @@ value_subscript (struct value *array, struct value *idx) c_style = 1; } - if (lowerbound != 0) - { - bound = value_from_longest (value_type (idx), (LONGEST) lowerbound); - idx = value_binop (idx, bound, BINOP_SUB); - } - + index -= lowerbound; array = value_coerce_array (array); } if (c_style) - return value_ind (value_ptradd (array, idx)); + { + struct value *idx; + + idx = value_from_longest (builtin_type_int32, index); + return value_ind (value_ptradd (array, idx)); + } else error (_("not an array or string")); } -/* Return the value of EXPR[IDX], expr an aggregate rvalue - (eg, a vector register). This routine used to promote floats - to doubles, but no longer does. */ +/* Return the value of *((void *) ARRAY + ELEMENT), ARRAY an aggregate rvalue + (eg, a vector register). This routine used to promote floats to doubles, + but no longer does. OFFSET is zero-based with 0 for the lowermost existing + element, it must be expressed in bytes (therefore multiplied by + check_typedef (TYPE_TARGET_TYPE (array_type)). */ struct value * -value_subscripted_rvalue (struct value *array, struct value *idx, int lowerbound) +value_subscripted_rvalue (struct value *array, CORE_ADDR offset) { struct type *array_type = check_typedef (value_type (array)); struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (array_type)); - unsigned int elt_size = TYPE_LENGTH (elt_type); - LONGEST index = value_as_long (idx); - unsigned int elt_offs = elt_size * longest_to_int (index - lowerbound); struct value *v; - if (index < lowerbound || elt_offs >= TYPE_LENGTH (array_type)) - error (_("no such vector element")); + /* Do not check TYPE_LENGTH (array_type) as we may have been given the + innermost dimension of a multi-dimensional Fortran array where its length + is shorter than the possibly accessed element offset. */ v = allocate_value (elt_type); if (VALUE_LVAL (array) == lval_memory && value_lazy (array)) set_value_lazy (v, 1); else - memcpy (value_contents_writeable (v), - value_contents (array) + elt_offs, elt_size); + { + unsigned int elt_size = TYPE_LENGTH (elt_type); + memcpy (value_contents_writeable (v), + value_contents (array) + offset, elt_size); + } set_value_component_location (v, array); VALUE_REGNUM (v) = VALUE_REGNUM (array); VALUE_FRAME_ID (v) = VALUE_FRAME_ID (array); - set_value_offset (v, value_offset (array) + elt_offs); + set_value_offset (v, value_offset (array) + offset); return v; } diff --git a/gdb/valops.c b/gdb/valops.c index 9810f2b..14c562e 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -38,6 +38,7 @@ #include "cp-support.h" #include "dfp.h" #include "user-regs.h" +#include "dwarf2loc.h" #include #include "gdb_string.h" @@ -254,9 +255,8 @@ value_cast_structs (struct type *type, struct value *v2) if (v) { /* Downcasting is possible (t1 is superclass of v2). */ - CORE_ADDR addr2 = VALUE_ADDRESS (v2); - addr2 -= (VALUE_ADDRESS (v) - + value_offset (v) + CORE_ADDR addr2 = value_address (v2); + addr2 -= (value_address (v) + value_embedded_offset (v)); return value_at (type, addr2); } @@ -371,8 +371,6 @@ value_cast (struct type *type, struct value *arg2) new_length = val_length / element_length; if (val_length % element_length != 0) warning (_("array element type size does not divide object size in cast")); - /* FIXME-type-allocation: need a way to free this type when - we are done with it. */ range_type = create_range_type ((struct type *) NULL, TYPE_TARGET_TYPE (range_type), low_bound, @@ -511,7 +509,7 @@ value_cast (struct type *type, struct value *arg2) } else if (VALUE_LVAL (arg2) == lval_memory) return value_at_lazy (type, - VALUE_ADDRESS (arg2) + value_offset (arg2)); + value_address (arg2)); else if (code1 == TYPE_CODE_VOID) { return value_zero (builtin_type_void, not_lval); @@ -568,6 +566,64 @@ value_one (struct type *type, enum lval_type lv) return val; } +/* object_address_set must be already called before this function. */ + +const char * +object_address_data_not_valid (struct type *type) +{ + /* Attributes are present only at the target type of a typedef. Make the + call conditional as it would otherwise loop through type_length_get. */ + if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) + CHECK_TYPEDEF (type); + + /* DW_AT_associated has a preference over DW_AT_allocated. */ + if (TYPE_NOT_ASSOCIATED (type) + || (TYPE_ASSOCIATED (type) != NULL + && 0 == dwarf_locexpr_baton_eval (TYPE_ASSOCIATED (type)))) + return N_("object is not associated"); + + if (TYPE_NOT_ALLOCATED (type) + || (TYPE_ALLOCATED (type) != NULL + && 0 == dwarf_locexpr_baton_eval (TYPE_ALLOCATED (type)))) + return N_("object is not allocated"); + + return NULL; +} + +/* Return non-zero if the variable is valid. If it is valid the function + may store the data address (DW_AT_DATA_LOCATION) of TYPE at *ADDRESS_RETURN. + You must set *ADDRESS_RETURN as VALUE_ADDRESS (VAL) before calling this + function. If no DW_AT_DATA_LOCATION is present for TYPE the address at + *ADDRESS_RETURN is left unchanged. ADDRESS_RETURN must not be NULL, use + object_address_data_not_valid () for just the data validity check. */ + +int +object_address_get_data (struct type *type, CORE_ADDR *address_return) +{ + gdb_assert (address_return != NULL); + + object_address_set (*address_return); + + /* TYPE_DATA_LOCATION_DWARF_BLOCK / TYPE_DATA_LOCATION_ADDR are present only + at the target type of a typedef. */ + CHECK_TYPEDEF (type); + + if (object_address_data_not_valid (type) != NULL) + { + /* Do not try to evaluate DW_AT_data_location as it may even crash + (it would just return the value zero in the gfortran case). */ + return 0; + } + + if (TYPE_DATA_LOCATION_IS_ADDR (type)) + *address_return = TYPE_DATA_LOCATION_ADDR (type); + else if (TYPE_DATA_LOCATION_DWARF_BLOCK (type) != NULL) + *address_return + = dwarf_locexpr_baton_eval (TYPE_DATA_LOCATION_DWARF_BLOCK (type)); + + return 1; +} + /* Return a value with type TYPE located at ADDR. Call value_at only if the data needs to be fetched immediately; @@ -593,7 +649,7 @@ value_at (struct type *type, CORE_ADDR addr) read_memory (addr, value_contents_all_raw (val), TYPE_LENGTH (type)); VALUE_LVAL (val) = lval_memory; - VALUE_ADDRESS (val) = addr; + set_value_address (val, addr); return val; } @@ -611,7 +667,7 @@ value_at_lazy (struct type *type, CORE_ADDR addr) val = allocate_value_lazy (type); VALUE_LVAL (val) = lval_memory; - VALUE_ADDRESS (val) = addr; + set_value_address (val, addr); return val; } @@ -637,11 +693,19 @@ value_fetch_lazy (struct value *val) allocate_value_contents (val); if (VALUE_LVAL (val) == lval_memory) { - CORE_ADDR addr = VALUE_ADDRESS (val) + value_offset (val); - int length = TYPE_LENGTH (check_typedef (value_enclosing_type (val))); + CORE_ADDR addr = VALUE_ADDRESS (val); + + if (object_address_get_data (value_type (val), &addr)) + { + struct type *type = value_enclosing_type (val); + int length = TYPE_LENGTH (check_typedef (type)); - if (length) - read_memory (addr, value_contents_all_raw (val), length); + if (length) + { + addr += value_offset (val); + read_memory (addr, value_contents_all_raw (val), length); + } + } } else if (VALUE_LVAL (val) == lval_register) { @@ -709,7 +773,7 @@ value_fetch_lazy (struct value *val) VALUE_REGNUM (new_val)); else if (VALUE_LVAL (new_val) == lval_memory) fprintf_unfiltered (gdb_stdlog, " address=0x%s", - paddr_nz (VALUE_ADDRESS (new_val))); + paddr_nz (value_address (new_val))); else fprintf_unfiltered (gdb_stdlog, " computed"); @@ -813,16 +877,15 @@ value_assign (struct value *toval, struct value *fromval) error (_("Can't handle bitfields which don't fit in a %d bit word."), (int) sizeof (LONGEST) * HOST_CHAR_BIT); - read_memory (VALUE_ADDRESS (toval) + value_offset (toval), - buffer, changed_len); + read_memory (value_address (toval), buffer, changed_len); modify_field (buffer, value_as_long (fromval), value_bitpos (toval), value_bitsize (toval)); - changed_addr = VALUE_ADDRESS (toval) + value_offset (toval); + changed_addr = value_address (toval); dest_buffer = buffer; } else { - changed_addr = VALUE_ADDRESS (toval) + value_offset (toval); + changed_addr = value_address (toval); changed_len = TYPE_LENGTH (type); dest_buffer = value_contents (fromval); } @@ -985,11 +1048,11 @@ value_repeat (struct value *arg1, int count) val = allocate_repeat_value (value_enclosing_type (arg1), count); - read_memory (VALUE_ADDRESS (arg1) + value_offset (arg1), + read_memory (value_address (arg1), value_contents_all_raw (val), TYPE_LENGTH (value_enclosing_type (val))); VALUE_LVAL (val) = lval_memory; - VALUE_ADDRESS (val) = VALUE_ADDRESS (arg1) + value_offset (arg1); + set_value_address (val, value_address (arg1)); return val; } @@ -1036,10 +1099,11 @@ address_of_variable (struct symbol *var, struct block *b) val = value_of_variable (var, b); - if ((VALUE_LVAL (val) == lval_memory && value_lazy (val)) + if ((VALUE_LVAL (val) == lval_memory && value_lazy (val) + && object_address_get_data (type, &VALUE_ADDRESS (val))) || TYPE_CODE (type) == TYPE_CODE_FUNC) { - CORE_ADDR addr = VALUE_ADDRESS (val); + CORE_ADDR addr = value_address (val); return value_from_pointer (lookup_pointer_type (type), addr); } @@ -1145,6 +1209,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 @@ -1154,8 +1219,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_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) + value_offset (arg1))); + address + value_offset (arg1)); } /* Given a value which is a function, return a value which is a pointer @@ -1170,7 +1239,7 @@ value_coerce_function (struct value *arg1) error (_("Attempt to take address of value not located in memory.")); retval = value_from_pointer (lookup_pointer_type (value_type (arg1)), - (VALUE_ADDRESS (arg1) + value_offset (arg1))); + (value_address (arg1))); return retval; } @@ -1205,8 +1274,7 @@ value_addr (struct value *arg1) /* Get target memory address */ arg2 = value_from_pointer (lookup_pointer_type (value_type (arg1)), - (VALUE_ADDRESS (arg1) - + value_offset (arg1) + (value_address (arg1) + value_embedded_offset (arg1))); /* This may be a pointer to a base subobject; so remember the @@ -1352,6 +1420,24 @@ value_array (int lowbound, int highbound, struct value **elemvec) return val; } +struct value * +value_typed_string (char *ptr, int len, struct type *char_type) +{ + struct value *val; + int lowbound = current_language->string_lower_bound; + int highbound = len / TYPE_LENGTH (char_type); + struct type *rangetype = create_range_type ((struct type *) NULL, + builtin_type_int32, + lowbound, + highbound + lowbound - 1); + struct type *stringtype + = create_array_type ((struct type *) NULL, char_type, rangetype); + + val = allocate_value (stringtype); + memcpy (value_contents_raw (val), ptr, len); + return val; +} + /* Create a value for a string constant by allocating space in the inferior, copying the data into that space, and returning the address with type TYPE_CODE_STRING. PTR points to the string @@ -1600,8 +1686,7 @@ search_struct_field (char *name, struct value *arg1, int offset, boffset = baseclass_offset (type, i, value_contents (arg1) + offset, - VALUE_ADDRESS (arg1) - + value_offset (arg1) + offset); + value_address (arg1) + offset); if (boffset == -1) error (_("virtual baseclass botch")); @@ -1616,13 +1701,13 @@ search_struct_field (char *name, struct value *arg1, int offset, v2 = allocate_value (basetype); base_addr = - VALUE_ADDRESS (arg1) + value_offset (arg1) + boffset; + value_address (arg1) + boffset; if (target_read_memory (base_addr, value_contents_raw (v2), TYPE_LENGTH (basetype)) != 0) error (_("virtual baseclass botch")); VALUE_LVAL (v2) = lval_memory; - VALUE_ADDRESS (v2) = base_addr; + set_value_address (v2, base_addr); } else { @@ -1745,8 +1830,7 @@ search_struct_method (char *name, struct value **arg1p, if (offset < 0 || offset >= TYPE_LENGTH (type)) { gdb_byte *tmp = alloca (TYPE_LENGTH (baseclass)); - if (target_read_memory (VALUE_ADDRESS (*arg1p) - + value_offset (*arg1p) + offset, + if (target_read_memory (value_address (*arg1p) + offset, tmp, TYPE_LENGTH (baseclass)) != 0) error (_("virtual baseclass botch")); base_valaddr = tmp; @@ -1755,8 +1839,7 @@ search_struct_method (char *name, struct value **arg1p, base_valaddr = value_contents (*arg1p) + offset; base_offset = baseclass_offset (type, i, base_valaddr, - VALUE_ADDRESS (*arg1p) - + value_offset (*arg1p) + offset); + value_address (*arg1p) + offset); if (base_offset == -1) error (_("virtual baseclass botch")); } @@ -1965,7 +2048,7 @@ find_method_list (struct value **argp, char *method, base_offset = value_offset (*argp) + offset; base_offset = baseclass_offset (type, i, value_contents (*argp) + base_offset, - VALUE_ADDRESS (*argp) + base_offset); + value_address (*argp) + base_offset); if (base_offset == -1) error (_("virtual baseclass botch")); } @@ -2083,12 +2166,25 @@ find_overload_match (struct type **arg_types, int nargs, if (method) { gdb_assert (obj); + + /* OBJ may be a pointer value rather than the object itself. */ + obj = coerce_ref (obj); + while (TYPE_CODE (check_typedef (value_type (obj))) == TYPE_CODE_PTR) + obj = coerce_ref (value_ind (obj)); obj_type_name = TYPE_NAME (value_type (obj)); - /* Hack: evaluate_subexp_standard often passes in a pointer - value rather than the object itself, so try again. */ - if ((!obj_type_name || !*obj_type_name) - && (TYPE_CODE (value_type (obj)) == TYPE_CODE_PTR)) - obj_type_name = TYPE_NAME (TYPE_TARGET_TYPE (value_type (obj))); + + /* First check whether this is a data member, e.g. a pointer to + a function. */ + if (TYPE_CODE (check_typedef (value_type (obj))) == TYPE_CODE_STRUCT) + { + *valp = search_struct_field (name, obj, 0, + check_typedef (value_type (obj)), 0); + if (*valp) + { + *staticp = 1; + return 0; + } + } fns_ptr = value_find_oload_method_list (&temp, name, 0, &num_fns, @@ -2108,16 +2204,29 @@ find_overload_match (struct type **arg_types, int nargs, } else { - const char *qualified_name = SYMBOL_CPLUS_DEMANGLED_NAME (fsym); + const char *qualified_name = SYMBOL_NATURAL_NAME (fsym); - /* If we have a C++ name, try to extract just the function - part. */ - if (qualified_name) - func_name = cp_func_name (qualified_name); + /* If we have a function with a C++ name, try to extract just + the function part. Do not try this for non-functions (e.g. + function pointers). */ + if (qualified_name + && TYPE_CODE (check_typedef (SYMBOL_TYPE (fsym))) == TYPE_CODE_FUNC) + { + func_name = cp_func_name (qualified_name); + + /* If cp_func_name did not remove anything, the name of the + symbol did not include scope or argument types - it was + probably a C-style function. */ + if (func_name && strcmp (func_name, qualified_name) == 0) + { + xfree (func_name); + func_name = NULL; + } + } - /* If there was no C++ name, this must be a C-style function. - Just return the same symbol. Do the same if cp_func_name - fails for some reason. */ + /* If there was no C++ name, this must be a C-style function or + not a function at all. Just return the same symbol. Do the + same if cp_func_name fails for some reason. */ if (func_name == NULL) { *symp = fsym; @@ -2558,8 +2667,8 @@ check_field (struct type *type, const char *name) the comment before value_struct_elt_for_reference. */ struct value * -value_aggregate_elt (struct type *curtype, - char *name, int want_address, +value_aggregate_elt (struct type *curtype, char *name, + struct type *expect_type, int want_address, enum noside noside) { switch (TYPE_CODE (curtype)) @@ -2567,7 +2676,7 @@ value_aggregate_elt (struct type *curtype, case TYPE_CODE_STRUCT: case TYPE_CODE_UNION: return value_struct_elt_for_reference (curtype, 0, curtype, - name, NULL, + name, expect_type, want_address, noside); case TYPE_CODE_NAMESPACE: return value_namespace_elt (curtype, name, @@ -2671,7 +2780,7 @@ value_struct_elt_for_reference (struct type *domain, int offset, if (intype) { while (j--) - if (TYPE_FN_FIELD_TYPE (f, j) == intype) + if (compare_parameters (TYPE_FN_FIELD_TYPE (f, j), intype)) break; if (j < 0) error (_("no member function matches that type instantiation")); @@ -2725,7 +2834,7 @@ value_struct_elt_for_reference (struct type *domain, int offset, result = allocate_value (lookup_methodptr_type (TYPE_FN_FIELD_TYPE (f, j))); cplus_make_method_ptr (value_type (result), value_contents_writeable (result), - VALUE_ADDRESS (v), 0); + value_address (v), 0); } } return result; @@ -2791,7 +2900,7 @@ value_maybe_namespace_elt (const struct type *curtype, struct symbol *sym; struct value *result; - sym = cp_lookup_symbol_namespace (namespace_name, name, NULL, + sym = cp_lookup_symbol_namespace_incremental (namespace_name, name, NULL, get_selected_block (0), VAR_DOMAIN); @@ -2884,7 +2993,7 @@ value_full_object (struct value *argp, /* Go back by the computed top_offset from the beginning of the object, adjusting for the embedded offset of argp if that's what value_rtti_type used for its computation. */ - new_val = value_at_lazy (real_type, VALUE_ADDRESS (argp) - top + + new_val = value_at_lazy (real_type, value_address (argp) - top + (using_enc ? 0 : value_embedded_offset (argp))); deprecated_set_value_type (new_val, value_type (argp)); set_value_embedded_offset (new_val, (using_enc @@ -2989,8 +3098,6 @@ value_slice (struct value *array, int lowbound, int length) || lowbound + length - 1 > upperbound) error (_("slice out of range")); - /* FIXME-type-allocation: need a way to free this type when we are - done with it. */ slice_range_type = create_range_type ((struct type *) NULL, TYPE_TARGET_TYPE (range_type), lowbound, diff --git a/gdb/valprint.c b/gdb/valprint.c index b02e9df..a9e8227 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -34,6 +34,7 @@ #include "doublest.h" #include "exceptions.h" #include "dfp.h" +#include "python/python.h" #include @@ -80,7 +81,9 @@ struct value_print_options user_print_options = 0, /* print_array_indexes */ 0, /* deref_ref */ 1, /* static_field_print */ - 1 /* pascal_static_field_print */ + 1, /* pascal_static_field_print */ + 0, /* raw */ + 0 /* summary */ }; /* Initialize *OPTS to be a copy of the user print options. */ @@ -257,6 +260,15 @@ val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, return (0); } + if (!options->raw) + { + ret = apply_val_pretty_printer (type, valaddr, embedded_offset, + address, stream, recurse, options, + language); + if (ret) + return ret; + } + TRY_CATCH (except, RETURN_MASK_ERROR) { ret = language->la_val_print (type, valaddr, embedded_offset, address, @@ -287,6 +299,13 @@ value_check_printable (struct value *val, struct ui_file *stream) return 0; } + if (TYPE_CODE (value_type (val)) == TYPE_CODE_INTERNAL_FUNCTION) + { + fprintf_filtered (stream, _(""), + value_internal_function_name (val)); + return 0; + } + return 1; } @@ -308,7 +327,7 @@ common_val_print (struct value *val, struct ui_file *stream, int recurse, return 0; return val_print (value_type (val), value_contents_all (val), - value_embedded_offset (val), VALUE_ADDRESS (val), + value_embedded_offset (val), value_address (val), stream, recurse, options, language); } @@ -324,6 +343,18 @@ value_print (struct value *val, struct ui_file *stream, if (!value_check_printable (val, stream)) return 0; + if (!options->raw) + { + int r = apply_val_pretty_printer (value_type (val), + value_contents_all (val), + value_embedded_offset (val), + value_address (val), + stream, 0, options, + current_language); + if (r) + return r; + } + return LA_VALUE_PRINT (val, stream, options); } @@ -919,7 +950,8 @@ print_hex_chars (struct ui_file *stream, const gdb_byte *valaddr, Omit any leading zero chars. */ void -print_char_chars (struct ui_file *stream, const gdb_byte *valaddr, +print_char_chars (struct ui_file *stream, struct type *type, + const gdb_byte *valaddr, unsigned len, enum bfd_endian byte_order) { const gdb_byte *p; @@ -932,7 +964,7 @@ print_char_chars (struct ui_file *stream, const gdb_byte *valaddr, while (p < valaddr + len) { - LA_EMIT_CHAR (*p, stream, '\''); + LA_EMIT_CHAR (*p, type, stream, '\''); ++p; } } @@ -944,7 +976,7 @@ print_char_chars (struct ui_file *stream, const gdb_byte *valaddr, while (p >= valaddr) { - LA_EMIT_CHAR (*p, stream, '\''); + LA_EMIT_CHAR (*p, type, stream, '\''); --p; } } @@ -1085,6 +1117,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, for (; i < len && things_printed < options->print_max; i++) { + size_t elt_offset = i * eltlen; if (i != 0) { if (options->prettyprint_arrays) @@ -1104,7 +1137,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, rep1 = i + 1; reps = 1; while ((rep1 < len) && - !memcmp (valaddr + i * eltlen, valaddr + rep1 * eltlen, eltlen)) + !memcmp (valaddr + elt_offset, valaddr + rep1 * eltlen, eltlen)) { ++reps; ++rep1; @@ -1112,7 +1145,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, if (reps > options->repeat_count_threshold) { - val_print (elttype, valaddr + i * eltlen, 0, address + i * eltlen, + val_print (elttype, valaddr + elt_offset, 0, address + elt_offset, stream, recurse + 1, options, current_language); annotate_elt_rep (reps); fprintf_filtered (stream, " ", reps); @@ -1123,7 +1156,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, } else { - val_print (elttype, valaddr + i * eltlen, 0, address + i * eltlen, + val_print (elttype, valaddr + elt_offset, 0, address + elt_offset, stream, recurse + 1, options, current_language); annotate_elt (); things_printed++; @@ -1315,7 +1348,8 @@ read_string (CORE_ADDR addr, int len, int width, unsigned int fetchlimit, whichever is smaller. */ int -val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream, +val_print_string (struct type *elttype, CORE_ADDR addr, int len, + struct ui_file *stream, const struct value_print_options *options) { int force_ellipsis = 0; /* Force ellipsis to be printed if nonzero. */ @@ -1325,6 +1359,7 @@ val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream, int bytes_read; gdb_byte *buffer = NULL; /* Dynamically growable fetch buffer. */ struct cleanup *old_chain = NULL; /* Top of the old cleanup chain. */ + int width = TYPE_LENGTH (elttype); /* First we need to figure out the limit on the number of characters we are going to attempt to fetch and print. This is actually pretty simple. If @@ -1378,7 +1413,7 @@ val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream, { fputs_filtered (" ", stream); } - LA_PRINT_STRING (stream, buffer, bytes_read / width, width, force_ellipsis, options); + LA_PRINT_STRING (stream, elttype, buffer, bytes_read / width, force_ellipsis, options); } if (errcode != 0) diff --git a/gdb/valprint.h b/gdb/valprint.h index 8b65af6..4f63fa6 100644 --- a/gdb/valprint.h +++ b/gdb/valprint.h @@ -84,6 +84,12 @@ struct value_print_options /* If nonzero, print static fields for Pascal. FIXME: C++ and Java share one flag, why not Pascal too? */ int pascal_static_field_print; + + /* Controls Python pretty-printing. */ + int raw; + + /* If nonzero, print the value in "summary" form. */ + int summary; }; /* The global print options set by the user. In general this should @@ -134,9 +140,10 @@ extern void print_decimal_chars (struct ui_file *, const gdb_byte *, extern void print_hex_chars (struct ui_file *, const gdb_byte *, unsigned int, enum bfd_endian); -extern void print_char_chars (struct ui_file *, const gdb_byte *, - unsigned int, enum bfd_endian); +extern void print_char_chars (struct ui_file *, struct type *, + const gdb_byte *, unsigned int, enum bfd_endian); int read_string (CORE_ADDR addr, int len, int width, unsigned int fetchlimit, gdb_byte **buffer, int *bytes_read); + #endif diff --git a/gdb/value.c b/gdb/value.c index 4d4329e..5c81d83 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -36,6 +36,7 @@ #include "block.h" #include "dfp.h" #include "objfiles.h" +#include "cli/cli-decode.h" #include "valprint.h" #include "python/python.h" @@ -44,6 +45,23 @@ void _initialize_values (void); +/* Definition of a user function. */ +struct internal_function +{ + /* The name of the function. It is a bit odd to have this in the + function itself -- the user might use a differently-named + convenience variable to hold the function. */ + char *name; + + /* The handler. */ + internal_function_fn handler; + + /* User data for the handler. */ + void *cookie; +}; + +static struct cmd_list_element *functionlist; + struct value { /* Type of value; either not an lval, or one of the various @@ -203,6 +221,10 @@ struct value_history_chunk static struct value_history_chunk *value_history_chain; static int value_history_count; /* Abs number of last entry stored */ + +/* The type of internal functions. */ + +static struct type *internal_fn_type; /* List of all value objects currently allocated (except for those released by calls to release_value) @@ -225,9 +247,11 @@ allocate_value_lazy (struct type *type) val->next = all_values; all_values = val; val->type = type; + type_incref (type); val->enclosing_type = type; + type_incref (type); VALUE_LVAL (val) = not_lval; - VALUE_ADDRESS (val) = 0; + val->location.address = 0; VALUE_FRAME_ID (val) = null_frame_id; val->offset = 0; val->bitpos = 0; @@ -269,13 +293,9 @@ struct value * allocate_repeat_value (struct type *type, int count) { int low_bound = current_language->string_lower_bound; /* ??? */ - /* FIXME-type-allocation: need a way to free this type when we are - done with it. */ struct type *range_type = create_range_type ((struct type *) NULL, builtin_type_int32, low_bound, count + low_bound - 1); - /* FIXME-type-allocation: need a way to free this type when we are - done with it. */ return allocate_value (create_array_type ((struct type *) NULL, type, range_type)); } @@ -335,6 +355,8 @@ value_type (struct value *value) void deprecated_set_value_type (struct value *value, struct type *type) { + type_incref (type); + type_decref (value->type); value->type = type; } @@ -509,6 +531,32 @@ deprecated_value_address_hack (struct value *value) return &value->location.address; } +CORE_ADDR +value_address (struct value *value) +{ + if (value->lval == lval_internalvar + || value->lval == lval_internalvar_component) + return 0; + return value->location.address + value->offset; +} + +CORE_ADDR +value_raw_address (struct value *value) +{ + if (value->lval == lval_internalvar + || value->lval == lval_internalvar_component) + return 0; + return value->location.address; +} + +void +set_value_address (struct value *value, CORE_ADDR addr) +{ + gdb_assert (value->lval != lval_internalvar + && value->lval != lval_internalvar_component); + value->location.address = addr; +} + struct internalvar ** deprecated_value_internalvar_hack (struct value *value) { @@ -547,11 +595,16 @@ value_mark (void) return all_values; } +/* Deallocate a value and run destructors if needed. */ + void value_free (struct value *val) { if (val) { + type_decref (val->type); + type_decref (val->enclosing_type); + if (VALUE_LVAL (val) == lval_computed) { struct lval_funcs *funcs = val->location.computed.funcs; @@ -655,6 +708,8 @@ value_copy (struct value *arg) val = allocate_value_lazy (encl_type); else val = allocate_value (encl_type); + type_incref (arg->type); + type_decref (val->type); val->type = arg->type; VALUE_LVAL (val) = VALUE_LVAL (arg); val->location = arg->location; @@ -693,6 +748,7 @@ set_value_component_location (struct value *component, struct value *whole) VALUE_LVAL (component) = VALUE_LVAL (whole); component->location = whole->location; + if (VALUE_LVAL (whole) == lval_computed) { struct lval_funcs *funcs = whole->location.computed.funcs; @@ -700,6 +756,8 @@ set_value_component_location (struct value *component, struct value *whole) if (funcs->copy_closure) component->location.computed.closure = funcs->copy_closure (whole); } + + object_address_get_data (value_type (whole), &VALUE_ADDRESS (component)); } @@ -830,6 +888,25 @@ 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; +} /* Internal variables. These are variables within the debugger that hold values assigned by debugger commands. @@ -878,7 +955,7 @@ init_if_undefined_command (char* args, int from_tty) the return value is NULL. */ struct internalvar * -lookup_only_internalvar (char *name) +lookup_only_internalvar (const char *name) { struct internalvar *var; @@ -894,7 +971,7 @@ lookup_only_internalvar (char *name) NAME should not normally include a dollar sign. */ struct internalvar * -create_internalvar (char *name) +create_internalvar (const char *name) { struct internalvar *var; var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); @@ -902,6 +979,7 @@ create_internalvar (char *name) var->value = allocate_value (builtin_type_void); var->endian = gdbarch_byte_order (current_gdbarch); var->make_value = NULL; + var->canonical = 0; release_value (var->value); var->next = internalvars; internalvars = var; @@ -934,7 +1012,7 @@ create_internalvar_type_lazy (char *name, internalvar_make_value fun) one is created, with a void value. */ struct internalvar * -lookup_internalvar (char *name) +lookup_internalvar (const char *name) { struct internalvar *var; @@ -1031,6 +1109,9 @@ set_internalvar (struct internalvar *var, struct value *val) { struct value *newval; + if (var->canonical) + error (_("Cannot overwrite convenience function %s"), var->name); + newval = value_copy (val); newval->modifiable = 1; @@ -1042,7 +1123,7 @@ set_internalvar (struct internalvar *var, struct value *val) /* Begin code which must not call error(). If var->value points to something free'd, an error() obviously leaves a dangling pointer. - But we also get a danling pointer if var->value points to + But we also get a dangling pointer if var->value points to something in the value chain (i.e., before release_value is called), because after the error free_all_values will get called before long. */ @@ -1059,6 +1140,76 @@ internalvar_name (struct internalvar *var) return var->name; } +static struct value * +value_create_internal_function (const char *name, + internal_function_fn handler, + void *cookie) +{ + struct value *result = allocate_value (internal_fn_type); + gdb_byte *addr = value_contents_writeable (result); + struct internal_function **fnp = (struct internal_function **) addr; + struct internal_function *ifn = XNEW (struct internal_function); + ifn->name = xstrdup (name); + ifn->handler = handler; + ifn->cookie = cookie; + *fnp = ifn; + return result; +} + +char * +value_internal_function_name (struct value *val) +{ + gdb_byte *addr = value_contents_writeable (val); + struct internal_function *ifn = * (struct internal_function **) addr; + return ifn->name; +} + +struct value * +call_internal_function (struct value *func, int argc, struct value **argv) +{ + gdb_byte *addr = value_contents_writeable (func); + struct internal_function *ifn = * (struct internal_function **) addr; + return (*ifn->handler) (ifn->cookie, argc, argv); +} + +/* 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 + registering an internal function. */ +static void +function_command (char *command, int from_tty) +{ + /* Do nothing. */ +} + +/* Clean up if an internal function's command is destroyed. */ +static void +function_destroyer (struct cmd_list_element *self, void *ignore) +{ + xfree (self->name); + xfree (self->doc); +} + +/* Add a new internal function. NAME is the name of the function; DOC + is a documentation string describing the function. HANDLER is + called when the function is invoked. COOKIE is an arbitrary + pointer which is passed to HANDLER and is intended for "user + data". */ +void +add_internal_function (const char *name, const char *doc, + internal_function_fn handler, void *cookie) +{ + struct cmd_list_element *cmd; + struct internalvar *var = lookup_internalvar (name); + struct value *fnval = value_create_internal_function (name, handler, cookie); + set_internalvar (var, fnval); + var->canonical = 1; + + cmd = add_cmd (xstrdup (name), no_class, function_command, (char *) doc, + &functionlist); + cmd->destroyer = function_destroyer; +} + /* Update VALUE before discarding OBJFILE. COPIED_TYPES is used to prevent cycles / duplicates. */ @@ -1067,12 +1218,21 @@ 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); + { + /* No need to decref the old type here, since we know it has no + reference count. */ + value->type = copy_type_recursive (value->type, copied_types); + type_incref (value->type); + } if (TYPE_OBJFILE (value->enclosing_type) == objfile) - value->enclosing_type = copy_type_recursive (objfile, - value->enclosing_type, - copied_types); + { + /* No need to decref the old type here, since we know it has no + reference count. */ + value->enclosing_type = copy_type_recursive (value->enclosing_type, + copied_types); + type_incref (value->enclosing_type); + } } /* Update the internal variables and value history when OBJFILE is @@ -1196,7 +1356,7 @@ value_as_address (struct value *val) Upon entry to this function, if VAL is a value of type `function' (that is, TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC), then - VALUE_ADDRESS (val) is the address of the function. This is what + value_address (val) is the address of the function. This is what you'll get if you evaluate an expression like `main'. The call to COERCE_ARRAY below actually does all the usual unary conversions, which includes converting values of type `function' @@ -1216,7 +1376,7 @@ value_as_address (struct value *val) function, just return its address directly. */ if (TYPE_CODE (value_type (val)) == TYPE_CODE_FUNC || TYPE_CODE (value_type (val)) == TYPE_CODE_METHOD) - return VALUE_ADDRESS (val); + return value_address (val); val = coerce_array (val); @@ -1447,7 +1607,7 @@ value_static_field (struct type *type, int fieldno) } if (retval && VALUE_LVAL (retval) == lval_memory) SET_FIELD_PHYSADDR (TYPE_FIELD (type, fieldno), - VALUE_ADDRESS (retval)); + value_address (retval)); } return retval; } @@ -1465,6 +1625,8 @@ value_change_enclosing_type (struct value *val, struct type *new_encl_type) val->contents = (gdb_byte *) xrealloc (val->contents, TYPE_LENGTH (new_encl_type)); + type_incref (new_encl_type); + type_decref (val->enclosing_type); val->enclosing_type = new_encl_type; return val; } @@ -1516,6 +1678,8 @@ value_primitive_field (struct value *arg1, int offset, memcpy (value_contents_all_raw (v), value_contents_all_raw (arg1), TYPE_LENGTH (value_enclosing_type (arg1))); } + type_incref (type); + type_decref (v->type); v->type = type; v->offset = value_offset (arg1); v->embedded_offset = (offset + value_embedded_offset (arg1) @@ -1592,7 +1756,7 @@ value_fn_field (struct value **arg1p, struct fn_field *f, int j, struct type *ty v = allocate_value (ftype); if (sym) { - VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); + set_value_address (v, BLOCK_START (SYMBOL_BLOCK_VALUE (sym))); } else { @@ -1601,9 +1765,9 @@ value_fn_field (struct value **arg1p, struct fn_field *f, int j, struct type *ty struct objfile *objfile = msymbol_objfile (msym); struct gdbarch *gdbarch = get_objfile_arch (objfile); - VALUE_ADDRESS (v) - = gdbarch_convert_from_func_ptr_addr - (gdbarch, SYMBOL_VALUE_ADDRESS (msym), ¤t_target); + set_value_address (v, + gdbarch_convert_from_func_ptr_addr + (gdbarch, SYMBOL_VALUE_ADDRESS (msym), ¤t_target)); } if (arg1p) @@ -1750,6 +1914,41 @@ pack_long (gdb_byte *buf, struct type *type, LONGEST num) } +/* Pack NUM into BUF using a target format of TYPE. */ + +void +pack_unsigned_long (gdb_byte *buf, struct type *type, ULONGEST num) +{ + int len; + + type = check_typedef (type); + len = TYPE_LENGTH (type); + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_INT: + case TYPE_CODE_CHAR: + case TYPE_CODE_ENUM: + case TYPE_CODE_FLAGS: + case TYPE_CODE_BOOL: + case TYPE_CODE_RANGE: + case TYPE_CODE_MEMBERPTR: + store_unsigned_integer (buf, len, num); + break; + + case TYPE_CODE_REF: + case TYPE_CODE_PTR: + store_typed_address (buf, type, (CORE_ADDR) num); + break; + + default: + error (_("\ +Unexpected type (%d) encountered for unsigned integer constant."), + TYPE_CODE (type)); + } +} + + /* Convert C numbers into newly allocated values. */ struct value * @@ -1763,6 +1962,19 @@ value_from_longest (struct type *type, LONGEST num) } +/* Convert C unsigned numbers into newly allocated values. */ + +struct value * +value_from_ulongest (struct type *type, ULONGEST num) +{ + struct value *val = allocate_value (type); + + pack_unsigned_long (value_contents_raw (val), type, num); + + return val; +} + + /* Create a value representing a pointer of type TYPE to the address ADDR. */ struct value * @@ -1816,8 +2028,9 @@ value_from_contents_and_address (struct type *type, set_value_lazy (v, 1); else memcpy (value_contents_raw (v), valaddr, TYPE_LENGTH (type)); - VALUE_ADDRESS (v) = address; - VALUE_LVAL (v) = lval_memory; + set_value_address (v, address); + if (address != 0) + VALUE_LVAL (v) = lval_memory; return v; } @@ -1944,4 +2157,15 @@ init-if-undefined VARIABLE = EXPRESSION\n\ Set an internal VARIABLE to the result of the EXPRESSION if it does not\n\ exist or does not contain a value. The EXPRESSION is not evaluated if the\n\ VARIABLE is already initialized.")); + + add_prefix_cmd ("function", no_class, function_command, _("\ +Placeholder command for showing help on convenience functions."), + &functionlist, "function ", 0, &cmdlist); + + internal_fn_type = alloc_type (OBJFILE_INTERNAL, NULL); + TYPE_CODE (internal_fn_type) = TYPE_CODE_INTERNAL_FUNCTION; + TYPE_LENGTH (internal_fn_type) = sizeof (struct internal_function *); + TYPE_NAME (internal_fn_type) = ""; + + make_final_cleanup (value_history_cleanup, NULL); } diff --git a/gdb/value.h b/gdb/value.h index aa43365..1ad3c75 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -272,12 +272,23 @@ extern void set_value_component_location (struct value *component, extern enum lval_type *deprecated_value_lval_hack (struct value *); #define VALUE_LVAL(val) (*deprecated_value_lval_hack (val)) -/* If lval == lval_memory, this is the address in the inferior. If - lval == lval_register, this is the byte offset into the registers - structure. */ +/* Backward compatibility for the Fedora merge branch. */ extern CORE_ADDR *deprecated_value_address_hack (struct value *); #define VALUE_ADDRESS(val) (*deprecated_value_address_hack (val)) +/* If lval == lval_memory, return the address in the inferior. If + lval == lval_register, return the byte offset into the registers + structure. Otherwise, return 0. The returned address + includes the offset, if any. */ +extern CORE_ADDR value_address (struct value *); + +/* Like value_address, except the result does not include value's + offset. */ +extern CORE_ADDR value_raw_address (struct value *); + +/* Set the address of a value. */ +extern void set_value_address (struct value *, CORE_ADDR); + /* Pointer to internal variable. */ extern struct internalvar **deprecated_value_internalvar_hack (struct value *); #define VALUE_INTERNALVAR(val) (*deprecated_value_internalvar_hack (val)) @@ -314,6 +325,9 @@ struct internalvar struct value *value; internalvar_make_value make_value; int endian; + /* True if this internalvar is the canonical name for a convenience + function. */ + int canonical; }; @@ -342,12 +356,17 @@ extern LONGEST unpack_field_as_long (struct type *type, extern void pack_long (gdb_byte *buf, struct type *type, LONGEST num); extern struct value *value_from_longest (struct type *type, LONGEST num); +extern struct value *value_from_ulongest (struct type *type, ULONGEST num); extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr); extern struct value *value_from_double (struct type *type, DOUBLEST num); extern struct value *value_from_decfloat (struct type *type, const gdb_byte *decbytes); extern struct value *value_from_string (char *string); +extern const char *object_address_data_not_valid (struct type *type); +extern int object_address_get_data (struct type *type, + CORE_ADDR *address_return); + extern struct value *value_at (struct type *type, CORE_ADDR addr); extern struct value *value_at_lazy (struct type *type, CORE_ADDR addr); @@ -388,6 +407,8 @@ extern struct value *value_mark (void); extern void value_free_to_mark (struct value *mark); +extern struct value *value_typed_string (char *ptr, int len, + struct type *char_type); extern struct value *value_string (char *ptr, int len); extern struct value *value_bitstring (char *ptr, int len); @@ -435,6 +456,7 @@ extern struct value *value_struct_elt (struct value **argp, extern struct value *value_aggregate_elt (struct type *curtype, char *name, + struct type *expect_type, int want_address, enum noside noside); @@ -533,14 +555,14 @@ extern void set_internalvar_component (struct internalvar *var, int bitpos, int bitsize, struct value *newvalue); -extern struct internalvar *lookup_only_internalvar (char *name); +extern struct internalvar *lookup_only_internalvar (const char *name); -extern struct internalvar *create_internalvar (char *name); +extern struct internalvar *create_internalvar (const char *name); extern struct internalvar * create_internalvar_type_lazy (char *name, internalvar_make_value fun); -extern struct internalvar *lookup_internalvar (char *name); +extern struct internalvar *lookup_internalvar (const char *name); extern int value_equal (struct value *arg1, struct value *arg2); @@ -619,7 +641,7 @@ extern int common_val_print (struct value *val, const struct value_print_options *options, const struct language_defn *language); -extern int val_print_string (CORE_ADDR addr, int len, int width, +extern int val_print_string (struct type *elttype, CORE_ADDR addr, int len, struct ui_file *stream, const struct value_print_options *options); @@ -658,5 +680,22 @@ extern struct value *value_allocate_space_in_inferior (int); extern struct value *value_of_local (const char *name, int complain); -extern struct value * value_subscripted_rvalue (struct value *array, struct value *idx, int lowerbound); +extern struct value *value_subscripted_rvalue (struct value *array, + CORE_ADDR offset); + +/* User function handler. */ + +typedef struct value *(*internal_function_fn) (void *cookie, + int argc, + struct value **argv); + +void add_internal_function (const char *name, const char *doc, + internal_function_fn handler, + void *cookie); + +struct value *call_internal_function (struct value *function, + int argc, struct value **argv); + +char *value_internal_function_name (struct value *); + #endif /* !defined (VALUE_H) */ diff --git a/gdb/varobj.c b/gdb/varobj.c index 2ec6d90..1237c96 100644 --- a/gdb/varobj.c +++ b/gdb/varobj.c @@ -29,11 +29,20 @@ #include "gdb_assert.h" #include "gdb_string.h" +#include "gdb_regex.h" #include "varobj.h" #include "vec.h" #include "gdbthread.h" #include "inferior.h" +#include "valprint.h" + +#if HAVE_PYTHON +#include "python/python.h" +#include "python/python-internal.h" +#else +typedef int PyObject; +#endif /* Non-zero if we want to see trace of varobj level stuff. */ @@ -138,6 +147,12 @@ struct varobj /* Children of this object. */ VEC (varobj_p) *children; + /* Whether the children of this varobj were requested. This field is + used to decide if dynamic varobj should recompute their children. + In the event that the frontend never asked for the children, we + can avoid that. */ + int children_requested; + /* Description of the root variable. Points to root variable for children. */ struct varobj_root *root; @@ -159,6 +174,16 @@ struct varobj not fetched if either the variable is frozen, or any parents is frozen. */ int not_fetched; + + /* Sub-range of children which the MI consumer has requested. If + FROM < 0 or TO < 0, means that all children have been + requested. */ + int from; + int to; + + /* The pretty-printer that has been constructed. If NULL, then a + new printer object is needed, and one will be constructed. */ + PyObject *pretty_printer; }; struct cpstack @@ -190,6 +215,10 @@ static void uninstall_variable (struct varobj *); static struct varobj *create_child (struct varobj *, int, char *); +static struct varobj * +create_child_with_value (struct varobj *parent, int index, const char *name, + struct value *value); + /* Utility routines */ static struct varobj *new_variable (void); @@ -200,6 +229,8 @@ static void free_variable (struct varobj *var); static struct cleanup *make_cleanup_free_variable (struct varobj *var); +static struct cleanup *make_cleanup_uninstall_variable (struct varobj *var); + static struct type *get_type (struct varobj *var); static struct type *get_value_type (struct varobj *var); @@ -215,6 +246,8 @@ static char *cppop (struct cpstack **pstack); static int install_new_value (struct varobj *var, struct value *value, int initial); +static void install_default_visualizer (struct varobj *var); + /* Language-specific routines. */ static enum varobj_languages variable_language (struct varobj *var); @@ -232,13 +265,17 @@ static struct value *value_of_child (struct varobj *parent, int index); static char *my_value_of_variable (struct varobj *var, enum varobj_display_formats format); -static char *value_get_print_value (struct value *value, - enum varobj_display_formats format); +char *value_get_print_value (struct value *value, + enum varobj_display_formats format, + PyObject *value_formatter); static int varobj_value_is_changeable_p (struct varobj *var); static int is_root_p (struct varobj *var); +static struct varobj * +varobj_add_child (struct varobj *var, const char *name, struct value *value); + /* C implementation */ static int c_number_of_children (struct varobj *var); @@ -570,8 +607,10 @@ varobj_create (char *objname, do_cleanups (old_chain); return NULL; } + make_cleanup_uninstall_variable (var); } + install_default_visualizer (var); discard_cleanups (old_chain); return var; } @@ -678,6 +717,33 @@ varobj_delete (struct varobj *var, char ***dellist, int only_children) return delcount; } +/* Convenience function for varobj_set_visualizer. Instantiate a + pretty-printer for a given value. */ +static PyObject * +instantiate_pretty_printer (PyObject *constructor, struct value *value) +{ +#if HAVE_PYTHON + PyObject *val_obj = NULL; + PyObject *printer; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + value = value_copy (value); + } + GDB_PY_HANDLE_EXCEPTION (except); + val_obj = value_to_value_object (value); + + if (! val_obj) + return NULL; + + printer = gdbpy_instantiate_printer (constructor, val_obj); + Py_DECREF (val_obj); + return printer; +#endif + return NULL; +} + /* Set/Get variable object display format */ enum varobj_display_formats @@ -702,7 +768,8 @@ varobj_set_display_format (struct varobj *var, && var->value && !value_lazy (var->value)) { xfree (var->print_value); - var->print_value = value_get_print_value (var->value, var->format); + var->print_value = value_get_print_value (var->value, var->format, + var->pretty_printer); } return var->format; @@ -714,6 +781,21 @@ varobj_get_display_format (struct varobj *var) return var->format; } +char * +varobj_get_display_hint (struct varobj *var) +{ + char *result = NULL; + +#if HAVE_PYTHON + PyGILState_STATE state = PyGILState_Ensure (); + if (var->pretty_printer) + result = gdbpy_get_display_hint (var->pretty_printer); + PyGILState_Release (state); +#endif + + return result; +} + /* If the variable object is bound to a specific thread, that is its evaluation can always be done in context of a frame inside that thread, returns GDB id of the thread -- which @@ -746,12 +828,141 @@ varobj_get_frozen (struct varobj *var) return var->frozen; } +static int +update_dynamic_varobj_children (struct varobj *var, + VEC (varobj_p) **changed, + VEC (varobj_p) **new_and_unchanged, + int *cchanged) + +{ +#if HAVE_PYTHON + /* FIXME: we *might* want to provide this functionality as + a standalone function, so that other interested parties + than varobj code can benefit for this. */ + struct cleanup *back_to; + PyObject *children; + PyObject *iterator; + int i; + int children_changed = 0; + PyObject *printer = var->pretty_printer; + PyGILState_STATE state; + + state = PyGILState_Ensure (); + back_to = make_cleanup_py_restore_gil (&state); + + *cchanged = 0; + if (!PyObject_HasAttr (printer, gdbpy_children_cst)) + { + do_cleanups (back_to); + return 0; + } + + children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst, + NULL); + + if (!children) + { + gdbpy_print_stack (); + error ("Null value returned for children"); + } + + make_cleanup_py_decref (children); + + if (!PyIter_Check (children)) + error ("Returned value is not iterable"); + + iterator = PyObject_GetIter (children); + if (!iterator) + { + gdbpy_print_stack (); + error ("Could not get children iterator"); + } + make_cleanup_py_decref (iterator); + + for (i = 0; ; ++i) + { + PyObject *item = PyIter_Next (iterator); + PyObject *py_v; + struct value *v; + char *name; + struct cleanup *inner; + + if (!item) + break; + inner = make_cleanup_py_decref (item); + + if (!PyArg_ParseTuple (item, "sO", &name, &py_v)) + error ("Invalid item from the child list"); + + if (PyObject_TypeCheck (py_v, &value_object_type)) + { + /* If we just call convert_value_from_python for this type, + we won't know who owns the result. For this one case we + need to copy the resulting value. */ + v = value_object_to_value (py_v); + v = value_copy (v); + } + else + v = convert_value_from_python (py_v); + + /* TODO: This assume the name of the i-th child never changes. */ + + /* Now see what to do here. */ + if (VEC_length (varobj_p, var->children) < i + 1) + { + /* There's no child yet. */ + struct varobj *child = varobj_add_child (var, name, v); + if (new_and_unchanged) + VEC_safe_push (varobj_p, *new_and_unchanged, child); + children_changed = 1; + } + else + { + varobj_p existing = VEC_index (varobj_p, var->children, i); + if (install_new_value (existing, v, 0) && changed) + { + if (changed) + VEC_safe_push (varobj_p, *changed, existing); + } + else + { + if (new_and_unchanged) + VEC_safe_push (varobj_p, *new_and_unchanged, existing); + } + } + + do_cleanups (inner); + } + + if (i < VEC_length (varobj_p, var->children)) + { + int i; + children_changed = 1; + for (i = 0; i < VEC_length (varobj_p, var->children); ++i) + varobj_delete (VEC_index (varobj_p, var->children, i), NULL, 0); + } + VEC_truncate (varobj_p, var->children, i); + var->num_children = VEC_length (varobj_p, var->children); + + do_cleanups (back_to); + + *cchanged = children_changed; + return 1; +#else + gdb_assert (0 && "should never be called if Python is not enabled"); +#endif +} int varobj_get_num_children (struct varobj *var) { if (var->num_children == -1) - var->num_children = number_of_children (var); + { + int changed; + if (!var->pretty_printer + || !update_dynamic_varobj_children (var, NULL, NULL, &changed)) + var->num_children = number_of_children (var); + } return var->num_children; } @@ -764,7 +975,16 @@ varobj_list_children (struct varobj *var) { struct varobj *child; char *name; - int i; + int i, children_changed; + + var->children_requested = 1; + + if (var->pretty_printer + /* This, in theory, can result in the number of children changing without + frontend noticing. But well, calling -var-list-children on the same + varobj twice is not something a sane frontend would do. */ + && update_dynamic_varobj_children (var, NULL, NULL, &children_changed)) + return var->children; if (var->num_children == -1) var->num_children = number_of_children (var); @@ -790,12 +1010,24 @@ varobj_list_children (struct varobj *var) name = name_of_child (var, i); existing = create_child (var, i, name); VEC_replace (varobj_p, var->children, i, existing); + install_default_visualizer (existing); } } return var->children; } +static struct varobj * +varobj_add_child (struct varobj *var, const char *name, struct value *value) +{ + varobj_p v = create_child_with_value (var, + VEC_length (varobj_p, var->children), + name, value); + VEC_safe_push (varobj_p, var->children, v); + install_default_visualizer (v); + return v; +} + /* Obtain the type of an object Variable as a string similar to the one gdb prints on the console */ @@ -1002,6 +1234,13 @@ install_new_value (struct varobj *var, struct value *value, int initial) a type. */ gdb_assert (var->type || CPLUS_FAKE_CHILD (var)); changeable = varobj_value_is_changeable_p (var); + + /* If the type has custom visualizer, we consider it to be always + changeable. FIXME: need to make sure this behaviour will not + mess up read-sensitive values. */ + if (var->pretty_printer) + changeable = 1; + need_to_fetch = changeable; /* We are not interested in the address of references, and given @@ -1053,12 +1292,14 @@ install_new_value (struct varobj *var, struct value *value, int initial) } } + /* Below, we'll be comparing string rendering of old and new values. Don't get string rendering if the value is lazy -- if it is, the code above has decided that the value should not be fetched. */ if (value && !value_lazy (value)) - print_value = value_get_print_value (value, var->format); + print_value = value_get_print_value (value, var->format, + var->pretty_printer); /* If the type is changeable, compare the old and the new values. If this is the initial assignment, we don't have any old value @@ -1123,6 +1364,150 @@ install_new_value (struct varobj *var, struct value *value, int initial) return changed; } +/* Return the effective requested range for a varobj. VAR is the + varobj. CHILDREN is the computed list of children. FROM and TO + are out parameters. If VAR has no bounds selected, *FROM and *TO + will be set to the full range of CHILDREN. Otherwise, *FROM and + *TO will be set to the selected sub-range of VAR, clipped to be in + range of CHILDREN. */ +void +varobj_get_child_range (struct varobj *var, VEC (varobj_p) *children, + int *from, int *to) +{ + if (var->from < 0 || var->to < 0) + { + *from = 0; + *to = VEC_length (varobj_p, children); + } + else + { + *from = var->from; + if (*from > VEC_length (varobj_p, children)) + *from = VEC_length (varobj_p, children); + *to = var->to; + if (*to > VEC_length (varobj_p, children)) + *to = VEC_length (varobj_p, children); + } +} + +/* Set the selected sub-range of children of VAR to start at index + FROM and end at index TO. If either FROM or TO is less than zero, + this is interpreted as a request for all children. */ +void +varobj_set_child_range (struct varobj *var, int from, int to) +{ + var->from = from; + var->to = to; +} + +static void +install_visualizer (struct varobj *var, PyObject *visualizer) +{ +#if HAVE_PYTHON + /* If there are any children now, wipe them. */ + varobj_delete (var, NULL, 1 /* children only */); + var->num_children = -1; + + Py_XDECREF (var->pretty_printer); + var->pretty_printer = visualizer; + + install_new_value (var, var->value, 1); + + /* If we removed the visualizer, and the user ever requested the + object's children, then we must compute the list of children. + Note that we needn't do this when installing a visualizer, + because updating will recompute dynamic children. */ + if (!visualizer && var->children_requested) + varobj_list_children (var); +#else + error ("Python support required"); +#endif +} + +static void +install_default_visualizer (struct varobj *var) +{ +#if HAVE_PYTHON + struct cleanup *cleanup; + PyGILState_STATE state; + PyObject *pretty_printer = NULL; + + state = PyGILState_Ensure (); + cleanup = make_cleanup_py_restore_gil (&state); + + if (var->value) + { + pretty_printer = gdbpy_get_varobj_pretty_printer (var->value); + if (! pretty_printer) + { + gdbpy_print_stack (); + error (_("Cannot instantiate printer for default visualizer")); + } + } + + if (pretty_printer == Py_None) + { + Py_DECREF (pretty_printer); + pretty_printer = NULL; + } + + install_visualizer (var, pretty_printer); + do_cleanups (cleanup); +#else + /* No error is right as this function is inserted just as a hook. */ +#endif +} + +void +varobj_set_visualizer (struct varobj *var, const char *visualizer) +{ +#if HAVE_PYTHON + PyObject *mainmod, *globals, *pretty_printer, *constructor; + struct cleanup *back_to, *value; + PyGILState_STATE state; + + + state = PyGILState_Ensure (); + back_to = make_cleanup_py_restore_gil (&state); + + mainmod = PyImport_AddModule ("__main__"); + globals = PyModule_GetDict (mainmod); + Py_INCREF (globals); + make_cleanup_py_decref (globals); + + constructor = PyRun_String (visualizer, Py_eval_input, globals, globals); + + /* Do not instantiate NoneType. */ + if (constructor == Py_None) + { + pretty_printer = Py_None; + Py_INCREF (pretty_printer); + } + else + pretty_printer = instantiate_pretty_printer (constructor, var->value); + + Py_XDECREF (constructor); + + if (! pretty_printer) + { + gdbpy_print_stack (); + error ("Could not evaluate visualizer expression: %s", visualizer); + } + + if (pretty_printer == Py_None) + { + Py_DECREF (pretty_printer); + pretty_printer = NULL; + } + + install_visualizer (var, pretty_printer); + + do_cleanups (back_to); +#else + error ("Python support required"); +#endif +} + /* Update the values for a variable and its children. This is a two-pronged attack. First, re-parse the value for the root's expression to see if it's changed. Then go all the way @@ -1148,7 +1533,7 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit) struct varobj **cv; struct varobj **templist = NULL; struct value *new; - VEC (varobj_p) *stack = NULL; + VEC (varobj_update_result) *stack = NULL; VEC (varobj_update_result) *result = NULL; struct frame_info *fi; @@ -1187,20 +1572,85 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit) if (new == NULL) r.status = VAROBJ_NOT_IN_SCOPE; - - if (r.type_changed || r.changed) - VEC_safe_push (varobj_update_result, result, &r); + r.value_installed = 1; if (r.status == VAROBJ_NOT_IN_SCOPE) - return result; + { + VEC_safe_push (varobj_update_result, result, &r); + return result; + } + + VEC_safe_push (varobj_update_result, stack, &r); + } + else + { + varobj_update_result r = {*varp}; + VEC_safe_push (varobj_update_result, stack, &r); } - - VEC_safe_push (varobj_p, stack, *varp); /* Walk through the children, reconstructing them all. */ - while (!VEC_empty (varobj_p, stack)) + while (!VEC_empty (varobj_update_result, stack)) { - v = VEC_pop (varobj_p, stack); + varobj_update_result r = *(VEC_last (varobj_update_result, stack)); + struct varobj *v = r.varobj; + + VEC_pop (varobj_update_result, stack); + + /* Update this variable, unless it's a root, which is already + updated. */ + if (!r.value_installed) + { + new = value_of_child (v->parent, v->index); + if (install_new_value (v, new, 0 /* type not changed */)) + { + r.changed = 1; + v->updated = 0; + } + } + + /* We probably should not get children of a varobj that has a + pretty-printer, but for which -var-list-children was never + invoked. Presumably, such varobj is not yet expanded in the + UI, so we need not bother getting it. */ + if (v->pretty_printer) + { + VEC (varobj_p) *changed = 0, *new_and_unchanged = 0; + int i, children_changed; + varobj_p tmp; + + if (!v->children_requested) + continue; + + if (v->frozen) + continue; + + /* If update_dynamic_varobj_children returns 0, then we have + a non-conforming pretty-printer, so we skip it. */ + if (update_dynamic_varobj_children (v, &changed, &new_and_unchanged, + &children_changed)) + { + if (children_changed) + r.children_changed = 1; + for (i = 0; VEC_iterate (varobj_p, changed, i, tmp); ++i) + { + varobj_update_result r = {tmp}; + r.changed = 1; + r.value_installed = 1; + VEC_safe_push (varobj_update_result, stack, &r); + } + for (i = 0; + VEC_iterate (varobj_p, new_and_unchanged, i, tmp); + ++i) + { + varobj_update_result r = {tmp}; + r.value_installed = 1; + VEC_safe_push (varobj_update_result, stack, &r); + } + if (r.changed || r.children_changed) + VEC_safe_push (varobj_update_result, result, &r); + continue; + } + } /* Push any children. Use reverse order so that the first child is popped from the work stack first, and so @@ -1211,26 +1661,18 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit) varobj_p c = VEC_index (varobj_p, v->children, i); /* Child may be NULL if explicitly deleted by -var-delete. */ if (c != NULL && !c->frozen) - VEC_safe_push (varobj_p, stack, c); - } - - /* Update this variable, unless it's a root, which is already - updated. */ - if (v->root->rootvar != v) - { - new = value_of_child (v->parent, v->index); - if (install_new_value (v, new, 0 /* type not changed */)) { - /* Note that it's changed */ - varobj_update_result r = {v}; - r.changed = 1; - VEC_safe_push (varobj_update_result, result, &r); - v->updated = 0; + varobj_update_result r = {c}; + VEC_safe_push (varobj_update_result, stack, &r); } } + + if (r.changed || r.type_changed) + VEC_safe_push (varobj_update_result, result, &r); } - VEC_free (varobj_p, stack); + VEC_free (varobj_update_result, stack); + return result; } @@ -1429,16 +1871,23 @@ uninstall_variable (struct varobj *var) static struct varobj * create_child (struct varobj *parent, int index, char *name) { + return create_child_with_value (parent, index, name, + value_of_child (parent, index)); +} + +static struct varobj * +create_child_with_value (struct varobj *parent, int index, const char *name, + struct value *value) +{ struct varobj *child; char *childs_name; - struct value *value; child = new_variable (); /* name is allocated by name_of_child */ - child->name = name; + /* FIXME: xstrdup should not be here. */ + child->name = xstrdup (name); child->index = index; - value = value_of_child (parent, index); child->parent = parent; child->root = parent->root; childs_name = xstrprintf ("%s.%s", parent->obj_name, name); @@ -1487,6 +1936,10 @@ new_variable (void) var->print_value = NULL; var->frozen = 0; var->not_fetched = 0; + var->children_requested = 0; + var->from = -1; + var->to = -1; + var->pretty_printer = 0; return var; } @@ -1519,6 +1972,14 @@ free_variable (struct varobj *var) xfree (var->root); } +#if HAVE_PYTHON + { + PyGILState_STATE state = PyGILState_Ensure (); + Py_XDECREF (var->pretty_printer); + PyGILState_Release (state); + } +#endif + xfree (var->name); xfree (var->obj_name); xfree (var->print_value); @@ -1538,6 +1999,18 @@ make_cleanup_free_variable (struct varobj *var) return make_cleanup (do_free_variable_cleanup, var); } +static void +do_uninstall_variable_cleanup (void *var) +{ + uninstall_variable (var); +} + +static struct cleanup * +make_cleanup_uninstall_variable (struct varobj *var) +{ + return make_cleanup (do_uninstall_variable_cleanup, var); +} + /* This returns the type of the variable. It also skips past typedefs to return the real type of the variable. @@ -1792,24 +2265,71 @@ my_value_of_variable (struct varobj *var, enum varobj_display_formats format) return NULL; } -static char * -value_get_print_value (struct value *value, enum varobj_display_formats format) +char * +value_get_print_value (struct value *value, enum varobj_display_formats format, + PyObject *value_formatter) { long dummy; struct ui_file *stb; struct cleanup *old_chain; - char *thevalue; + char *thevalue = NULL; struct value_print_options opts; if (value == NULL) return NULL; +#if HAVE_PYTHON + { + PyGILState_STATE state = PyGILState_Ensure (); + if (value_formatter && PyObject_HasAttr (value_formatter, + gdbpy_to_string_cst)) + { + char *hint; + struct value *replacement; + int string_print = 0; + + hint = gdbpy_get_display_hint (value_formatter); + if (hint) + { + if (!strcmp (hint, "string")) + string_print = 1; + xfree (hint); + } + + thevalue = apply_varobj_pretty_printer (value_formatter, + &replacement); + if (thevalue && !string_print) + { + PyGILState_Release (state); + return thevalue; + } + if (replacement) + value = replacement; + } + PyGILState_Release (state); + } +#endif + stb = mem_fileopen (); old_chain = make_cleanup_ui_file_delete (stb); get_formatted_print_options (&opts, format_code[(int) format]); opts.deref_ref = 0; - common_val_print (value, stb, 0, &opts, current_language); + opts.raw = 1; + if (thevalue) + { + struct type *string_char_type; + + make_cleanup (xfree, thevalue); + + /* OUTPUT is already in the hosts's charset. */ + string_char_type = language_string_char_type (current_language, + current_gdbarch); + LA_PRINT_STRING (stb, string_char_type, (gdb_byte *) thevalue, + strlen (thevalue), 0, &opts); + } + else + common_val_print (value, stb, 0, &opts, current_language); thevalue = ui_file_xstrdup (stb, &dummy); do_cleanups (old_chain); @@ -1900,7 +2420,7 @@ varobj_floating_p (struct varobj *var) value is not known. If WAS_PTR is not NULL, set *WAS_PTR to 0 or 1 - depending on whether pointer was deferenced + depending on whether pointer was dereferenced in this function. */ static void adjust_value_for_child_access (struct value **value, @@ -2269,6 +2789,11 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format) catch that case explicitly. */ struct type *type = get_type (var); + /* If we have a custom formatter, return whatever string it has + produced. */ + if (var->pretty_printer && var->print_value) + return xstrdup (var->print_value); + /* Strip top-level references. */ while (TYPE_CODE (type) == TYPE_CODE_REF) type = check_typedef (TYPE_TARGET_TYPE (type)); @@ -2313,7 +2838,8 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format) if (format == var->format) return xstrdup (var->print_value); else - return value_get_print_value (var->value, format); + return value_get_print_value (var->value, format, + var->pretty_printer); } } } diff --git a/gdb/varobj.h b/gdb/varobj.h index f2cdcf8..10758d6 100644 --- a/gdb/varobj.h +++ b/gdb/varobj.h @@ -72,7 +72,12 @@ typedef struct varobj_update_result_t struct varobj *varobj; int type_changed; int changed; + int children_changed; enum varobj_scope_status status; + /* This variable is used internally by varobj_update to indicate if the + new value of varobj is already computed and installed, or has to + be yet installed. Don't use this outside varobj.c */ + int value_installed; } varobj_update_result; DEF_VEC_O (varobj_update_result); @@ -107,6 +112,14 @@ extern void varobj_set_frozen (struct varobj *var, int frozen); extern int varobj_get_frozen (struct varobj *var); +extern void varobj_get_child_range (struct varobj *var, + VEC (varobj_p) *children, + int *from, int *to); + +extern void varobj_set_child_range (struct varobj *var, int from, int to); + +extern char *varobj_get_display_hint (struct varobj *var); + extern int varobj_get_num_children (struct varobj *var); /* Return the list of children of VAR. The returned vector @@ -141,4 +154,13 @@ extern int varobj_editable_p (struct varobj *var); extern int varobj_floating_p (struct varobj *var); +extern void +varobj_set_visualizer (struct varobj *var, const char *visualizer); + +extern void +varobj_clear_type_visualizers (); + +extern void +varobj_set_visualizer (struct varobj *var, const char *visualizer); + #endif /* VAROBJ_H */ diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c index aab3e48..d41738b 100644 --- a/gdb/xcoffread.c +++ b/gdb/xcoffread.c @@ -3021,6 +3021,7 @@ static struct sym_fns xcoff_sym_fns = xcoff_new_init, /* sym_new_init: init anything gbl to entire symtab */ xcoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ xcoff_initial_scan, /* sym_read: read a symbol file into symtab */ + NULL, /* sym_read_psymbols */ xcoff_symfile_finish, /* sym_finish: finished with file, cleanup */ xcoff_symfile_offsets, /* sym_offsets: xlate offsets ext->int form */ default_symfile_segments, /* sym_segments: Get segment information from diff --git a/gdb/xml-syscall.c b/gdb/xml-syscall.c new file mode 100644 index 0000000..498f58a --- /dev/null +++ b/gdb/xml-syscall.c @@ -0,0 +1,423 @@ +/* Functions that provide the mechanism to parse a syscall XML file + and get its values. + + Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, + 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "gdbtypes.h" +#include "xml-support.h" +#include "xml-syscall.h" + +#include "filenames.h" + +#include "gdb_assert.h" + +#ifndef HAVE_LIBEXPAT + +/* Dummy functions to indicate that there's no support for fetching + syscalls information. */ + +static void +syscall_warn_user (void) +{ + static int have_warned = 0; + if (!have_warned) + { + have_warned = 1; + warning (_("Can not parse XML syscalls information; XML support was " + "disabled at compile time")); + } +} + +const struct syscalls_info * +xml_init_syscalls_info (const char *filename) +{ + syscall_warn_user (); + return NULL; +} + +int +xml_get_syscall_number (const struct syscalls_info *sysinfo, + const char *syscall_name) +{ + syscall_warn_user (); + return UNKNOWN_SYSCALL; +} + +const char * +xml_get_syscall_name (const struct syscalls_info *sysinfo, + int syscall_number) +{ + syscall_warn_user (); + return NULL; +} + +int +xml_number_of_syscalls (const struct syscalls_info *sysinfo) +{ + syscall_warn_user (); + return 0; +} + +const char ** +xml_list_of_syscalls (const struct syscalls_info *sysinfo) +{ + syscall_warn_user (); + return NULL; +} + +#else + +/* Structure which describes a syscall. */ + +typedef struct syscall_desc +{ + /* The syscall number. */ + + int number; + + /* The syscall name. */ + + char *name; +} *syscall_desc_p; +DEF_VEC_P(syscall_desc_p); + +/* Structure that represents syscalls information. */ + +struct syscalls_info +{ + /* The syscalls. */ + + VEC(syscall_desc_p) *syscalls; +}; + +/* Callback data for syscall information parsing. */ + +struct syscall_parsing_data +{ + /* The syscalls_info we are building. */ + + struct syscalls_info *sysinfo; +}; + + +static struct syscalls_info * +allocate_syscalls_info (void) +{ + return XZALLOC (struct syscalls_info); +} + +static void +sysinfo_free_syscalls_desc (struct syscall_desc *sd) +{ + xfree (sd->name); +} + +static void +free_syscalls_info (void *arg) +{ + struct syscalls_info *sysinfo = arg; + struct syscall_desc *sysdesc; + int i; + + for (i = 0; + VEC_iterate (syscall_desc_p, sysinfo->syscalls, i, sysdesc); + i++) + sysinfo_free_syscalls_desc (sysdesc); + VEC_free (syscall_desc_p, sysinfo->syscalls); + + xfree (sysinfo); +} + +struct cleanup * +make_cleanup_free_syscalls_info (struct syscalls_info *sysinfo) +{ + return make_cleanup (free_syscalls_info, sysinfo); +} + +/* Open FILENAME, read all its text into memory, close it, and return + the text. If something goes wrong, return NULL and warn. */ + +static char * +fetch_xml_from_file (const char *filename, void *baton) +{ + const char *dirname = baton; + FILE *file; + struct cleanup *back_to; + char *text; + size_t len, offset; + + if (dirname && *dirname) + { + char *fullname = concat (dirname, "/", filename, (char *) NULL); + if (fullname == NULL) + nomem (0); + file = fopen (fullname, FOPEN_RT); + xfree (fullname); + } + else + file = fopen (filename, FOPEN_RT); + + if (file == NULL) + return NULL; + + back_to = make_cleanup_fclose (file); + + /* Read in the whole file, one chunk at a time. */ + len = 4096; + offset = 0; + text = xmalloc (len); + make_cleanup (free_current_contents, &text); + while (1) + { + size_t bytes_read; + + /* Continue reading where the last read left off. Leave at least + one byte so that we can NUL-terminate the result. */ + bytes_read = fread (text + offset, 1, len - offset - 1, file); + if (ferror (file)) + { + warning (_("Read error from \"%s\""), filename); + do_cleanups (back_to); + return NULL; + } + + offset += bytes_read; + + if (feof (file)) + break; + + len = len * 2; + text = xrealloc (text, len); + } + + fclose (file); + discard_cleanups (back_to); + + text[offset] = '\0'; + return text; +} + +static void +syscall_create_syscall_desc (struct syscalls_info *sysinfo, + const char *name, int number) +{ + struct syscall_desc *sysdesc = XZALLOC (struct syscall_desc); + + sysdesc->name = xstrdup (name); + sysdesc->number = number; + + VEC_safe_push (syscall_desc_p, sysinfo->syscalls, sysdesc); +} + +/* Handle the start of a element. */ + +static void +syscall_start_syscalls_info (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, + VEC(gdb_xml_value_s) *attributes) +{ + struct syscall_parsing_data *data = user_data; + struct syscalls_info *sysinfo = data->sysinfo; +} + +/* Handle the start of a element. */ + +static void +syscall_start_syscall (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, VEC(gdb_xml_value_s) *attributes) +{ + struct syscall_parsing_data *data = user_data; + struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); + int len, i; + /* syscall info. */ + char *name = NULL; + int number = 0; + + len = VEC_length (gdb_xml_value_s, attributes); + + for (i = 0; i < len; i++) + { + if (strcmp (attrs[i].name, "name") == 0) + name = attrs[i].value; + else if (strcmp (attrs[i].name, "number") == 0) + number = * (ULONGEST *) attrs[i].value; + else + internal_error (__FILE__, __LINE__, + _("Unknown attribute name '%s'."), attrs[i].name); + } + + syscall_create_syscall_desc (data->sysinfo, name, number); +} + + +/* The elements and attributes of an XML syscall document. */ + +static const struct gdb_xml_attribute syscall_attr[] = { + { "number", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "name", GDB_XML_AF_NONE, NULL, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element syscalls_info_children[] = { + { "syscall", syscall_attr, NULL, + GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + syscall_start_syscall, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element syselements[] = { + { "syscalls_info", NULL, syscalls_info_children, + GDB_XML_EF_NONE, syscall_start_syscalls_info, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +static struct syscalls_info * +syscall_parse_xml (const char *document, xml_fetch_another fetcher, + void *fetcher_baton) +{ + struct cleanup *result_cleanup; + struct gdb_xml_parser *parser; + struct syscall_parsing_data data; + char *expanded_text; + int i; + + parser = gdb_xml_create_parser_and_cleanup (_("syscalls info"), + syselements, &data); + + memset (&data, 0, sizeof (struct syscall_parsing_data)); + data.sysinfo = allocate_syscalls_info (); + result_cleanup = make_cleanup_free_syscalls_info (data.sysinfo); + + if (gdb_xml_parse (parser, document) == 0) + { + /* Parsed successfully. */ + discard_cleanups (result_cleanup); + return data.sysinfo; + } + else + { + warning (_("Could not load XML syscalls info; ignoring")); + do_cleanups (result_cleanup); + return NULL; + } +} + +const struct syscalls_info * +xml_init_syscalls_info (const char *filename) +{ + char *full_file; + char *dirname; + struct syscalls_info *sysinfo; + struct cleanup *back_to; + + full_file = fetch_xml_from_file (filename, gdb_datadir); + if (full_file == NULL) + { + warning (_("Could not open \"%s\""), filename); + return NULL; + } + + back_to = make_cleanup (xfree, full_file); + + dirname = ldirname (filename); + if (dirname != NULL) + make_cleanup (xfree, dirname); + + sysinfo = syscall_parse_xml (full_file, fetch_xml_from_file, dirname); + do_cleanups (back_to); + + return sysinfo; +} + +int +xml_get_syscall_number (const struct syscalls_info *sysinfo, + const char *syscall_name) +{ + struct syscall_desc *sysdesc; + int i; + + if (sysinfo == NULL + || syscall_name == NULL) + return UNKNOWN_SYSCALL; + + for (i = 0; + VEC_iterate(syscall_desc_p, sysinfo->syscalls, i, sysdesc); + i++) + if (strcmp (sysdesc->name, syscall_name) == 0) + return sysdesc->number; + + return UNKNOWN_SYSCALL; +} + +const char * +xml_get_syscall_name (const struct syscalls_info *sysinfo, + int syscall_number) +{ + struct syscall_desc *sysdesc; + int i; + + if (sysinfo == NULL + || syscall_number < 0) + return NULL; + + for (i = 0; + VEC_iterate(syscall_desc_p, sysinfo->syscalls, i, sysdesc); + i++) + if (sysdesc->number == syscall_number) + return sysdesc->name; + + return NULL; +} + +int +xml_number_of_syscalls (const struct syscalls_info *sysinfo) +{ + return (sysinfo == NULL ? 0 : VEC_length(syscall_desc_p, + sysinfo->syscalls)); +} + +const char ** +xml_list_of_syscalls (const struct syscalls_info *sysinfo) +{ + struct syscall_desc *sysdesc; + const char **names = NULL; + int nsyscalls; + int i; + + if (sysinfo == NULL) + return NULL; + + nsyscalls = VEC_length (syscall_desc_p, sysinfo->syscalls); + names = xmalloc ((nsyscalls + 1) * sizeof (char *)); + + for (i = 0; + VEC_iterate (syscall_desc_p, sysinfo->syscalls, i, sysdesc); + i++) + names[i] = sysdesc->name; + + names[i] = NULL; + + return names; +} + +#endif /* HAVE_LIBEXPAT */ diff --git a/gdb/xml-syscall.h b/gdb/xml-syscall.h new file mode 100644 index 0000000..ff11f20 --- /dev/null +++ b/gdb/xml-syscall.h @@ -0,0 +1,64 @@ +/* Functions that provide the mechanism to parse a syscall XML file + and get its values. + + Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, + 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef XML_SYSCALL_H +#define XML_SYSCALL_H 1 + +/* Structure that stores information about the system's + syscalls. */ + +struct syscalls_info; + + +/* Function responsible for initializing the information + about the syscalls. It reads the XML file and fills the + struct syscalls_info with the values. + + Returns the struct syscalls_info if the file is valid, NULL otherwise. */ + +const struct syscalls_info *xml_init_syscalls_info (const char *); + +/* Function that retrieves the syscall number corresponding to the given + name. + + Returns the syscall number if found, or otherwise. */ + +int xml_get_syscall_number (const struct syscalls_info *, const char *); + +/* Function that retrieves the syscall name corresponding to the given + number. + + Returns the syscall name if found, NULL otherwise. */ +const char *xml_get_syscall_name (const struct syscalls_info *, int); + +/* Function that returns the number of syscalls defined in the system. + + Returns the number of syscalls, or zero otherwise. */ +int xml_number_of_syscalls (const struct syscalls_info *); + +/* Function used to retrieve the list of syscalls in the system. This list + is returned as an array of strings. + + Returns the list of syscalls in the system, or NULL otherwise. */ +const char **xml_list_of_syscalls (const struct syscalls_info *sysinfo); + +#endif /* XML_SYSCALL_H */ diff --git a/opcodes/ppc-opc.c b/opcodes/ppc-opc.c index c872db5..5e70395 100644 --- a/opcodes/ppc-opc.c +++ b/opcodes/ppc-opc.c @@ -4560,8 +4560,8 @@ const struct powerpc_opcode powerpc_opcodes[] = { {"lhbrx", X(31,790), X_MASK, COM, PPCNONE, {RT, RA0, RB}}, -{"lfqx", X(31,791), X_MASK, POWER2, PPCNONE, {FRT, RA, RB}}, {"lfdpx", X(31,791), X_MASK, POWER6, POWER7, {FRT, RA, RB}}, +{"lfqx", X(31,791), X_MASK, POWER2, PPCNONE, {FRT, RA, RB}}, {"sraw", XRC(31,792,0), X_MASK, PPCCOM, PPCNONE, {RA, RS, RB}}, {"sra", XRC(31,792,0), X_MASK, PWRCOM, PPCNONE, {RA, RS, RB}}, @@ -4638,8 +4638,8 @@ const struct powerpc_opcode powerpc_opcodes[] = { {"sthbrx", X(31,918), X_MASK, COM, PPCNONE, {RS, RA0, RB}}, -{"stfqx", X(31,919), X_MASK, POWER2, PPCNONE, {FRS, RA, RB}}, {"stfdpx", X(31,919), X_MASK, POWER6, PPCNONE, {FRS, RA, RB}}, +{"stfqx", X(31,919), X_MASK, POWER2, PPCNONE, {FRS, RA, RB}}, {"sraq", XRC(31,920,0), X_MASK, M601, PPCNONE, {RA, RS, RB}}, {"sraq.", XRC(31,920,1), X_MASK, M601, PPCNONE, {RA, RS, RB}}, @@ -4801,12 +4801,12 @@ const struct powerpc_opcode powerpc_opcodes[] = { {"psq_l", OP(56), OP_MASK, PPCPS, PPCNONE, {FRT,PSD,RA,PSW,PSQ}}, +{"lfdp", OP(57), OP_MASK, POWER6, POWER7, {FRT, D, RA0}}, + {"lfqu", OP(57), OP_MASK, POWER2, PPCNONE, {FRT, D, RA0}}, {"psq_lu", OP(57), OP_MASK, PPCPS, PPCNONE, {FRT,PSD,RA,PSW,PSQ}}, -{"lfdp", OP(57), OP_MASK, POWER6, POWER7, {FRT, D, RA0}}, - {"ld", DSO(58,0), DS_MASK, PPC64, PPCNONE, {RT, DS, RA0}}, {"ldu", DSO(58,1), DS_MASK, PPC64, PPCNONE, {RT, DS, RAL}}, {"lwa", DSO(58,2), DS_MASK, PPC64, PPCNONE, {RT, DS, RA0}}, @@ -4921,10 +4921,6 @@ const struct powerpc_opcode powerpc_opcodes[] = { {"fcfidus", XRC(59,974,0), XRA_MASK, POWER7, PPCNONE, {FRT, FRB}}, {"fcfidus.", XRC(59,974,1), XRA_MASK, POWER7, PPCNONE, {FRT, FRB}}, -{"stfq", OP(60), OP_MASK, POWER2, PPCNONE, {FRS, D, RA}}, - -{"psq_st", OP(60), OP_MASK, PPCPS, PPCNONE, {FRS,PSD,RA,PSW,PSQ}}, - {"xxsldwi", XX3(60,2), XX3SHW_MASK, PPCVSX, PPCNONE, {XT6, XA6, XB6, SHW}}, {"xxsel", XX4(60,3), XX4_MASK, PPCVSX, PPCNONE, {XT6, XA6, XB6, XC6}}, {"xxspltd", XX3(60,10), XX3DM_MASK, PPCVSX, PPCNONE, {XT6, XA6, XB6S, DMEX}}, @@ -5067,12 +5063,16 @@ const struct powerpc_opcode powerpc_opcodes[] = { {"xvcvsxddp", XX2(60,504), XX2_MASK, PPCVSX, PPCNONE, {XT6, XB6}}, {"xvnegdp", XX2(60,505), XX2_MASK, PPCVSX, PPCNONE, {XT6, XB6}}, -{"psq_stu", OP(61), OP_MASK, PPCPS, PPCNONE, {FRS,PSD,RA,PSW,PSQ}}, +{"stfq", OP(60), OP_MASK, POWER2, PPCNONE, {FRS, D, RA}}, -{"stfqu", OP(61), OP_MASK, POWER2, PPCNONE, {FRS, D, RA}}, +{"psq_st", OP(60), OP_MASK, PPCPS, PPCNONE, {FRS,PSD,RA,PSW,PSQ}}, {"stfdp", OP(61), OP_MASK, POWER6, PPCNONE, {FRT, D, RA0}}, +{"stfqu", OP(61), OP_MASK, POWER2, PPCNONE, {FRS, D, RA}}, + +{"psq_stu", OP(61), OP_MASK, PPCPS, PPCNONE, {FRS,PSD,RA,PSW,PSQ}}, + {"std", DSO(62,0), DS_MASK, PPC64, PPCNONE, {RS, DS, RA0}}, {"stdu", DSO(62,1), DS_MASK, PPC64, PPCNONE, {RS, DS, RAS}}, {"stq", DSO(62,2), DS_MASK, POWER4, PPCNONE, {RSQ, DS, RA0}},