📄 values.c
字号:
/* Low level packing and unpacking of values for GDB, the GNU Debugger. Copyright 1986, 1987, 1989, 1991 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 <string.h>#include "symtab.h"#include "gdbtypes.h"#include "value.h"#include "gdbcore.h"#include "frame.h"#include "command.h"#include "gdbcmd.h"#include "target.h"#include "demangle.h"/* Local function prototypes. */static valuevalue_headof PARAMS ((value, struct type *, struct type *));static voidshow_values PARAMS ((char *, int));static voidshow_convenience PARAMS ((char *, int));/* The value-history records all the values printed by print commands during this session. Each chunk records 60 consecutive values. The first chunk on the chain records the most recent values. The total number of values is in value_history_count. */#define VALUE_HISTORY_CHUNK 60struct value_history_chunk{ struct value_history_chunk *next; value values[VALUE_HISTORY_CHUNK];};/* Chain of chunks now in use. */static struct value_history_chunk *value_history_chain;static int value_history_count; /* Abs number of last entry stored *//* List of all value objects currently allocated (except for those released by calls to release_value) This is so they can be freed after each command. */static value all_values;/* Allocate a value that has the correct length for type TYPE. */valueallocate_value (type) struct type *type;{ register value val; check_stub_type (type); val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type)); VALUE_NEXT (val) = all_values; all_values = val; VALUE_TYPE (val) = type; VALUE_LVAL (val) = not_lval; VALUE_ADDRESS (val) = 0; VALUE_FRAME (val) = 0; VALUE_OFFSET (val) = 0; VALUE_BITPOS (val) = 0; VALUE_BITSIZE (val) = 0; VALUE_REPEATED (val) = 0; VALUE_REPETITIONS (val) = 0; VALUE_REGNO (val) = -1; VALUE_LAZY (val) = 0; VALUE_OPTIMIZED_OUT (val) = 0; return val;}/* Allocate a value that has the correct length for COUNT repetitions type TYPE. */valueallocate_repeat_value (type, count) struct type *type; int count;{ register value val; val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type) * count); VALUE_NEXT (val) = all_values; all_values = val; VALUE_TYPE (val) = type; VALUE_LVAL (val) = not_lval; VALUE_ADDRESS (val) = 0; VALUE_FRAME (val) = 0; VALUE_OFFSET (val) = 0; VALUE_BITPOS (val) = 0; VALUE_BITSIZE (val) = 0; VALUE_REPEATED (val) = 1; VALUE_REPETITIONS (val) = count; VALUE_REGNO (val) = -1; VALUE_LAZY (val) = 0; VALUE_OPTIMIZED_OUT (val) = 0; return val;}/* Return a mark in the value chain. All values allocated after the mark is obtained (except for those released) are subject to being freed if a subsequent value_free_to_mark is passed the mark. */valuevalue_mark (){ return all_values;}/* Free all values allocated since MARK was obtained by value_mark (except for those released). */voidvalue_free_to_mark (mark) value mark;{ value val, next; for (val = all_values; val && val != mark; val = next) { next = VALUE_NEXT (val); value_free (val); } all_values = val;}/* Free all the values that have been allocated (except for those released). Called after each command, successful or not. */voidfree_all_values (){ register value val, next; for (val = all_values; val; val = next) { next = VALUE_NEXT (val); value_free (val); } all_values = 0;}/* Remove VAL from the chain all_values so it will not be freed automatically. */voidrelease_value (val) register value val;{ register value v; if (all_values == val) { all_values = val->next; return; } for (v = all_values; v; v = v->next) { if (v->next == val) { v->next = val->next; break; } }}/* Return a copy of the value ARG. It contains the same contents, for same memory address, but it's a different block of storage. */valuevalue_copy (arg) value arg;{ register value val; register struct type *type = VALUE_TYPE (arg); if (VALUE_REPEATED (arg)) val = allocate_repeat_value (type, VALUE_REPETITIONS (arg)); else val = allocate_value (type); VALUE_LVAL (val) = VALUE_LVAL (arg); VALUE_ADDRESS (val) = VALUE_ADDRESS (arg); VALUE_OFFSET (val) = VALUE_OFFSET (arg); VALUE_BITPOS (val) = VALUE_BITPOS (arg); VALUE_BITSIZE (val) = VALUE_BITSIZE (arg); VALUE_REGNO (val) = VALUE_REGNO (arg); VALUE_LAZY (val) = VALUE_LAZY (arg); if (!VALUE_LAZY (val)) { memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS_RAW (arg), TYPE_LENGTH (VALUE_TYPE (arg)) * (VALUE_REPEATED (arg) ? VALUE_REPETITIONS (arg) : 1)); } return val;}/* Access to the value history. *//* Record a new value in the value history. Returns the absolute history index of the entry. Result of -1 indicates the value was not saved; otherwise it is the value history index of this new item. */intrecord_latest_value (val) value val;{ int i; /* Check error now if about to store an invalid float. We return -1 to the caller, but allow them to continue, e.g. to print it as "Nan". */ if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FLT) { unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &i); if (i) return -1; /* Indicate value not saved in history */ } /* Here we treat value_history_count as origin-zero and applying to the value being stored now. */ i = value_history_count % VALUE_HISTORY_CHUNK; if (i == 0) { register struct value_history_chunk *new = (struct value_history_chunk *) xmalloc (sizeof (struct value_history_chunk)); memset (new->values, 0, sizeof new->values); new->next = value_history_chain; value_history_chain = new; } value_history_chain->values[i] = val; release_value (val); /* Now we regard value_history_count as origin-one and applying to the value just stored. */ return ++value_history_count;}/* Return a copy of the value in the history with sequence number NUM. */valueaccess_value_history (num) int num;{ register struct value_history_chunk *chunk; register int i; register int absnum = num; if (absnum <= 0) absnum += value_history_count; if (absnum <= 0) { if (num == 0) error ("The history is empty."); else if (num == 1) error ("There is only one value in the history."); else error ("History does not go back to $$%d.", -num); } if (absnum > value_history_count) error ("History has not yet reached $%d.", absnum); absnum--; /* Now absnum is always absolute and origin zero. */ chunk = value_history_chain; for (i = (value_history_count - 1) / VALUE_HISTORY_CHUNK - absnum / VALUE_HISTORY_CHUNK; i > 0; i--) chunk = chunk->next; return value_copy (chunk->values[absnum % VALUE_HISTORY_CHUNK]);}/* Clear the value history entirely. Must be done when new symbol tables are loaded, because the type pointers become invalid. */voidclear_value_history (){ register struct value_history_chunk *next; register int i; register value val; while (value_history_chain) { for (i = 0; i < VALUE_HISTORY_CHUNK; i++) if (val = value_history_chain->values[i]) free ((PTR)val); next = value_history_chain->next; free ((PTR)value_history_chain); value_history_chain = next; } value_history_count = 0;}static voidshow_values (num_exp, from_tty) char *num_exp; int from_tty;{ register int i; register value val; static int num = 1; if (num_exp) { if (num_exp[0] == '+' && num_exp[1] == '\0') /* "info history +" should print from the stored position. */ ; else /* "info history <exp>" should print around value number <exp>. */ num = parse_and_eval_address (num_exp) - 5; } else { /* "info history" means print the last 10 values. */ num = value_history_count - 9; } if (num <= 0) num = 1; for (i = num; i < num + 10 && i <= value_history_count; i++) { val = access_value_history (i); printf_filtered ("$%d = ", i); value_print (val, stdout, 0, Val_pretty_default); printf_filtered ("\n"); } /* The next "info history +" should start after what we just printed. */ num += 10; /* Hitting just return after this command should do the same thing as "info history +". If num_exp is null, this is unnecessary, since "info history +" is not useful after "info history". */ if (from_tty && num_exp) { num_exp[0] = '+'; num_exp[1] = '\0'; }}/* Internal variables. These are variables within the debugger that hold values assigned by debugger commands. The user refers to them with a '$' prefix that does not appear in the variable names stored internally. */static struct internalvar *internalvars;/* Look up an internal variable with name NAME. NAME should not normally include a dollar sign. If the specified internal variable does not exist, one is created, with a void value. */struct internalvar *lookup_internalvar (name) char *name;{ register struct internalvar *var; for (var = internalvars; var; var = var->next) if (!strcmp (var->name, name)) return var; var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); var->name = concat (name, NULL); var->value = allocate_value (builtin_type_void); release_value (var->value); var->next = internalvars; internalvars = var; return var;}valuevalue_of_internalvar (var) struct internalvar *var;{ register value val;#ifdef IS_TRAPPED_INTERNALVAR if (IS_TRAPPED_INTERNALVAR (var->name)) return VALUE_OF_TRAPPED_INTERNALVAR (var);#endif val = value_copy (var->value); if (VALUE_LAZY (val)) value_fetch_lazy (val); VALUE_LVAL (val) = lval_internalvar; VALUE_INTERNALVAR (val) = var; return val;}voidset_internalvar_component (var, offset, bitpos, bitsize, newval) struct internalvar *var; int offset, bitpos, bitsize; value newval;{ register char *addr = VALUE_CONTENTS (var->value) + offset;#ifdef IS_TRAPPED_INTERNALVAR if (IS_TRAPPED_INTERNALVAR (var->name)) SET_TRAPPED_INTERNALVAR (var, newval, bitpos, bitsize, offset);#endif if (bitsize) modify_field (addr, (int) value_as_long (newval), bitpos, bitsize); else memcpy (addr, VALUE_CONTENTS (newval), TYPE_LENGTH (VALUE_TYPE (newval)));}voidset_internalvar (var, val) struct internalvar *var; value val;{#ifdef IS_TRAPPED_INTERNALVAR if (IS_TRAPPED_INTERNALVAR (var->name)) SET_TRAPPED_INTERNALVAR (var, val, 0, 0, 0);#endif free ((PTR)var->value); var->value = value_copy (val); /* Force the value to be fetched from the target now, to avoid problems later when this internalvar is referenced and the target is gone or has changed. */ if (VALUE_LAZY (var->value)) value_fetch_lazy (var->value); release_value (var->value);}char *internalvar_name (var) struct internalvar *var;{ return var->name;}/* Free all internalvars. Done when new symtabs are loaded, because that makes the values invalid. */voidclear_internalvars (){ register struct internalvar *var; while (internalvars) { var = internalvars; internalvars = var->next; free ((PTR)var->name); free ((PTR)var->value); free ((PTR)var); }}static voidshow_convenience (ignore, from_tty) char *ignore; int from_tty;{ register struct internalvar *var; int varseen = 0; for (var = internalvars; var; var = var->next) {#ifdef IS_TRAPPED_INTERNALVAR if (IS_TRAPPED_INTERNALVAR (var->name)) continue;#endif if (!varseen) { varseen = 1; } printf_filtered ("$%s = ", var->name); value_print (var->value, stdout, 0, Val_pretty_default); printf_filtered ("\n"); } if (!varseen) printf ("No debugger convenience variables now defined.\n\Convenience variables have names starting with \"$\";\n\use \"set\" as in \"set $foo = 5\" to define them.\n");}/* Extract a value as a C number (either long or double). Knows how to convert fixed values to double, or floating values to long. Does not deallocate the value. */LONGESTvalue_as_long (val) register value val;{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -