X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Ffindvar.c;h=18dd3cd04f5254247d22f9e8e1ba0fd715565b53;hb=c1b5c1ebc938b6dc0277363b8c47d75b0b5a621f;hp=80c709a9861f329dc940eb1c298eee063ac810f8;hpb=61baf725eca99af2569262d10aca03dcde2698f6;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/findvar.c b/gdb/findvar.c index 80c709a986..18dd3cd04f 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -1,6 +1,6 @@ /* Find a variable's value in memory, for GDB, the GNU debugger. - Copyright (C) 1986-2017 Free Software Foundation, Inc. + Copyright (C) 1986-2019 Free Software Foundation, Inc. This file is part of GDB. @@ -25,7 +25,6 @@ #include "gdbcore.h" #include "inferior.h" #include "target.h" -#include "floatformat.h" #include "symfile.h" /* for overlay functions */ #include "regcache.h" #include "user-regs.h" @@ -33,6 +32,7 @@ #include "objfiles.h" #include "language.h" #include "dwarf2loc.h" +#include "gdbsupport/selftest.h" /* Basic byte-swapping routines. All 'extract' functions return a host-format integer from a target-format integer at ADDR which is @@ -46,70 +46,54 @@ you lose #endif -LONGEST -extract_signed_integer (const gdb_byte *addr, int len, - enum bfd_endian byte_order) +template +T +extract_integer (const gdb_byte *addr, int len, enum bfd_endian byte_order) { - LONGEST retval; + typename std::make_unsigned::type retval = 0; const unsigned char *p; const unsigned char *startaddr = addr; const unsigned char *endaddr = startaddr + len; - if (len > (int) sizeof (LONGEST)) + if (len > (int) sizeof (T)) error (_("\ That operation is not available on integers of more than %d bytes."), - (int) sizeof (LONGEST)); + (int) sizeof (T)); /* Start at the most significant end of the integer, and work towards the least significant. */ if (byte_order == BFD_ENDIAN_BIG) { p = startaddr; - /* Do the sign extension once at the start. */ - retval = ((LONGEST) * p ^ 0x80) - 0x80; - for (++p; p < endaddr; ++p) + if (std::is_signed::value) + { + /* Do the sign extension once at the start. */ + retval = ((LONGEST) * p ^ 0x80) - 0x80; + ++p; + } + for (; p < endaddr; ++p) retval = (retval << 8) | *p; } else { p = endaddr - 1; - /* Do the sign extension once at the start. */ - retval = ((LONGEST) * p ^ 0x80) - 0x80; - for (--p; p >= startaddr; --p) + if (std::is_signed::value) + { + /* Do the sign extension once at the start. */ + retval = ((LONGEST) * p ^ 0x80) - 0x80; + --p; + } + for (; p >= startaddr; --p) retval = (retval << 8) | *p; } return retval; } -ULONGEST -extract_unsigned_integer (const gdb_byte *addr, int len, - enum bfd_endian byte_order) -{ - ULONGEST retval; - const unsigned char *p; - const unsigned char *startaddr = addr; - const unsigned char *endaddr = startaddr + len; - - if (len > (int) sizeof (ULONGEST)) - error (_("\ -That operation is not available on integers of more than %d bytes."), - (int) sizeof (ULONGEST)); - - /* Start at the most significant end of the integer, and work towards - the least significant. */ - retval = 0; - if (byte_order == BFD_ENDIAN_BIG) - { - for (p = startaddr; p < endaddr; ++p) - retval = (retval << 8) | *p; - } - else - { - for (p = endaddr - 1; p >= startaddr; --p) - retval = (retval << 8) | *p; - } - return retval; -} +/* Explicit instantiations. */ +template LONGEST extract_integer (const gdb_byte *addr, int len, + enum bfd_endian byte_order); +template ULONGEST extract_integer (const gdb_byte *addr, int len, + enum bfd_endian byte_order); /* Sometimes a long long unsigned integer can be extracted as a LONGEST value. This is done so that we can print these values @@ -169,8 +153,7 @@ extract_long_unsigned_integer (const gdb_byte *addr, int orig_len, CORE_ADDR extract_typed_address (const gdb_byte *buf, struct type *type) { - if (TYPE_CODE (type) != TYPE_CODE_PTR - && TYPE_CODE (type) != TYPE_CODE_REF) + if (TYPE_CODE (type) != TYPE_CODE_PTR && !TYPE_IS_REFERENCE (type)) internal_error (__FILE__, __LINE__, _("extract_typed_address: " "type is not a pointer or reference")); @@ -180,10 +163,10 @@ extract_typed_address (const gdb_byte *buf, struct type *type) /* All 'store' functions accept a host-format integer and store a target-format integer at ADDR which is LEN bytes long. */ - +template void -store_signed_integer (gdb_byte *addr, int len, - enum bfd_endian byte_order, LONGEST val) +store_integer (gdb_byte *addr, int len, enum bfd_endian byte_order, + T val) { gdb_byte *p; gdb_byte *startaddr = addr; @@ -209,41 +192,21 @@ store_signed_integer (gdb_byte *addr, int len, } } -void -store_unsigned_integer (gdb_byte *addr, int len, - enum bfd_endian byte_order, ULONGEST val) -{ - unsigned char *p; - unsigned char *startaddr = (unsigned char *) addr; - unsigned char *endaddr = startaddr + len; +/* Explicit instantiations. */ +template void store_integer (gdb_byte *addr, int len, + enum bfd_endian byte_order, + LONGEST val); - /* Start at the least significant end of the integer, and work towards - the most significant. */ - if (byte_order == BFD_ENDIAN_BIG) - { - for (p = endaddr - 1; p >= startaddr; --p) - { - *p = val & 0xff; - val >>= 8; - } - } - else - { - for (p = startaddr; p < endaddr; ++p) - { - *p = val & 0xff; - val >>= 8; - } - } -} +template void store_integer (gdb_byte *addr, int len, + enum bfd_endian byte_order, + ULONGEST val); /* Store the address ADDR as a pointer of type TYPE at BUF, in target form. */ void store_typed_address (gdb_byte *buf, struct type *type, CORE_ADDR addr) { - if (TYPE_CODE (type) != TYPE_CODE_PTR - && TYPE_CODE (type) != TYPE_CODE_REF) + if (TYPE_CODE (type) != TYPE_CODE_PTR && !TYPE_IS_REFERENCE (type)) internal_error (__FILE__, __LINE__, _("store_typed_address: " "type is not a pointer or reference")); @@ -251,7 +214,46 @@ store_typed_address (gdb_byte *buf, struct type *type, CORE_ADDR addr) gdbarch_address_to_pointer (get_type_arch (type), type, buf, addr); } +/* Copy a value from SOURCE of size SOURCE_SIZE bytes to DEST of size DEST_SIZE + bytes. If SOURCE_SIZE is greater than DEST_SIZE, then truncate the most + significant bytes. If SOURCE_SIZE is less than DEST_SIZE then either sign + or zero extended according to IS_SIGNED. Values are stored in memory with + endianness BYTE_ORDER. */ +void +copy_integer_to_size (gdb_byte *dest, int dest_size, const gdb_byte *source, + int source_size, bool is_signed, + enum bfd_endian byte_order) +{ + signed int size_diff = dest_size - source_size; + + /* Copy across everything from SOURCE that can fit into DEST. */ + + if (byte_order == BFD_ENDIAN_BIG && size_diff > 0) + memcpy (dest + size_diff, source, source_size); + else if (byte_order == BFD_ENDIAN_BIG && size_diff < 0) + memcpy (dest, source - size_diff, dest_size); + else + memcpy (dest, source, std::min (source_size, dest_size)); + + /* Fill the remaining space in DEST by either zero extending or sign + extending. */ + + if (size_diff > 0) + { + gdb_byte extension = 0; + if (is_signed + && ((byte_order != BFD_ENDIAN_BIG && source[source_size - 1] & 0x80) + || (byte_order == BFD_ENDIAN_BIG && source[0] & 0x80))) + extension = 0xff; + + /* Extend into MSBs of SOURCE. */ + if (byte_order == BFD_ENDIAN_BIG) + memset (dest, extension, size_diff); + else + memset (dest + source_size, extension, size_diff); + } +} /* Return a `value' with the contents of (virtual or cooked) register REGNUM as found in the specified FRAME. The register's type is @@ -265,8 +267,7 @@ value_of_register (int regnum, struct frame_info *frame) /* User registers lie completely outside of the range of normal registers. Catch them early so that the target never sees them. */ - if (regnum >= gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch)) + if (regnum >= gdbarch_num_cooked_regs (gdbarch)) return value_of_user_reg (regnum, frame); reg_val = value_of_register_lazy (frame, regnum); @@ -285,8 +286,7 @@ value_of_register_lazy (struct frame_info *frame, int regnum) struct value *reg_val; struct frame_info *next_frame; - gdb_assert (regnum < (gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch))); + gdb_assert (regnum < gdbarch_num_cooked_regs (gdbarch)); gdb_assert (frame != NULL); @@ -309,7 +309,7 @@ CORE_ADDR unsigned_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf) { - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + enum bfd_endian byte_order = type_byte_order (type); return extract_unsigned_integer (buf, TYPE_LENGTH (type), byte_order); } @@ -318,7 +318,7 @@ CORE_ADDR signed_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf) { - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + enum bfd_endian byte_order = type_byte_order (type); return extract_signed_integer (buf, TYPE_LENGTH (type), byte_order); } @@ -329,7 +329,7 @@ void unsigned_address_to_pointer (struct gdbarch *gdbarch, struct type *type, gdb_byte *buf, CORE_ADDR addr) { - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + enum bfd_endian byte_order = type_byte_order (type); store_unsigned_integer (buf, TYPE_LENGTH (type), byte_order, addr); } @@ -338,7 +338,7 @@ void address_to_signed_pointer (struct gdbarch *gdbarch, struct type *type, gdb_byte *buf, CORE_ADDR addr) { - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + enum bfd_endian byte_order = type_byte_order (type); store_signed_integer (buf, TYPE_LENGTH (type), byte_order, addr); } @@ -446,7 +446,7 @@ follow_static_link (struct frame_info *frame, QUIT; /* If we don't know how to compute FRAME's base address, don't give up: - maybe the frame we are looking for is upper in the stace frame. */ + maybe the frame we are looking for is upper in the stack frame. */ if (framefunc != NULL && SYMBOL_BLOCK_OPS (framefunc) != NULL && SYMBOL_BLOCK_OPS (framefunc)->get_frame_base != NULL @@ -566,9 +566,9 @@ get_hosting_frame (struct symbol *var, const struct block *var_block, { if (BLOCK_FUNCTION (var_block) && !block_inlined_p (var_block) - && SYMBOL_PRINT_NAME (BLOCK_FUNCTION (var_block))) + && BLOCK_FUNCTION (var_block)->print_name ()) error (_("No frame is currently executing in block %s."), - SYMBOL_PRINT_NAME (BLOCK_FUNCTION (var_block))); + BLOCK_FUNCTION (var_block)->print_name ()); else error (_("No frame is currently executing in specified" " block")); @@ -601,7 +601,7 @@ default_read_var_value (struct symbol *var, const struct block *var_block, if (sym_need == SYMBOL_NEEDS_FRAME) gdb_assert (frame != NULL); else if (sym_need == SYMBOL_NEEDS_REGISTERS && !target_has_registers) - error (_("Cannot read `%s' without registers"), SYMBOL_PRINT_NAME (var)); + error (_("Cannot read `%s' without registers"), var->print_name ()); if (frame != NULL) frame = get_hosting_frame (var, var_block, frame); @@ -620,7 +620,7 @@ default_read_var_value (struct symbol *var, const struct block *var_block, /* Put the constant back in target format. */ v = allocate_value (type); store_signed_integer (value_contents_raw (v), TYPE_LENGTH (type), - gdbarch_byte_order (get_type_arch (type)), + type_byte_order (type), (LONGEST) SYMBOL_VALUE (var)); VALUE_LVAL (v) = not_lval; return v; @@ -630,7 +630,7 @@ default_read_var_value (struct symbol *var, const struct block *var_block, v = allocate_value (type); if (overlay_debugging) { - CORE_ADDR addr + addr = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var), SYMBOL_OBJ_SECTION (symbol_objfile (var), var)); @@ -668,7 +668,7 @@ default_read_var_value (struct symbol *var, const struct block *var_block, addr = get_frame_args_address (frame); if (!addr) error (_("Unknown argument list address for `%s'."), - SYMBOL_PRINT_NAME (var)); + var->print_name ()); addr += SYMBOL_VALUE (var); break; @@ -680,7 +680,7 @@ default_read_var_value (struct symbol *var, const struct block *var_block, argref = get_frame_args_address (frame); if (!argref) error (_("Unknown argument list address for `%s'."), - SYMBOL_PRINT_NAME (var)); + var->print_name ()); argref += SYMBOL_VALUE (var); ref = value_at (lookup_pointer_type (type), argref); addr = value_as_address (ref); @@ -694,16 +694,16 @@ default_read_var_value (struct symbol *var, const struct block *var_block, case LOC_TYPEDEF: error (_("Cannot look up value of a typedef `%s'."), - SYMBOL_PRINT_NAME (var)); + var->print_name ()); break; case LOC_BLOCK: if (overlay_debugging) addr = symbol_overlayed_address - (BLOCK_START (SYMBOL_BLOCK_VALUE (var)), + (BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (var)), SYMBOL_OBJ_SECTION (symbol_objfile (var), var)); else - addr = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); + addr = BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (var)); break; case LOC_REGISTER: @@ -721,7 +721,7 @@ default_read_var_value (struct symbol *var, const struct block *var_block, if (regval == NULL) error (_("Value of register variable not available for `%s'."), - SYMBOL_PRINT_NAME (var)); + var->print_name ()); addr = value_as_address (regval); } @@ -731,7 +731,7 @@ default_read_var_value (struct symbol *var, const struct block *var_block, if (regval == NULL) error (_("Value of register variable not available for `%s'."), - SYMBOL_PRINT_NAME (var)); + var->print_name ()); return regval; } } @@ -747,7 +747,7 @@ default_read_var_value (struct symbol *var, const struct block *var_block, struct obj_section *obj_section; memset (&lookup_data, 0, sizeof (lookup_data)); - lookup_data.name = SYMBOL_LINKAGE_NAME (var); + lookup_data.name = var->linkage_name (); gdbarch_iterate_over_objfiles_in_search_order (symbol_arch (var), @@ -767,7 +767,7 @@ default_read_var_value (struct symbol *var, const struct block *var_block, can't be NULL. */ gdb_assert (flavour_name != NULL); error (_("Missing %s symbol \"%s\"."), - flavour_name, SYMBOL_LINKAGE_NAME (var)); + flavour_name, var->linkage_name ()); } obj_section = MSYMBOL_OBJ_SECTION (lookup_data.result.objfile, msym); /* Relocate address, unless there is no section or the variable is @@ -787,11 +787,13 @@ default_read_var_value (struct symbol *var, const struct block *var_block, break; case LOC_OPTIMIZED_OUT: + if (is_dynamic_type (type)) + type = resolve_dynamic_type (type, NULL, /* Unused address. */ 0); return allocate_optimized_out_value (type); default: error (_("Cannot look up value of a botched symbol `%s'."), - SYMBOL_PRINT_NAME (var)); + var->print_name ()); break; } @@ -805,7 +807,7 @@ struct value * read_var_value (struct symbol *var, const struct block *var_block, struct frame_info *frame) { - const struct language_defn *lang = language_def (SYMBOL_LANGUAGE (var)); + const struct language_defn *lang = language_def (var->language ()); gdb_assert (lang != NULL); gdb_assert (lang->la_read_var_value != NULL); @@ -838,7 +840,7 @@ default_value_from_register (struct gdbarch *gdbarch, struct type *type, an integral number of registers. Otherwise, you need to do some fiddling with the last register copied here for little endian machines. */ - if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG + if (type_byte_order (type) == BFD_ENDIAN_BIG && len < register_size (gdbarch, regnum)) /* Big-endian, and we want less than full size. */ set_value_offset (value, register_size (gdbarch, regnum) - len); @@ -953,8 +955,7 @@ address_from_register (int regnum, struct frame_info *frame) struct type *type = builtin_type (gdbarch)->builtin_data_ptr; struct value *value; CORE_ADDR result; - int regnum_max_excl = (gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch)); + int regnum_max_excl = gdbarch_num_cooked_regs (gdbarch); if (regnum < 0 || regnum >= regnum_max_excl) error (_("Invalid register #%d, expecting 0 <= # < %d"), regnum, @@ -1002,8 +1003,97 @@ address_from_register (int regnum, struct frame_info *frame) result = value_as_address (value); release_value (value); - value_free (value); return result; } +#if GDB_SELF_TEST +namespace selftests { +namespace findvar_tests { + +/* Function to test copy_integer_to_size. Store SOURCE_VAL with size + SOURCE_SIZE to a buffer, making sure no sign extending happens at this + stage. Copy buffer to a new buffer using copy_integer_to_size. Extract + copied value and compare to DEST_VALU. Copy again with a signed + copy_integer_to_size and compare to DEST_VALS. Do everything for both + LITTLE and BIG target endians. Use unsigned values throughout to make + sure there are no implicit sign extensions. */ + +static void +do_cint_test (ULONGEST dest_valu, ULONGEST dest_vals, int dest_size, + ULONGEST src_val, int src_size) +{ + for (int i = 0; i < 2 ; i++) + { + gdb_byte srcbuf[sizeof (ULONGEST)] = {}; + gdb_byte destbuf[sizeof (ULONGEST)] = {}; + enum bfd_endian byte_order = i ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE; + + /* Fill the src buffer (and later the dest buffer) with non-zero junk, + to ensure zero extensions aren't hidden. */ + memset (srcbuf, 0xaa, sizeof (srcbuf)); + + /* Store (and later extract) using unsigned to ensure there are no sign + extensions. */ + store_unsigned_integer (srcbuf, src_size, byte_order, src_val); + + /* Test unsigned. */ + memset (destbuf, 0xaa, sizeof (destbuf)); + copy_integer_to_size (destbuf, dest_size, srcbuf, src_size, false, + byte_order); + SELF_CHECK (dest_valu == extract_unsigned_integer (destbuf, dest_size, + byte_order)); + + /* Test signed. */ + memset (destbuf, 0xaa, sizeof (destbuf)); + copy_integer_to_size (destbuf, dest_size, srcbuf, src_size, true, + byte_order); + SELF_CHECK (dest_vals == extract_unsigned_integer (destbuf, dest_size, + byte_order)); + } +} + +static void +copy_integer_to_size_test () +{ + /* Destination is bigger than the source, which has the signed bit unset. */ + do_cint_test (0x12345678, 0x12345678, 8, 0x12345678, 4); + do_cint_test (0x345678, 0x345678, 8, 0x12345678, 3); + + /* Destination is bigger than the source, which has the signed bit set. */ + do_cint_test (0xdeadbeef, 0xffffffffdeadbeef, 8, 0xdeadbeef, 4); + do_cint_test (0xadbeef, 0xffffffffffadbeef, 8, 0xdeadbeef, 3); + + /* Destination is smaller than the source. */ + do_cint_test (0x5678, 0x5678, 2, 0x12345678, 3); + do_cint_test (0xbeef, 0xbeef, 2, 0xdeadbeef, 3); + + /* Destination and source are the same size. */ + do_cint_test (0x8765432112345678, 0x8765432112345678, 8, 0x8765432112345678, + 8); + do_cint_test (0x432112345678, 0x432112345678, 6, 0x8765432112345678, 6); + do_cint_test (0xfeedbeaddeadbeef, 0xfeedbeaddeadbeef, 8, 0xfeedbeaddeadbeef, + 8); + do_cint_test (0xbeaddeadbeef, 0xbeaddeadbeef, 6, 0xfeedbeaddeadbeef, 6); + + /* Destination is bigger than the source. Source is bigger than 32bits. */ + do_cint_test (0x3412345678, 0x3412345678, 8, 0x3412345678, 6); + do_cint_test (0xff12345678, 0xff12345678, 8, 0xff12345678, 6); + do_cint_test (0x432112345678, 0x432112345678, 8, 0x8765432112345678, 6); + do_cint_test (0xff2112345678, 0xffffff2112345678, 8, 0xffffff2112345678, 6); +} + +} // namespace findvar_test +} // namespace selftests + +#endif + +void +_initialize_findvar (void) +{ +#if GDB_SELF_TEST + selftests::register_test + ("copy_integer_to_size", + selftests::findvar_tests::copy_integer_to_size_test); +#endif +}