/* Find a variable's value in memory, for GDB, the GNU debugger.
- Copyright (C) 1986-2016 Free Software Foundation, Inc.
+ Copyright (C) 1986-2020 Free Software Foundation, Inc.
This file is part of GDB.
#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"
#include "block.h"
#include "objfiles.h"
#include "language.h"
-#include "dwarf2loc.h"
+#include "dwarf2/loc.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
you lose
#endif
-LONGEST
-extract_signed_integer (const gdb_byte *addr, int len,
- enum bfd_endian byte_order)
+template<typename T, typename>
+T
+extract_integer (const gdb_byte *addr, int len, enum bfd_endian byte_order)
{
- LONGEST retval;
+ typename std::make_unsigned<T>::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<T>::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<T>::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<LONGEST> (const gdb_byte *addr, int len,
+ enum bfd_endian byte_order);
+template ULONGEST extract_integer<ULONGEST> (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
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_CODE_PTR && !TYPE_IS_REFERENCE (type))
internal_error (__FILE__, __LINE__,
_("extract_typed_address: "
"type is not a pointer or reference"));
/* All 'store' functions accept a host-format integer and store a
target-format integer at ADDR which is LEN bytes long. */
-
+template<typename T, typename>
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;
}
}
-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_CODE_PTR && !TYPE_IS_REFERENCE (type))
internal_error (__FILE__, __LINE__,
_("store_typed_address: "
"type is not a pointer or reference"));
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
- determined by register_type(). */
+ determined by register_type (). */
struct value *
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);
/* Return a `value' with the contents of (virtual or cooked) register
REGNUM as found in the specified FRAME. The register's type is
- determined by register_type(). The value is not fetched. */
+ determined by register_type (). The value is not fetched. */
struct value *
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);
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);
}
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);
}
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);
}
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);
}
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
{
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"));
return frame;
}
-/* A default implementation for the "la_read_var_value" hook in
- the language vector which should work in most situations. */
+/* See language.h. */
struct value *
-default_read_var_value (struct symbol *var, const struct block *var_block,
- struct frame_info *frame)
+language_defn::read_var_value (struct symbol *var,
+ const struct block *var_block,
+ struct frame_info *frame) const
{
struct value *v;
struct type *type = SYMBOL_TYPE (var);
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);
if (is_dynamic_type (type))
{
/* Value is a constant byte-sequence and needs no memory access. */
- type = resolve_dynamic_type (type, NULL, /* Unused address. */ 0);
+ type = resolve_dynamic_type (type, {}, /* Unused address. */ 0);
}
/* 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;
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));
if (is_dynamic_type (type))
{
/* Value is a constant byte-sequence and needs no memory access. */
- type = resolve_dynamic_type (type, NULL, /* Unused address. */ 0);
+ type = resolve_dynamic_type (type, {}, /* Unused address. */ 0);
}
v = allocate_value (type);
memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var),
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;
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);
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:
if (regval == NULL)
error (_("Value of register variable not available for `%s'."),
- SYMBOL_PRINT_NAME (var));
+ var->print_name ());
addr = value_as_address (regval);
}
if (regval == NULL)
error (_("Value of register variable not available for `%s'."),
- SYMBOL_PRINT_NAME (var));
+ var->print_name ());
return regval;
}
}
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),
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
break;
case LOC_OPTIMIZED_OUT:
+ if (is_dynamic_type (type))
+ type = resolve_dynamic_type (type, {}, /* 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;
}
return v;
}
-/* Calls VAR's language la_read_var_value hook with the given arguments. */
+/* Calls VAR's language read_var_value hook with the given arguments. */
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);
- return lang->la_read_var_value (var, var_block, frame);
+ return lang->read_var_value (var, var_block, frame);
}
/* Install default attributes for register values. */
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);
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,
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
+_initialize_findvar ()
+{
+#if GDB_SELF_TEST
+ selftests::register_test
+ ("copy_integer_to_size",
+ selftests::findvar_tests::copy_integer_to_size_test);
+#endif
+}