aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbtk-variable.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/gdbtk-variable.c')
-rw-r--r--gdb/gdbtk-variable.c1629
1 files changed, 0 insertions, 1629 deletions
diff --git a/gdb/gdbtk-variable.c b/gdb/gdbtk-variable.c
deleted file mode 100644
index f1e7455..0000000
--- a/gdb/gdbtk-variable.c
+++ /dev/null
@@ -1,1629 +0,0 @@
-/* Variable user interface for GDB, the GNU debugger.
- Copyright 1999 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 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. */
-
-#include "defs.h"
-#include "value.h"
-#include "expression.h"
-#include "frame.h"
-#include "valprint.h"
-
-#include <tcl.h>
-#include <tk.h>
-#include "gdbtk.h"
-#include "gdbtk-wrapper.h"
-
-#include <math.h>
-
-/* Enumeration type defining the return values for valueChanged */
-enum value_changed
-{
- VALUE_UNCHANGED, /* the variable's value is unchanged */
- VALUE_CHANGED, /* the variable's value has changed */
- VALUE_OUT_OF_SCOPE /* the variable is no longer in scope */
-};
-
-/* String representations of the value_changed enums */
-static char *value_changed_string[] = {
- "VARIABLE_UNCHANGED",
- "VARIABLE_CHANGED",
- "VARIABLE_OUT_OF_SCOPE",
- NULL
-};
-
-/* Enumeration for the format types */
-enum display_format
-{
- FORMAT_NATURAL, /* What gdb actually calls 'natural' */
- FORMAT_BINARY, /* Binary display */
- FORMAT_DECIMAL, /* Decimal display */
- FORMAT_HEXADECIMAL, /* Hex display */
- FORMAT_OCTAL /* Octal display */
-};
-
-/* Mappings of display_format enums to gdb's format codes */
-int format_code[] = {0, 't', 'd', 'x', 'o'};
-
-/* String representations of the format codes */
-char *format_string[] = {"natural", "binary", "decimal", "hexadecimal", "octal"};
-
-/* Every parent variable keeps a linked list of its children, described
- by the following structure. */
-struct variable_child {
-
- /* Pointer to the child's data */
- struct _gdb_variable *child;
-
- /* Pointer to the next child */
- struct variable_child *next;
-};
-
-/* Every variable in the system has a structure of this type defined
- for it. This structure holds all information necessary to manipulate
- a particular object variable. Members which must be freed are noted. */
-struct _gdb_variable {
-
- /* Alloc'd name of the variable for this object.. If this variable is a
- child, then this name will be the child's source name.
- (bar, not foo.bar) */
- char *name;
-
- /* The alloc'd real name of this variable. This is used to construct the
- variable's children. It is always a valid expression. */
- char *real_name;
-
- /* The alloc'd name for this variable's object. This is here for
- convenience when constructing this object's children. */
- char *obj_name;
-
- /* Alloc'd expression for this variable */
- struct expression *exp;
-
- /* Block for which this expression is valid */
- struct block *valid_block;
-
- /* The frame for this expression */
- CORE_ADDR frame;
-
- /* The value of this expression */
- value_ptr value;
-
- /* Did an error occur evaluating the expression or getting its value? */
- int error;
-
- /* The number of (immediate) children this variable has */
- int num_children;
-
- /* If this object is a child, this points to its parent. */
- struct _gdb_variable *parent;
-
- /* A list of this object's children */
- struct variable_child *children;
-
- /* The format of the output for this object */
- enum display_format format;
-};
-
-typedef struct _gdb_variable gdb_variable;
-
-/* This variable will hold the value of the output from gdb
- for commands executed through call_gdb_* */
-static Tcl_Obj *fputs_obj;
-
-/*
- * Public functions defined in this file
- */
-
-int gdb_variable_init PARAMS ((Tcl_Interp *));
-
-/*
- * Private functions defined in this file
- */
-
-/* Entries into this file */
-
-static int gdb_variable_command PARAMS ((ClientData, Tcl_Interp *, int,
- Tcl_Obj *CONST[]));
-
-static int variable_create PARAMS ((Tcl_Interp *, int, Tcl_Obj *CONST[]));
-
-static void variable_delete PARAMS ((Tcl_Interp *, gdb_variable *));
-
-static void variable_debug PARAMS ((gdb_variable *));
-
-static int variable_obj_command PARAMS ((ClientData, Tcl_Interp *, int,
- Tcl_Obj *CONST[]));
-static Tcl_Obj *variable_children PARAMS ((Tcl_Interp *, gdb_variable *));
-
-static enum value_changed variable_value_changed PARAMS ((gdb_variable *));
-
-static int variable_format PARAMS ((Tcl_Interp *, int, Tcl_Obj *CONST[],
- gdb_variable *));
-
-static int variable_type PARAMS ((Tcl_Interp *, int, Tcl_Obj *CONST[],
- gdb_variable *));
-
-static int variable_value PARAMS ((Tcl_Interp *, int, Tcl_Obj *CONST[],
- gdb_variable *));
-
-static int variable_editable PARAMS ((gdb_variable *));
-
-/* Helper functions for the above functions. */
-
-static gdb_variable *create_variable PARAMS ((char *, char *, CORE_ADDR));
-
-static void delete_children PARAMS ((Tcl_Interp *, gdb_variable *, int));
-
-static void install_variable PARAMS ((Tcl_Interp *, char *, gdb_variable *));
-
-static void uninstall_variable PARAMS ((Tcl_Interp *, gdb_variable *));
-
-static gdb_variable *child_exists PARAMS ((gdb_variable *, char *));
-
-static gdb_variable *create_child PARAMS ((Tcl_Interp *, gdb_variable *,
- char *, int));
-static char *name_of_child PARAMS ((gdb_variable *, int));
-
-static int number_of_children PARAMS ((gdb_variable *));
-
-static enum display_format variable_default_display PARAMS ((gdb_variable *));
-
-static void save_child_in_parent PARAMS ((gdb_variable *, gdb_variable *));
-
-static void remove_child_from_parent PARAMS ((gdb_variable *, gdb_variable *));
-
-static struct type *get_type PARAMS ((value_ptr));
-
-static struct type *get_target_type PARAMS ((struct type *));
-
-static Tcl_Obj *get_call_output PARAMS ((void));
-
-static void clear_gdb_output PARAMS ((void));
-
-static int call_gdb_type_print PARAMS ((value_ptr));
-
-static int call_gdb_val_print PARAMS ((value_ptr, int));
-
-static void variable_fputs PARAMS ((const char *, GDB_FILE *));
-
-static void null_fputs PARAMS ((const char *, GDB_FILE *));
-
-static int my_value_equal PARAMS ((gdb_variable *, value_ptr));
-
-#define INIT_VARIABLE(x) { \
-(x)->name = NULL; \
-(x)->real_name = NULL; \
-(x)->obj_name = NULL; \
-(x)->exp = NULL; \
-(x)->valid_block = NULL; \
-(x)->frame = (CORE_ADDR) 0; \
-(x)->value = NULL; \
-(x)->error = 0; \
-(x)->num_children = 0; \
-(x)->parent = NULL; \
-(x)->children = NULL; \
-(x)->format = FORMAT_NATURAL; \
-}
-
-#if defined(FREEIF)
-# undef FREEIF
-#endif
-#define FREEIF(x) if (x != NULL) free((char *) (x))
-
-/* Initialize the variable code. This function should be called once
- to install and initialize the variable code into the interpreter. */
-int
-gdb_variable_init (interp)
- Tcl_Interp *interp;
-{
- Tcl_Command result;
-
- result = Tcl_CreateObjCommand (interp, "gdb_variable", call_wrapper,
- (ClientData) gdb_variable_command, NULL);
- if (result == NULL)
- return TCL_ERROR;
-
- return TCL_OK;
-}
-
-/* This function defines the "gdb_variable" command which is used to
- create variable objects. Its syntax includes:
-
- gdb_variable create
- gdb_variable create NAME
- gdb_variable create -expr EXPR
- gdb_variable create NAME -expr EXPR
-
- NAME = name of object to create. If no NAME, then automatically create
- a name
- EXPR = the gdb expression for which to create a variable. This will
- be the most common usage.
-*/
-static int
-gdb_variable_command (clientData, interp, objc, objv)
- ClientData clientData;
- Tcl_Interp *interp;
- int objc;
- Tcl_Obj *CONST objv[];
-{
- static char *commands[] = { "create", NULL };
- enum commands_enum { VARIABLE_CREATE };
- int index, result;
-
- if (objc < 2)
- {
- Tcl_WrongNumArgs (interp, 1, objv, "option ?arg...?");
- return TCL_ERROR;
- }
-
- if (Tcl_GetIndexFromObj (interp, objv[1], commands, "options", 0,
- &index) != TCL_OK)
- {
- return TCL_ERROR;
- }
-
- switch ((enum commands_enum) index)
- {
- case VARIABLE_CREATE:
- result = variable_create (interp, objc - 2, objv + 2);
- break;
-
- default:
- return TCL_ERROR;
- }
-
- return result;
-}
-
-/* This function implements the actual object command for each
- variable object that is created (and each of its children).
-
- Currently the following commands are implemented:
- - delete delete this object and its children
- - valueChanged has the value of this object changed since the last check?
- - numChildren how many children does this object have
- - children create the children and return a list of their objects
- - debug print out a little debug info for the object
- - name print out the name of this variable
-*/
-static int
-variable_obj_command (clientData, interp, objc, objv)
- ClientData clientData;
- Tcl_Interp *interp;
- int objc;
- Tcl_Obj *CONST objv[];
-{
- enum commands_enum {
- VARIABLE_DELETE,
- VARIABLE_VALUE_CHANGED,
- VARIABLE_NUM_CHILDREN,
- VARIABLE_CHILDREN,
- VARIABLE_DEBUG,
- VARIABLE_FORMAT,
- VARIABLE_TYPE,
- VARIABLE_VALUE,
- VARIABLE_NAME,
- VARIABLE_EDITABLE
- };
- static char *commands[] = {
- "delete",
- "valueChanged",
- "numChildren",
- "children",
- "debug",
- "format",
- "type",
- "value",
- "name",
- "editable",
- NULL
- };
- gdb_variable *var = (gdb_variable *) clientData;
- int index, result;
-
- if (objc < 2)
- {
- Tcl_WrongNumArgs (interp, 1, objv, "option ?arg...?");
- return TCL_ERROR;
- }
-
- if (Tcl_GetIndexFromObj (interp, objv[1], commands, "options", 0,
- &index) != TCL_OK)
- return TCL_ERROR;
-
- result = TCL_OK;
- switch ((enum commands_enum) index)
- {
- case VARIABLE_DELETE:
- if (objc > 2)
- {
- int len;
- char *s = Tcl_GetStringFromObj (objv[2], &len);
- if (*s == 'c' && strncmp (s, "children", len) == 0)
- {
- delete_children (interp, var, 1);
- break;
- }
- }
- variable_delete (interp, var);
- break;
-
- case VARIABLE_VALUE_CHANGED:
- {
- enum value_changed vc = variable_value_changed (var);
- Tcl_SetObjResult (interp, Tcl_NewStringObj (value_changed_string[vc], -1));
- }
- break;
-
- case VARIABLE_NUM_CHILDREN:
- Tcl_SetObjResult (interp, Tcl_NewIntObj (var->num_children));
- break;
-
- case VARIABLE_CHILDREN:
- {
- Tcl_Obj *children = variable_children (interp, var);
- Tcl_SetObjResult (interp, children);
- }
- break;
-
- case VARIABLE_DEBUG:
- variable_debug (var);
- break;
-
- case VARIABLE_FORMAT:
- result = variable_format (interp, objc, objv, var);
- break;
-
- case VARIABLE_TYPE:
- result = variable_type (interp, objc, objv, var);
- break;
-
- case VARIABLE_VALUE:
- result = variable_value (interp, objc, objv, var);
- break;
-
- case VARIABLE_NAME:
- Tcl_SetObjResult (interp, Tcl_NewStringObj (var->name, -1));
- break;
-
- case VARIABLE_EDITABLE:
- Tcl_SetObjResult (interp, Tcl_NewIntObj (variable_editable (var)));
- break;
-
- default:
- return TCL_ERROR;
- }
-
- return result;
-}
-
-/*
- * Variable object construction/destruction
- */
-
-/* This function is responsible for processing the user's specifications
- and constructing a variable object. */
-static int
-variable_create (interp, objc, objv)
- Tcl_Interp *interp;
- int objc;
- Tcl_Obj *CONST objv[];
-{
- enum create_opts { CREATE_EXPR, CREATE_PC };
- static char *create_options[] = { "-expr", "-pc", NULL };
- gdb_variable *var;
- char *name;
- char obj_name[31];
- int index;
- static int id = 0;
- CORE_ADDR pc = (CORE_ADDR) -1;
-
- /* REMINDER: This command may be invoked in the following ways:
- gdb_variable create
- gdb_variable create NAME
- gdb_variable create -expr EXPR
- gdb_variable create NAME -expr EXPR
-
- NAME = name of object to create. If no NAME, then automatically create
- a name
- EXPR = the gdb expression for which to create a variable. This will
- be the most common usage.
- */
- name = NULL;
- if (objc)
- name = Tcl_GetStringFromObj (objv[0], NULL);
- if (name == NULL || *name == '-')
- {
- /* generate a name for this object */
- id++;
- sprintf (obj_name, "var%d", id);
- }
- else
- {
- /* specified name for object */
- strncpy (obj_name, name, 30);
- objv++;
- objc--;
- }
-
- /* Run through all the possible options for this command */
- name = NULL;
- while (objc > 0)
- {
- if (Tcl_GetIndexFromObj (interp, objv[0], create_options, "options",
- 0, &index) != TCL_OK)
- {
- result_ptr->flags |= GDBTK_IN_TCL_RESULT;
- return TCL_ERROR;
- }
-
- switch ((enum create_opts) index)
- {
- case CREATE_EXPR:
- name = Tcl_GetStringFromObj (objv[1], NULL);
- objc--;
- objv++;
- break;
-
- case CREATE_PC:
- {
- char *str;
- str = Tcl_GetStringFromObj (objv[1], NULL);
- pc = parse_and_eval_address (str);
- objc--;
- objv++;
- }
- break;
-
- default:
- break;
- }
-
- objc--;
- objv++;
- }
-
- /* Create the variable */
- {
- /* Add parentheses to the name so that casts do
- not confuse it. */
- char *newname = (char *) xmalloc (strlen (name) + 3);
- sprintf (newname, "(%s)", name);
- var = create_variable (name, newname, pc);
- FREEIF (newname);
- }
-
- if (var != NULL)
- {
- /* Install a command into the interpreter that represents this
- object */
- install_variable (interp, obj_name, var);
- Tcl_SetObjResult (interp, Tcl_NewStringObj (obj_name, -1));
- result_ptr->flags |= GDBTK_IN_TCL_RESULT;
-
- return TCL_OK;
- }
-
- return TCL_ERROR;
-}
-
-/* Fill out a gdb_variable structure for the variable being constructed.
- This function should never fail if real_name is a valid expression.
- (That means no longjmp'ing!) */
-static gdb_variable *
-create_variable (name, real_name, pc)
- char *name;
- char *real_name;
- CORE_ADDR pc;
-{
- gdb_variable *var;
- value_ptr mark;
- struct frame_info *fi, *old_fi;
- struct block *block;
- void (*old_fputs) PARAMS ((const char *, GDB_FILE *));
- gdb_result r;
-
- var = (gdb_variable *) xmalloc (sizeof (gdb_variable));
- INIT_VARIABLE (var);
-
- if (name != NULL)
- {
- char *p;
-
- /* Parse and evaluate the expression, filling in as much
- of the variable's data as possible */
-
- /* Allow creator to specify context of variable */
- if (pc == (CORE_ADDR) -1)
- block = 0;
- else
- {
- r = GDB_block_for_pc (pc, &block);
- if (r != GDB_OK)
- block = 0;
- }
-
- p = real_name;
- innermost_block = NULL;
- r = GDB_parse_exp_1 (&p, block, 0, &(var->exp));
- if (r != GDB_OK)
- {
- FREEIF ((char *) var);
- return NULL;
- }
-
- /* Don't allow variables to be created for types. */
- if (var->exp->elts[0].opcode == OP_TYPE)
- {
- free_current_contents ((char **) &(var->exp));
- FREEIF (var);
- printf_unfiltered ("Attempt to use a type name as an expression.");
- return NULL;
- }
-
- var->valid_block = innermost_block;
- var->name = savestring (name, strlen (name));
- var->real_name = savestring (real_name, strlen (real_name));
-
- /* Several of the GDB_* calls can cause messages to be displayed. We swallow
- those here, because we don't need them (the "value" command will
- show them). */
- old_fputs = fputs_unfiltered_hook;
- fputs_unfiltered_hook = null_fputs;
-
- /* When the PC is different from the current PC (pc == -1),
- then we must select the appropriate frame before parsing
- the expression, otherwise the value will not be current.
- Since select_frame is so benign, just call it for all cases. */
- r = GDB_block_innermost_frame (var->valid_block, &fi);
- if (r != GDB_OK)
- fi = NULL;
- if (fi)
- var->frame = FRAME_FP (fi);
- old_fi = selected_frame;
- GDB_select_frame (fi, -1);
-
- mark = value_mark ();
- if (GDB_evaluate_expression (var->exp, &var->value) == GDB_OK)
- {
- release_value (var->value);
- if (VALUE_LAZY (var->value))
- {
- if (GDB_value_fetch_lazy (var->value) != GDB_OK)
- var->error = 1;
- else
- var->error = 0;
- }
- }
- else
- var->error = 1;
- value_free_to_mark (mark);
-
- /* Reset the selected frame */
- GDB_select_frame (old_fi, -1);
-
- /* Restore the output hook to normal */
- fputs_unfiltered_hook = old_fputs;
-
- var->num_children = number_of_children (var);
- var->format = variable_default_display (var);
- }
-
- return var;
-}
-
-/* Install the given variable VAR into the tcl interpreter with
- the object name NAME. */
-static void
-install_variable (interp, name, var)
- Tcl_Interp *interp;
- char *name;
- gdb_variable *var;
-{
- var->obj_name = savestring (name, strlen (name));
- Tcl_CreateObjCommand (interp, name, variable_obj_command,
- (ClientData) var, NULL);
-}
-
-/* Unistall the object VAR in the tcl interpreter. */
-static void
-uninstall_variable (interp, var)
- Tcl_Interp *interp;
- gdb_variable *var;
-{
- Tcl_DeleteCommand (interp, var->obj_name);
-}
-
-/* Delete the variable object VAR and its children */
-static void
-variable_delete (interp, var)
- Tcl_Interp *interp;
- gdb_variable *var;
-{
- /* Delete any children of this variable, too. */
- delete_children (interp, var, 0);
-
- /* If this variable has a parent, remove it from its parent's list */
- if (var->parent != NULL)
- {
- remove_child_from_parent (var->parent, var);
- }
-
- uninstall_variable (interp, var);
-
- /* Free memory associated with this variable */
- FREEIF (var->name);
- FREEIF (var->real_name);
- FREEIF (var->obj_name);
- if (var->exp != NULL)
- free_current_contents ((char **) &var->exp);
- FREEIF (var);
-}
-
-/* Silly debugging info */
-static void
-variable_debug (var)
- gdb_variable *var;
-{
- Tcl_Obj *str;
-
- str = Tcl_NewStringObj ("name=", -1);
- Tcl_AppendStringsToObj (str, var->name, "\nreal_name=", var->real_name,
- "\nobj_name=", var->obj_name, NULL);
- Tcl_SetObjResult (gdbtk_interp, str);
-}
-
-/*
- * Child construction/destruction
- */
-
-/* Delete the children associated with the object VAR. If NOTIFY is set,
- notify the parent object that this child was deleted. This is used as
- a small optimization when deleting variables and their children. If the
- parent is also being deleted, don't bother notifying it that its children
- are being deleted. */
-static void
-delete_children (interp, var, notify)
- Tcl_Interp *interp;
- gdb_variable *var;
- int notify;
-{
- struct variable_child *vc;
- struct variable_child *next;
-
- for (vc = var->children; vc != NULL; vc = next)
- {
- if (!notify)
- vc->child->parent = NULL;
- variable_delete (interp, vc->child);
- next = vc->next;
- free (vc);
- }
-}
-
-/* Return the number of children for a given variable.
-
- This can get a little complicated, since we would like to make
- certain assumptions about certain types of variables.
-
- - struct/union *: dereference first
- - (*)(): do not allow derefencing
- - arrays:
- - declared size = num of children or
- - -1 if we don't know, i.e., int foo [];
- - if there was an error reported constructing this object,
- assume it has no children (and try this again later)
- - void * and char * have no children
-*/
-static int
-number_of_children (var)
- gdb_variable *var;
-{
- struct type *type;
- struct type *target;
- int children;
-
- if (var->value != NULL)
- {
- type = get_type (var->value);
- target = get_target_type (type);
- children = 0;
-
- switch (TYPE_CODE (type))
- {
- case TYPE_CODE_ARRAY:
- if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (target) > 0
- && TYPE_ARRAY_UPPER_BOUND_TYPE (type) != BOUND_CANNOT_BE_DETERMINED)
- children = TYPE_LENGTH (type) / TYPE_LENGTH (target);
- else
- children = -1;
- break;
-
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- /* If we have a virtual table pointer, omit it. */
- if (TYPE_VPTR_BASETYPE (type) == type
- && !(TYPE_VPTR_FIELDNO (type) < 0))
- children = TYPE_NFIELDS (type) - 1;
- else
- children = TYPE_NFIELDS (type);
- break;
-
- case TYPE_CODE_PTR:
- /* This is where things get compilcated. All pointers have one child.
- Except, of course, for struct and union ptr, which we automagically
- dereference for the user and function ptrs, which have no children. */
- switch (TYPE_CODE (target))
- {
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- /* If we have a virtual table pointer, omit it. */
- if (TYPE_VPTR_BASETYPE (target) == target
- && !(TYPE_VPTR_FIELDNO (target) < 0))
- children = TYPE_NFIELDS (target) - 1;
- else
- children = TYPE_NFIELDS (target);
- break;
-
- case TYPE_CODE_FUNC:
- children = 0;
- break;
-
- default:
- /* Don't dereference char* or void*. */
- if (TYPE_NAME (target) != NULL
- && (STREQ (TYPE_NAME (target), "char")
- || STREQ (TYPE_NAME (target), "void")))
- children = 0;
- else
- children = 1;
- }
- break;
-
- default:
- break;
- }
- }
- else
- {
- /* var->value can be null if we tried to access non-existent or
- protected memory. In this case, we simply do not allow any
- children. This will be checked again when we check if its
- value has changed. */
- children = 0;
- }
-
- return children;
-}
-
-/* Return a list of all the children of VAR, creating them if necessary. */
-static Tcl_Obj *
-variable_children (interp, var)
- Tcl_Interp *interp;
- gdb_variable *var;
-{
- Tcl_Obj *list;
- gdb_variable *child;
- char *name;
- int i;
-
- list = Tcl_NewListObj (0, NULL);
- for (i = 0; i < var->num_children; i++)
- {
- /* check if child exists */
- name = name_of_child (var, i);
- child = child_exists (var, name);
- if (child == NULL)
- {
- child = create_child (interp, var, name, i);
-
- /* name_of_child returns a malloc'd string */
- free (name);
- }
- Tcl_ListObjAppendElement (NULL, list, Tcl_NewStringObj (child->obj_name, -1));
- }
-
- return list;
-}
-
-/* Does a child with the name NAME exist in VAR? If so, return its data.
- If not, return NULL. */
-static gdb_variable *
-child_exists (var, name)
- gdb_variable *var; /* Parent */
- char *name; /* name of child */
-{
- struct variable_child *vc;
-
- for (vc = var->children; vc != NULL; vc = vc->next)
- {
- if (STREQ (vc->child->name, name))
- return vc->child;
- }
-
- return NULL;
-}
-
-/* Create and install a child of the parent of the given name */
-static gdb_variable *
-create_child (interp, parent, name, index)
- Tcl_Interp *interp;
- gdb_variable *parent;
- char *name;
- int index;
-{
- struct type *type;
- struct type *target;
- gdb_variable *child;
- char separator[10], prefix[2048], suffix[20];
- char *childs_name;
- char *save_name;
- int deref = 0;
- int len;
-
- /* name should never be null. For pointer derefs, it should contain "*name".
- For arrays of a known size, the name will simply contain the index into
- the array. */
-
- separator[0] = '\0';
- prefix[0] = '\0';
- suffix[0] = '\0';;
- save_name = name;
-
- /* This code must contain a lot of the logic for children based on the parent's
- type. */
- type = get_type (parent->value);
- target = get_target_type (type);
-
- switch (TYPE_CODE (type))
- {
- case TYPE_CODE_ARRAY:
- sprintf (suffix, "[%s]", name);
- name = "";
- break;
-
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- if (index < TYPE_N_BASECLASSES (type))
- {
- strcpy (prefix, "((");
- strcat (prefix, name);
- strcat (prefix, ")");
- strcpy (suffix, ") ");
- name = "";
- }
- else
- strcpy (separator, ".");
- break;
-
- case TYPE_CODE_PTR:
- switch (TYPE_CODE (target))
- {
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- if (index < TYPE_N_BASECLASSES (target))
- {
- strcpy (prefix, "(*(");
- strcat (prefix, name);
- strcat (prefix, " *)");
- strcpy (suffix, ")");
- name = "";
- }
- else
- strcpy (separator, "->");
- break;
-
- default:
- deref = 1;
- break;
- }
-
- default:
- break;
- }
-
- /* When we get here, we should know how to construct a legal
- expression for the child's name */
- len = strlen (prefix);
- len += strlen (parent->real_name);
- len += strlen (separator);
- len += strlen (name);
- len += strlen (suffix);
- if (deref)
- len += 3;
- childs_name = (char *) xmalloc ((len + 1) * sizeof (char));
- if (deref)
- {
- strcpy (childs_name, "(*");
- strcat (childs_name, parent->real_name);
- strcat (childs_name, suffix);
- strcat (childs_name, ")");
- }
- else
- {
- strcpy (childs_name, prefix);
- strcat (childs_name, parent->real_name);
- strcat (childs_name, separator);
- strcat (childs_name, name);
- strcat (childs_name, suffix);
- }
-
- /* childs_name now contains a valid expression for the child */
- child = create_variable (save_name, childs_name, (CORE_ADDR) -1);
- child->parent = parent;
- free (childs_name);
- childs_name = (char *) xmalloc ((strlen (parent->obj_name) + strlen (save_name) + 2)
- * sizeof (char));
- sprintf (childs_name, "%s.%s", parent->obj_name, save_name);
- install_variable (interp, childs_name, child);
- free (childs_name);
-
- /* Save a pointer to this child in the parent */
- save_child_in_parent (parent, child);
-
- return child;
-}
-
-/* Save CHILD in the PARENT's data. */
-static void
-save_child_in_parent (parent, child)
- gdb_variable *parent;
- gdb_variable *child;
-{
- struct variable_child *vc;
-
- /* Insert the child at the top */
- vc = parent->children;
- parent->children =
- (struct variable_child *) xmalloc (sizeof (struct variable_child));
-
- parent->children->next = vc;
- parent->children->child = child;
-}
-
-/* Remove the CHILD from the PARENT's list of children. */
-static void
-remove_child_from_parent (parent, child)
- gdb_variable *parent;
- gdb_variable *child;
-{
- struct variable_child *vc, *prev;
-
- /* Find the child in the parent's list */
- prev = NULL;
- for (vc = parent->children; vc != NULL; )
- {
- if (vc->child == child)
- break;
- prev = vc;
- vc = vc->next;
- }
-
- if (prev == NULL)
- parent->children = vc->next;
- else
- prev->next = vc->next;
-
-}
-
-/* What is the name of the INDEX'th child of VAR? */
-static char *
-name_of_child (var, index)
- gdb_variable *var;
- int index;
-{
- struct type *type;
- struct type *target;
- char *name;
- char *string;
-
- type = get_type (var->value);
- target = get_target_type (type);
-
- switch (TYPE_CODE (type))
- {
- case TYPE_CODE_ARRAY:
- {
- /* We never get here unless var->num_children is greater than 0... */
- int len = 1;
- while ((int) pow ((double) 10, (double) len) < index)
- len++;
- name = (char *) xmalloc (1 + len * sizeof (char));
- sprintf (name, "%d", index);
- }
- break;
-
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- string = TYPE_FIELD_NAME (type, index);
- name = savestring (string, strlen (string));
- break;
-
- case TYPE_CODE_PTR:
- switch (TYPE_CODE (target))
- {
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- string = TYPE_FIELD_NAME (target, index);
- name = savestring (string, strlen (string));
- break;
-
- default:
- name = (char *) xmalloc ((strlen (var->name) + 2) * sizeof (char));
- sprintf (name, "*%s", var->name);
- break;
- }
- }
-
- return name;
-}
-
-/* Has the value of this object changed since the last time we looked?
-
- There are some special cases:
- - structs/unions/arrays. The "value" of these never changes.
- Only their children's values change.
- - if an error occurred with evaluate_expression or fetch_value_lazy,
- then we need to be a little more elaborate with our determination
- of "value changed". Specifically, the value does not change when
- both the previous evaluate fails and the one done here also fails.
-*/
-static enum value_changed
-variable_value_changed (var)
- gdb_variable *var;
-{
- value_ptr mark, new_val;
- struct frame_info *fi, *old_fi;
- int within_scope;
- enum value_changed result;
- gdb_result r;
-
- /* Save the selected stack frame, since we will need to change it
- in order to evaluate expressions. */
- old_fi = selected_frame;
-
- /* Determine whether the variable is still around. */
- if (var->valid_block == NULL)
- within_scope = 1;
- else
- {
- GDB_reinit_frame_cache ();
- r = GDB_find_frame_addr_in_frame_chain (var->frame, &fi);
- if (r != GDB_OK)
- fi = NULL;
- within_scope = fi != NULL;
- /* FIXME: GDB_select_frame could fail */
- if (within_scope)
- GDB_select_frame (fi, -1);
- }
-
- result = VALUE_OUT_OF_SCOPE;
- if (within_scope)
- {
- struct type *type = get_type (var->value);
-
- /* Arrays, struct, classes, unions never change value */
- if (type != NULL && (TYPE_CODE (type) == TYPE_CODE_STRUCT
- || TYPE_CODE (type) == TYPE_CODE_UNION
- || TYPE_CODE (type) == TYPE_CODE_ARRAY))
- result = VALUE_UNCHANGED;
- else
- {
- mark = value_mark ();
- if (GDB_evaluate_expression (var->exp, &new_val) == GDB_OK)
- {
- if (!my_value_equal (var, new_val))
- {
- /* value changed */
- release_value (new_val);
- if (var->value == NULL)
- {
- /* This can happen if there was an error
- evaluating the expression (like deref NULL) */
- var->num_children = number_of_children (var);
- }
- value_free (var->value);
- var->value = new_val;
- result = VALUE_CHANGED;
- }
- else
- result = VALUE_UNCHANGED;
- }
- else
- {
- /* evaluate expression failed. If we failed before, then
- the value of this variable has not changed. If we
- succeed before, then the value did change. */
- if (var->value == NULL)
- result = VALUE_UNCHANGED;
- else
- {
- var->value = NULL;
- var->error = 1;
- result = VALUE_CHANGED;
- }
- }
-
- value_free_to_mark (mark);
- }
- }
-
- /* Restore selected frame */
- GDB_select_frame (old_fi, -1);
-
- return result;
-}
-
-static int
-variable_format (interp, objc, objv, var)
- Tcl_Interp *interp;
- int objc;
- Tcl_Obj *CONST objv[];
- gdb_variable *var;
-{
-
- if (objc > 2)
- {
- /* Set the format of VAR to given format */
- int len;
- char *fmt = Tcl_GetStringFromObj (objv[2], &len);
- if (STREQN (fmt, "natural", len))
- var->format = FORMAT_NATURAL;
- else if (STREQN (fmt, "binary", len))
- var->format = FORMAT_BINARY;
- else if (STREQN (fmt, "decimal", len))
- var->format = FORMAT_DECIMAL;
- else if (STREQN (fmt, "hexadecimal", len))
- var->format = FORMAT_HEXADECIMAL;
- else if (STREQN (fmt, "octal", len))
- var->format = FORMAT_OCTAL;
- else
- {
- Tcl_Obj *obj = Tcl_NewStringObj (NULL, 0);
- Tcl_AppendStringsToObj (obj, "unknown display format \"",
- fmt, "\": must be: \"natural\", \"binary\""
- ", \"decimal\", \"hexadecimal\", or \"octal\"",
- NULL);
- Tcl_SetObjResult (interp, obj);
- return TCL_ERROR;
- }
- }
- else
- {
- /* Report the current format */
- Tcl_Obj *fmt;
-
- fmt = Tcl_NewStringObj (format_string [(int) var->format], -1);
- Tcl_SetObjResult (interp, fmt);
- }
-
- return TCL_OK;
-}
-
-/* What is the default display for this variable? We assume that
- everything is "natural". Any exceptions? */
-static enum display_format
-variable_default_display (var)
- gdb_variable *var;
-{
- return FORMAT_NATURAL;
-}
-
-/* This function returns the type of a variable in the interpreter (or an error)
- and returns either TCL_OK or TCL_ERROR as appropriate. */
-static int
-variable_type (interp, objc, objv, var)
- Tcl_Interp *interp;
- int objc;
- Tcl_Obj *CONST objv[];
- gdb_variable *var;
-{
- int result;
- value_ptr val;
- char *first, *last, *string;
- Tcl_RegExp regexp;
- gdb_result r;
-
- if (var->value != NULL)
- val = var->value;
- else
- {
- r = GDB_evaluate_type (var->exp, &val);
- if (r != GDB_OK)
- return TCL_ERROR;
- }
-
- result = call_gdb_type_print (val);
- if (result == TCL_OK)
- {
- string = strdup (Tcl_GetStringFromObj (get_call_output (), NULL));
- first = string;
-
- /* gdb will print things out like "struct {...}" for anonymous structs.
- In gui-land, we don't want the {...}, so we strip it here. */
- regexp = Tcl_RegExpCompile (interp, "{...}");
- if (Tcl_RegExpExec (interp, regexp, string, first))
- {
- /* We have an anonymous struct/union/class/enum */
- Tcl_RegExpRange (regexp, 0, &first, &last);
- if (*(first - 1) == ' ')
- first--;
- *first = '\0';
- }
-
- Tcl_SetObjResult (interp, Tcl_NewStringObj (string, -1));
- FREEIF (string);
- return TCL_OK;
- }
-
- Tcl_SetObjResult (interp, get_call_output ());
- return result;
-}
-
-/* This function returns the value of a variable in the interpreter (or an error)
- and returns either TCL_OK or TCL_ERROR as appropriate. */
-static int
-variable_value (interp, objc, objv, var)
- Tcl_Interp *interp;
- int objc;
- Tcl_Obj *CONST objv[];
- gdb_variable *var;
-{
- int result;
- struct type *type;
- value_ptr val;
- Tcl_Obj *str;
- gdb_result r;
- int real_addressprint;
-
- /* If we set the value of the variable, objv[2] will contain the
- variable's new value. We need to first construct a legal expression
- for this -- ugh! */
- if (objc > 2)
- {
- /* Does this cover all the bases? */
- struct expression *exp;
- value_ptr value;
- int saved_input_radix = input_radix;
-
- if (VALUE_LVAL (var->value) != not_lval && var->value->modifiable)
- {
- char *s;
-
- input_radix = 10; /* ALWAYS reset to decimal temporarily */
- s = Tcl_GetStringFromObj (objv[2], NULL);
- r = GDB_parse_exp_1 (&s, 0, 0, &exp);
- if (r != GDB_OK)
- return TCL_ERROR;
- if (GDB_evaluate_expression (exp, &value) != GDB_OK)
- return TCL_ERROR;
-
- val = value_assign (var->value, value);
- value_free (var->value);
- release_value (val);
- var->value = val;
- input_radix = saved_input_radix;
- }
-
- return TCL_OK;
- }
-
- if (var->value != NULL)
- val = var->value;
- else
- {
- /* This can happen if we attempt to get the value of a struct
- member when the parent is an invalid pointer.
-
- GDB reports the error as the error derived from accessing the
- parent, but we don't have access to that here... */
- Tcl_SetObjResult (interp, Tcl_NewStringObj ("???", -1));
- return TCL_ERROR;
- }
-
- /* C++: addressprint causes val_print to print the
- address of the reference, too. So clear it to get
- the real value -- BUT ONLY FOR C++ REFERENCE TYPES! */
- real_addressprint = addressprint;
-
- /* BOGUS: if val_print sees a struct/class, it will print out its
- children instead of "{...}" */
- type = get_type (val);
- switch (TYPE_CODE (type))
- {
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- str = Tcl_NewStringObj ("{...}", -1);
- break;
-
- case TYPE_CODE_ARRAY:
- {
- char number[256];
- str = Tcl_NewStringObj (NULL, 0);
- sprintf (number, "%d", var->num_children);
- Tcl_AppendStringsToObj (str, "[", number, "]", NULL);
- }
- break;
-
- case TYPE_CODE_REF:
- /* Clear addressprint so that the actual value is printed */
- addressprint = 0;
-
- /* fall through */
- default:
- result = call_gdb_val_print (val, format_code[(int) var->format]);
- Tcl_SetObjResult (interp, get_call_output ());
-
- /* Restore addressprint */
- addressprint = real_addressprint;
- return result;
- }
-
- /* We only get here if we encountered one of the "special types" above */
-
- /* Restore addressprint */
- addressprint = real_addressprint;
-
- Tcl_SetObjResult (interp, str);
- return TCL_OK;
-}
-
-/* Is this variable editable? Use the variable's type to make
- this determination. */
-static int
-variable_editable (var)
- gdb_variable *var;
-{
- struct type *type;
- int result;
- gdb_result r;
-
- type = get_type (var->value);
- if (type == NULL)
- {
- value_ptr val;
- r = GDB_evaluate_type (var->exp, &val);
- if (r != GDB_OK)
- return 0;
- type = get_type (val);
- }
-
- switch (TYPE_CODE (type))
- {
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- case TYPE_CODE_ARRAY:
- case TYPE_CODE_FUNC:
- case TYPE_CODE_MEMBER:
- case TYPE_CODE_METHOD:
- result = 0;
- break;
-
- default:
- result = 1;
- break;
- }
-
- return result;
-}
-
-/*
- * Call stuff. These functions are used to capture the output of gdb commands
- * without going through the tcl interpreter.
- */
-
-/* Retrieve gdb output in the buffer since last call. */
-static Tcl_Obj *
-get_call_output ()
-{
- /* Clear the error flags, in case we errored. */
- if (result_ptr != NULL)
- result_ptr->flags &= ~GDBTK_ERROR_ONLY;
- return fputs_obj;
-}
-
-/* Clear the output of the buffer. */
-static void
-clear_gdb_output ()
-{
- if (fputs_obj != NULL)
- Tcl_DecrRefCount (fputs_obj);
-
- fputs_obj = Tcl_NewStringObj (NULL, -1);
- Tcl_IncrRefCount (fputs_obj);
-}
-
-/* Call the gdb command "type_print", retaining its output in the buffer. */
-static int
-call_gdb_type_print (val)
- value_ptr val;
-{
- void (*old_hook) PARAMS ((const char *, GDB_FILE *));
- int result;
-
- /* Save the old hook and install new hook */
- old_hook = fputs_unfiltered_hook;
- fputs_unfiltered_hook = variable_fputs;
-
- /* Call our command with our args */
- clear_gdb_output ();
-
-
- if (GDB_type_print (val, "", gdb_stdout, -1) == GDB_OK)
- result = TCL_OK;
- else
- result = TCL_ERROR;
-
- /* Restore fputs hook */
- fputs_unfiltered_hook = old_hook;
-
- return result;
-}
-
-/* Call the gdb command "val_print", retaining its output in the buffer. */
-static int
-call_gdb_val_print (val, format)
- value_ptr val;
- int format;
-{
- void (*old_hook) PARAMS ((const char *, GDB_FILE *));
- gdb_result r;
- int result;
-
- /* Save the old hook and install new hook */
- old_hook = fputs_unfiltered_hook;
- fputs_unfiltered_hook = variable_fputs;
-
- /* Call our command with our args */
- clear_gdb_output ();
-
- if (VALUE_LAZY (val))
- {
- r = GDB_value_fetch_lazy (val);
- if (r != GDB_OK)
- {
- fputs_unfiltered_hook = old_hook;
- return TCL_ERROR;
- }
- }
- r = GDB_val_print (VALUE_TYPE (val), VALUE_CONTENTS_RAW (val), VALUE_ADDRESS (val),
- gdb_stdout, format, 1, 0, 0);
- if (r == GDB_OK)
- result = TCL_OK;
- else
- result = TCL_ERROR;
-
- /* Restore fputs hook */
- fputs_unfiltered_hook = old_hook;
-
- return result;
-}
-
-/* The fputs_unfiltered_hook function used to save the output from one of the
- call commands in this file. */
-static void
-variable_fputs (text, stream)
- const char *text;
- GDB_FILE *stream;
-{
- /* Just append everything to the fputs_obj... Issues with stderr/stdout? */
- Tcl_AppendToObj (fputs_obj, (char *) text, -1);
-}
-
-/* Empty handler for the fputs_unfiltered_hook. Set the hook to this function
- whenever the output is irrelevent. */
-static void
-null_fputs (text, stream)
- const char *text;
- GDB_FILE *stream;
-{
- return;
-}
-
-/*
- * Special wrapper-like stuff to supplement the generic wrappers
- */
-
-/* This returns the type of the variable. This skips past typedefs
- and returns the real type of the variable. */
-static struct type *
-get_type (val)
- value_ptr val;
-{
- struct type *type = NULL;
-
- if (val != NULL)
- {
- type = VALUE_TYPE (val);
- while (type != NULL && TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
- type = TYPE_TARGET_TYPE (type);
- }
-
- return type;
-}
-
-/* This returns the target type (or NULL) of TYPE, also skipping
- past typedefs, just like get_type (). */
-static struct type *
-get_target_type (type)
- struct type *type;
-{
- if (type != NULL)
- {
- type = TYPE_TARGET_TYPE (type);
- while (type != NULL && TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
- type = TYPE_TARGET_TYPE (type);
- }
-
- return type;
-}
-
-/* This function is a special wrap. This call never "fails".*/
-static int
-my_value_equal (var, val2)
- gdb_variable *var;
- value_ptr val2;
-{
- int err1, err2, r;
-
- /* This is bogus, but unfortunately necessary. We must know
- exactly what caused an error -- reading var->val (which we
- get from var->error and/or val2, so that we can really determine
- if we think that something has changed. */
- err1 = var->error;
- err2 = 0;
- if (VALUE_LAZY (val2) && GDB_value_fetch_lazy (val2) != GDB_OK)
- err2 = 1;
-
- /* Another special case: NULL values. If both are null, say
- they're equal. */
- if (var->value == NULL && val2 == NULL)
- return 1;
- else if (var->value == NULL || val2 == NULL)
- return 0;
-
- if (GDB_value_equal (var->value, val2, &r) != GDB_OK)
- {
- /* An error occurred, this could have happened if
- either val1 or val2 errored. ERR1 and ERR2 tell
- us which of these it is. If both errored, then
- we assume nothing has changed. If one of them is
- valid, though, then something has changed. */
- if (err1 == err2)
- {
- /* both the old and new values caused errors, so
- we say the value did not change */
- /* This is indeterminate, though. Perhaps we should
- be safe and say, yes, it changed anyway?? */
- return 1;
- }
- else
- {
- /* err2 replaces var->error since this new value
- WILL replace the old one. */
- var->error = err2;
- return 0;
- }
- }
-
- return r;
-}
-
-/* Local variables: */
-/* change-log-default-name: "ChangeLog-gdbtk" */
-/* End: */