📄 valops.c
字号:
/* Perform non-arithmetic operations on values, for GDB. Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc.This file is part of GDB.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "defs.h"#include "symtab.h"#include "gdbtypes.h"#include "value.h"#include "frame.h"#include "inferior.h"#include "gdbcore.h"#include "target.h"#include <errno.h>/* Local functions. */static CORE_ADDRfind_function_addr PARAMS ((value, struct type **));static CORE_ADDRvalue_push PARAMS ((CORE_ADDR, value));CORE_ADDRvalue_arg_push PARAMS ((CORE_ADDR, value));static valuesearch_struct_field PARAMS ((char *, value, int, struct type *, int));static valuesearch_struct_method PARAMS ((char *, value *, value *, int, int *, struct type *));static intcheck_field_in PARAMS ((struct type *, const char *));/* Cast value ARG2 to type TYPE and return as a value. More general than a C cast: accepts any two types of the same length, and if ARG2 is an lvalue it can be cast into anything at all. *//* In C++, casts may change pointer representations. */valuevalue_cast (type, arg2) struct type *type; register value arg2;{ register enum type_code code1; register enum type_code code2; register int scalar; /* Coerce arrays but not enums. Enums will work as-is and coercing them would cause an infinite recursion. */ if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_ENUM) COERCE_ARRAY (arg2); code1 = TYPE_CODE (type); code2 = TYPE_CODE (VALUE_TYPE (arg2)); scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_ENUM); if (code1 == TYPE_CODE_FLT && scalar) return value_from_double (type, value_as_double (arg2)); else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM) && (scalar || code2 == TYPE_CODE_PTR)) return value_from_longest (type, value_as_long (arg2)); else if (TYPE_LENGTH (type) == TYPE_LENGTH (VALUE_TYPE (arg2))) { if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) { /* Look in the type of the source to see if it contains the type of the target as a superclass. If so, we'll need to offset the pointer rather than just change its type. */ struct type *t1 = TYPE_TARGET_TYPE (type); struct type *t2 = TYPE_TARGET_TYPE (VALUE_TYPE (arg2)); if ( TYPE_CODE (t1) == TYPE_CODE_STRUCT && TYPE_CODE (t2) == TYPE_CODE_STRUCT && TYPE_NAME (t1) != 0) /* if name unknown, can't have supercl */ { value v = search_struct_field (type_name_no_tag (t1), value_ind (arg2), 0, t2, 1); if (v) { v = value_addr (v); VALUE_TYPE (v) = type; return v; } } /* No superclass found, just fall through to change ptr type. */ } VALUE_TYPE (arg2) = type; return arg2; } else if (VALUE_LVAL (arg2) == lval_memory) { return value_at_lazy (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2)); } else if (code1 == TYPE_CODE_VOID) { return value_zero (builtin_type_void, not_lval); } else { error ("Invalid cast."); return 0; }}/* Create a value of type TYPE that is zero, and return it. */valuevalue_zero (type, lv) struct type *type; enum lval_type lv;{ register value val = allocate_value (type); memset (VALUE_CONTENTS (val), 0, TYPE_LENGTH (type)); VALUE_LVAL (val) = lv; return val;}/* Return a value with type TYPE located at ADDR. Call value_at only if the data needs to be fetched immediately; if we can be 'lazy' and defer the fetch, perhaps indefinately, call value_at_lazy instead. value_at_lazy simply records the address of the data and sets the lazy-evaluation-required flag. The lazy flag is tested in the VALUE_CONTENTS macro, which is used if and when the contents are actually required. */valuevalue_at (type, addr) struct type *type; CORE_ADDR addr;{ register value val = allocate_value (type); read_memory (addr, VALUE_CONTENTS_RAW (val), TYPE_LENGTH (type)); VALUE_LVAL (val) = lval_memory; VALUE_ADDRESS (val) = addr; return val;}/* Return a lazy value with type TYPE located at ADDR (cf. value_at). */valuevalue_at_lazy (type, addr) struct type *type; CORE_ADDR addr;{ register value val = allocate_value (type); VALUE_LVAL (val) = lval_memory; VALUE_ADDRESS (val) = addr; VALUE_LAZY (val) = 1; return val;}/* Called only from the VALUE_CONTENTS macro, if the current data for a variable needs to be loaded into VALUE_CONTENTS(VAL). Fetches the data from the user's process, and clears the lazy flag to indicate that the data in the buffer is valid. If the value is zero-length, we avoid calling read_memory, which would abort. We mark the value as fetched anyway -- all 0 bytes of it. This function returns a value because it is used in the VALUE_CONTENTS macro as part of an expression, where a void would not work. The value is ignored. */intvalue_fetch_lazy (val) register value val;{ CORE_ADDR addr = VALUE_ADDRESS (val) + VALUE_OFFSET (val); if (TYPE_LENGTH (VALUE_TYPE (val))) read_memory (addr, VALUE_CONTENTS_RAW (val), TYPE_LENGTH (VALUE_TYPE (val))); VALUE_LAZY (val) = 0; return 0;}/* Store the contents of FROMVAL into the location of TOVAL. Return a new value with the location of TOVAL and contents of FROMVAL. */valuevalue_assign (toval, fromval) register value toval, fromval;{ register struct type *type = VALUE_TYPE (toval); register value val; char raw_buffer[MAX_REGISTER_RAW_SIZE]; char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; int use_buffer = 0; COERCE_ARRAY (fromval); COERCE_REF (toval); if (VALUE_LVAL (toval) != lval_internalvar) fromval = value_cast (type, fromval); /* If TOVAL is a special machine register requiring conversion of program values to a special raw format, convert FROMVAL's contents now, with result in `raw_buffer', and set USE_BUFFER to the number of bytes to write. */ if (VALUE_REGNO (toval) >= 0 && REGISTER_CONVERTIBLE (VALUE_REGNO (toval))) { int regno = VALUE_REGNO (toval); if (VALUE_TYPE (fromval) != REGISTER_VIRTUAL_TYPE (regno)) fromval = value_cast (REGISTER_VIRTUAL_TYPE (regno), fromval); memcpy (virtual_buffer, VALUE_CONTENTS (fromval), REGISTER_VIRTUAL_SIZE (regno)); REGISTER_CONVERT_TO_RAW (regno, virtual_buffer, raw_buffer); use_buffer = REGISTER_RAW_SIZE (regno); } switch (VALUE_LVAL (toval)) { case lval_internalvar: set_internalvar (VALUE_INTERNALVAR (toval), fromval); break; case lval_internalvar_component: set_internalvar_component (VALUE_INTERNALVAR (toval), VALUE_OFFSET (toval), VALUE_BITPOS (toval), VALUE_BITSIZE (toval), fromval); break; case lval_memory: if (VALUE_BITSIZE (toval)) { int v; /* FIXME, this won't work for large bitfields */ read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), (char *) &v, sizeof v); modify_field ((char *) &v, (int) value_as_long (fromval), VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), (char *)&v, sizeof v); } else if (use_buffer) write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), raw_buffer, use_buffer); else write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); break; case lval_register: if (VALUE_BITSIZE (toval)) { int v; read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), (char *) &v, sizeof v); modify_field ((char *) &v, (int) value_as_long (fromval), VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), (char *) &v, sizeof v); } else if (use_buffer) write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), raw_buffer, use_buffer); else write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); break; case lval_reg_frame_relative: { /* value is stored in a series of registers in the frame specified by the structure. Copy that value out, modify it, and copy it back in. */ int amount_to_copy = (VALUE_BITSIZE (toval) ? 1 : TYPE_LENGTH (type)); int reg_size = REGISTER_RAW_SIZE (VALUE_FRAME_REGNUM (toval)); int byte_offset = VALUE_OFFSET (toval) % reg_size; int reg_offset = VALUE_OFFSET (toval) / reg_size; int amount_copied; char *buffer = (char *) alloca (amount_to_copy); int regno; FRAME frame; /* Figure out which frame this is in currently. */ for (frame = get_current_frame (); frame && FRAME_FP (frame) != VALUE_FRAME (toval); frame = get_prev_frame (frame)) ; if (!frame) error ("Value being assigned to is no longer active."); amount_to_copy += (reg_size - amount_to_copy % reg_size); /* Copy it out. */ for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset, amount_copied = 0); amount_copied < amount_to_copy; amount_copied += reg_size, regno++) { get_saved_register (buffer + amount_copied, (int *)NULL, (CORE_ADDR *)NULL, frame, regno, (enum lval_type *)NULL); } /* Modify what needs to be modified. */ if (VALUE_BITSIZE (toval)) modify_field (buffer + byte_offset, (int) value_as_long (fromval), VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); else if (use_buffer) memcpy (buffer + byte_offset, raw_buffer, use_buffer); else memcpy (buffer + byte_offset, VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); /* Copy it back. */ for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset, amount_copied = 0); amount_copied < amount_to_copy; amount_copied += reg_size, regno++) { enum lval_type lval; CORE_ADDR addr; int optim; /* Just find out where to put it. */ get_saved_register ((char *)NULL, &optim, &addr, frame, regno, &lval); if (optim) error ("Attempt to assign to a value that was optimized out."); if (lval == lval_memory) write_memory (addr, buffer + amount_copied, reg_size); else if (lval == lval_register) write_register_bytes (addr, buffer + amount_copied, reg_size); else error ("Attempt to assign to an unmodifiable value."); } } break; default: error ("Left side of = operation is not an lvalue."); } /* Return a value just like TOVAL except with the contents of FROMVAL (except in the case of the type if TOVAL is an internalvar). */ if (VALUE_LVAL (toval) == lval_internalvar || VALUE_LVAL (toval) == lval_internalvar_component) { type = VALUE_TYPE (fromval); } val = allocate_value (type); memcpy (val, toval, VALUE_CONTENTS_RAW (val) - (char *) val); memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); VALUE_TYPE (val) = type; return val;}/* Extend a value VAL to COUNT repetitions of its type. */valuevalue_repeat (arg1, count) value arg1; int count;{ register value val; if (VALUE_LVAL (arg1) != lval_memory) error ("Only values in memory can be extended with '@'."); if (count < 1) error ("Invalid number %d of repetitions.", count); val = allocate_repeat_value (VALUE_TYPE (arg1), count); read_memory (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1), VALUE_CONTENTS_RAW (val), TYPE_LENGTH (VALUE_TYPE (val)) * count); VALUE_LVAL (val) = lval_memory; VALUE_ADDRESS (val) = VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -