From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 5904 invoked by alias); 16 Nov 2005 14:43:21 -0000 Received: (qmail 5890 invoked by uid 22791); 16 Nov 2005 14:43:16 -0000 Received: from lon-del-02.spheriq.net (HELO lon-del-02.spheriq.net) (195.46.50.98) by sourceware.org (qpsmtpd/0.30-dev) with ESMTP; Wed, 16 Nov 2005 14:43:16 +0000 Received: from lon-out-02.spheriq.net ([195.46.50.130]) by lon-del-02.spheriq.net with ESMTP id jAGEhDaT026231 for ; Wed, 16 Nov 2005 14:43:13 GMT Received: from lon-cus-02.spheriq.net (lon-cus-02.spheriq.net [195.46.50.38]) by lon-out-02.spheriq.net with ESMTP id jAGEhDr3005807 for ; Wed, 16 Nov 2005 14:43:13 GMT Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by lon-cus-02.spheriq.net with ESMTP id jAGEhAHb011991 (version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=OK) for ; Wed, 16 Nov 2005 14:43:11 GMT Received: from zeta.dmz-eu.st.com (ns2.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id D7AB6DA45 for ; Wed, 16 Nov 2005 14:43:09 +0000 (GMT) Received: by zeta.dmz-eu.st.com (STMicroelectronics, from userid 60012) id 8B29B47413; Wed, 16 Nov 2005 14:46:08 +0000 (GMT) Received: from zeta.dmz-eu.st.com (localhost [127.0.0.1]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 1BA4C75969 for ; Wed, 16 Nov 2005 14:46:08 +0000 (UTC) Received: from mail1.bri.st.com (mail1.bri.st.com [164.129.8.218]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 439FD4741D for ; Wed, 16 Nov 2005 14:46:07 +0000 (GMT) Received: from [164.129.15.13] (terrorhawk.bri.st.com [164.129.15.13]) by mail1.bri.st.com (MOS 3.5.8-GR) with ESMTP id CGZ37549 (AUTH "andrew stubbs"); Wed, 16 Nov 2005 14:43:06 GMT Message-ID: <437B44E1.8090008@st.com> Date: Wed, 16 Nov 2005 15:54:00 -0000 From: Andrew STUBBS User-Agent: Mozilla Thunderbird 1.0.2 (Windows/20050317) MIME-Version: 1.0 To: gdb-patches@sources.redhat.com Subject: [PATCH] keep-variable command Content-Type: multipart/mixed; boundary="------------090909020103060603090208" X-O-Spoofed: Not Scanned X-O-General-Status: No X-O-Spam1-Status: Not Scanned X-O-Spam2-Status: Not Scanned X-O-URL-Status: Not Scanned X-O-Virus1-Status: No X-O-Virus2-Status: Not Scanned X-O-Virus3-Status: No X-O-Virus4-Status: No X-O-Virus5-Status: Not Scanned X-O-Image-Status: Not Scanned X-O-Attach-Status: Not Scanned X-SpheriQ-Ver: 4.1.07 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2005-11/txt/msg00230.txt.bz2 This is a multi-part message in MIME format. --------------090909020103060603090208 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 871 Hi, This patch adds a command 'keep-variable'. The command takes one single parameter - a convenience variable. This variable is then protected from being deleted by the symbol-file command. In order to achieve this it must patch up the type information after the symbol table has changed. If the type cannot be fixed up then a warning is given and the value is lost. Lazy fixup means that this only happens if the variable is actually accessed. If the keep-variable is never used then variables work exactly as before. I feel certain that there is something somebody will not like about this implementation, but I hope we can sort it out. The patch requires that my endian fixup patch has been applied first. The context in the patch assumes the init-if-undefined has been applied first, although the patch is not actually dependent. Thanks Andrew Stubbs --------------090909020103060603090208 Content-Type: text/plain; name="keepvariable.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="keepvariable.patch" Content-length: 14941 2005-11-16 Andrew Stubbs * value.c: Include exceptions.h. (fixup_internalvar_endian): Don't fix the endian if the type needs fixing due to keep-variable. (keep_variable_command): New function. (fixup_internalvar_type_info): New function. (lookup_internalvar): Call fixup_internalvar_type_info() if needed. Initialise new 'temp' and 'type_needs_fixing' fields. (set_internalvar): Reset type_needs_fixing. (get_name_from_type): New function. (clear_internalvars): Rewrite to support keep-variable command. (show_convenience): Call fixup_internalvar_type_info() if needed. (_initialize_values): Add keep-variable command. * exec.c (exec_file_attach). Call clear_internalvars(). * symfile.c (symbol_file_command). Call clear_internalvars(). * value.h (struct internalvar): Add 'temp', 'type_needs_fixing', 'type_name', and 'enclosing_type_name' fields. * Makefile.in (value.o): Add dependency on exceptions.h. doc/ * gdb.texinfo (Convenience variables): Add keep-variable command. Index: src/gdb/value.c =================================================================== --- src.orig/gdb/value.c 2005-11-07 18:27:03.000000000 +0000 +++ src/gdb/value.c 2005-11-07 18:27:04.000000000 +0000 @@ -37,6 +37,7 @@ #include "gdb_assert.h" #include "regcache.h" #include "block.h" +#include "exceptions.h" /* Prototypes for exported functions. */ @@ -779,10 +780,12 @@ fixup_internalvar_endian (struct interna gdb_byte temp; gdb_byte *array = value_contents_raw (var->value); - /* Don't do anything if the endian has not changed. + /* Don't do anything if the endian has not changed or if the type needs + fixing - the endian will be fixed with the type later. Also disregard FP types because they don't seem to vary with endian - at least, not on i686 Linux or sparc Solaris. */ if (var->endian != TARGET_BYTE_ORDER + && var->type_needs_fixing == 0 && TYPE_CODE (value_type (var->value)) != TYPE_CODE_FLT) { /* Reverse the bytes. @@ -811,6 +814,92 @@ fixup_all_internalvars_endian (void) } +/* Ensure that the specified internal variable will not be destroyed + when new symtabs are loaded. The argument 'name', must + be an internal variable name, prefixed with a dollar character. */ +static void +keep_variable_command (char* name, int from_tty) +{ + struct internalvar* intvar; + char* str; + + if (name == NULL || name[0] != '$') + { + printf_unfiltered( "usage: keep-variable $\n" ); + return; + } + + str = ++name; /* Remove $ character, i.e. "$var" ==> "var" */ + intvar = lookup_internalvar(str); + intvar->temp = 0; /* Preserve variable by clearing 'temp' attribute */ +} + +/* If the symbol table is reloaded then permanent variables will lose + their type info. clear_internalvars() makes a note of the name of + any such types in the variable. + This function is called whenever the variable is next required to + get the new type info. It also fixes the endianess if required. */ + +static void +fixup_internalvar_type_info (struct internalvar *var) +{ + int i, error=0; + + /* For each in type and enclosing type ... */ + for (i=0; i<2; i++) + { + char *type_name = i==0 ? var->type_name + : var->enclosing_type_name; + struct type **var_type = i==0 ? &var->value->type + : &var->value->enclosing_type; + + if (type_name != NULL) + { + /* Get the typename using parse expression - it can cope + with builtin types even when there is no symbol table. */ + struct expression *expr = (struct expression *) + catch_errors ((catch_errors_ftype *)parse_expression, + type_name, NULL, RETURN_MASK_ALL); + register struct cleanup *old_chain = + make_cleanup (free_current_contents, &expr); + + if (expr != NULL && expr->nelts >= 2 + && expr->elts[0].opcode == OP_TYPE) + /* Overwite the old (now broken) type with the shiny new one. */ + *var_type = expr->elts[1].type; + else + error=1; + + do_cleanups (old_chain); + } + } + + + if (error) + { + /* Types no longer exist. + The only thing to do is wipe the value. */ + xfree (var->value); + var->value = allocate_value (builtin_type_void); + release_value (var->value); + + /* Tell the user we have had to do this. + The message will occur when they are accessing the variable. */ + printf_unfiltered ( + "The type of '$%s' was lost when the symbol table was updated.\n", + var->name); + } + + /* Return the internal variable to its normal state. */ + xfree (var->type_name); + xfree (var->enclosing_type_name); + var->type_needs_fixing = 0; + + /* Fix up the endianess. */ + fixup_internalvar_endian (var); +} + + /* Look up an internal variable with name NAME. NAME should not normally include a dollar sign. @@ -824,12 +913,18 @@ lookup_internalvar (char *name) for (var = internalvars; var; var = var->next) if (strcmp (var->name, name) == 0) - return var; + { + if (var->type_needs_fixing) + fixup_internalvar_type_info (var); + return var; + } var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); var->name = concat (name, (char *)NULL); var->value = allocate_value (builtin_type_void); var->endian = TARGET_BYTE_ORDER; + var->temp = 1; + var->type_needs_fixing = 0; release_value (var->value); var->next = internalvars; internalvars = var; @@ -885,6 +980,7 @@ set_internalvar (struct internalvar *var xfree (var->value); var->value = newval; var->endian = TARGET_BYTE_ORDER; + var->type_needs_fixing = 0; release_value (newval); /* End code which must not call error(). */ } @@ -895,21 +991,136 @@ internalvar_name (struct internalvar *va return var->name; } -/* Free all internalvars. Done when new symtabs are loaded, - because that makes the values invalid. */ + +/* Get the typename from a struct type. + Returns the name of type as parse_expresion will understand. + Returns NULL if the type is unsupported. */ + +static char * +get_name_from_type (const struct type *type) +{ + char *result; + char *prefix = NULL, pointers=0; + + /* Follow the pointer types until the base type is discovered. */ + while (TYPE_CODE (type) == TYPE_CODE_PTR) + { + pointers++; + type = TYPE_TARGET_TYPE (type); + } + + /* Find the appropriate string for the type. + If we can't find one then return NULL and fixup_internalvar_type_info() + will replace the variable with void. If this is a problem then this + table will have to be extended to support the relavent type. */ + switch (TYPE_CODE (type)) + { + case TYPE_CODE_STRUCT: + prefix = "struct"; + /* Fall through. */ + case TYPE_CODE_UNION: + if (prefix == NULL) + prefix = "union"; + /* Fall through. */ + case TYPE_CODE_ENUM: + if (prefix == NULL) + prefix = "enum"; + + /* Note that these types do not have names, but do have tag names. */ + + if (TYPE_TAG_NAME(type) == NULL) + return NULL; + + result = xmalloc (strlen (prefix) + + 1 /* space */ + + strlen (TYPE_TAG_NAME(type)) + + 1 /* space */ + + pointers + + 1 /* terminator */); + sprintf( result, "%s %s ", prefix, TYPE_TAG_NAME(type)); + + break; + default: + /* Other types all (?) have names. */ + + if ( TYPE_NAME(type) == NULL ) + return NULL; + + result = xmalloc (strlen (TYPE_NAME(type)) + + 1 /* space */ + + pointers + + 1 /* terminator */); + sprintf (result, "%s ", TYPE_NAME(type)); + } + + /* Add stars for pointer types. */ + while ( pointers-- > 0 ) + strcat (result, "*"); + + return result; +} + + +/* Traverse list of intervalvars. If an internalvar's 'temp' + attribute is set, then free it - otherwise ignore it and check + the next member of the list. Ensure that 'internalvars' points + to the head of the list. + + Although the variables are kept, the type information is not. + Therefore take a note of the textual names. The types will then + be patched up later when they are referenced. The function that + does this is fixup_internalvars_type_info(). + + In order to take the notes BEFORE the types vanish a few extra + calls to this function have been inserted elsewhere. + + The majority of internalvar's will be cleared when new symtabs are + loaded, because at this point they become invalid. */ void clear_internalvars (void) { struct internalvar *var; + struct internalvar *next, **prev; - while (internalvars) + var = internalvars; + prev = &internalvars; + + while (var) { - var = internalvars; - internalvars = var->next; - xfree (var->name); - xfree (var->value); - xfree (var); + next = var->next; + + /* Is this a temporary variable? If so - free it. */ + if (var->temp) + { + /* Move the next variable up the list - we may want to keep it. */ + *prev = next; + + xfree (var->name); + xfree (var->value); + xfree (var); + } + else + { + /* This is a permanent variable so it will not be removed from + the list. Mark it as the current tail of the list. */ + prev = &var->next; + + /* Note down the values of the types. + This ensures that they can be fixed up after the symbol + tables are rebuilt. + Don't do it twice - the lazy fixup means it may not have been + fixed since the last time we were here. */ + if ( var->type_needs_fixing == 0 ) + { + var->type_needs_fixing = 1; + var->type_name = get_name_from_type (var->value->type); + var->enclosing_type_name = + get_name_from_type (var->value->enclosing_type); + } + } + + var = next; } } @@ -921,6 +1132,9 @@ show_convenience (char *ignore, int from for (var = internalvars; var; var = var->next) { + if (var->type_needs_fixing) + fixup_internalvar_type_info (var); + if (!varseen) { varseen = 1; @@ -1730,4 +1944,7 @@ A few convenience variables are given va init-if-undefined = \n\ Ensure that an internal variable exists and set it to\n\ a given value if it does not.")); + + add_com("keep-variable", class_vars, keep_variable_command, + _("Ensures that specified internal variable will not be removed")); } Index: src/gdb/exec.c =================================================================== --- src.orig/gdb/exec.c 2005-11-07 17:22:56.000000000 +0000 +++ src/gdb/exec.c 2005-11-07 18:27:04.000000000 +0000 @@ -266,6 +266,11 @@ exec_file_attach (char *filename, int fr validate_files (); + /* Delete convenience variables BEFORE their types become invalid. + This way a note can be made of what the types of the permanent + variables were and they can recover later. */ + clear_internalvars (); + set_gdbarch_from_file (exec_bfd); push_target (&exec_ops); Index: src/gdb/symfile.c =================================================================== --- src.orig/gdb/symfile.c 2005-11-07 17:22:56.000000000 +0000 +++ src/gdb/symfile.c 2005-11-07 18:27:04.000000000 +0000 @@ -1268,6 +1268,11 @@ symbol_file_command (char *args, int fro { dont_repeat (); + /* Delete convenience variables BEFORE their types become invalid. + This way a note can be made of what the types of the permanent + variables were and they can recover later. */ + clear_internalvars (); + if (args == NULL) { symbol_file_clear (from_tty); Index: src/gdb/value.h =================================================================== --- src.orig/gdb/value.h 2005-11-07 18:27:03.000000000 +0000 +++ src/gdb/value.h 2005-11-07 18:27:04.000000000 +0000 @@ -246,6 +246,15 @@ struct internalvar char *name; struct value *value; int endian; + + /* 'temp' determines whether the variable will be destroyed when + new symtabs are loaded. */ + int temp; + /* These are used to fixup the type pointers after the symbol tables + are reloaded. */ + char type_needs_fixing; + char *type_name; + char *enclosing_type_name; }; Index: src/gdb/Makefile.in =================================================================== --- src.orig/gdb/Makefile.in 2005-11-07 18:27:03.000000000 +0000 +++ src/gdb/Makefile.in 2005-11-07 18:27:04.000000000 +0000 @@ -2735,7 +2735,7 @@ valprint.o: valprint.c $(defs_h) $(gdb_s value.o: value.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ $(value_h) $(gdbcore_h) $(command_h) $(gdbcmd_h) $(target_h) \ $(language_h) $(scm_lang_h) $(demangle_h) $(doublest_h) \ - $(gdb_assert_h) $(regcache_h) $(block_h) + $(gdb_assert_h) $(regcache_h) $(block_h) $(exceptions_h) varobj.o: varobj.c $(defs_h) $(value_h) $(expression_h) $(frame_h) \ $(language_h) $(wrapper_h) $(gdbcmd_h) $(gdb_string_h) $(varobj_h) vaxbsd-nat.o: vaxbsd-nat.c $(defs_h) $(inferior_h) $(regcache_h) $(target_h) \ Index: src/gdb/doc/gdb.texinfo =================================================================== --- src.orig/gdb/doc/gdb.texinfo 2005-11-07 18:27:03.000000000 +0000 +++ src/gdb/doc/gdb.texinfo 2005-11-07 19:01:11.000000000 +0000 @@ -6120,6 +6120,11 @@ Using a convenience variable for the fir value is @code{void} until you assign a new value. You can alter the value with another assignment at any time. +@value{GDBN} commands that wipe the symbol table, such as @samp{file} and +@samp{symbol-file}, cause all convenience variables to be deleted - their +types are lost so their value would become meaningless. This can be avoided +using the @samp{keep-variable} command below. + Convenience variables have no fixed types. You can assign a convenience variable any type of value, including structures and arrays, even if that variable already has a value of a different type. The convenience @@ -6143,6 +6148,24 @@ override default values used in a comman If the variable is already defined then the expression is not evaluated so any side-effects do not occur. + +@kindex keep-variable +@cindex convenience variables, keeping +@item keep-variable $@var{variable} +Mark the variable to be preserved across commands which destroy the symbol +table, such as @samp{symbol-file}. + +The next time the variable is accessed (by whatever means) @value{GDBN} will +attempt to find a type, in the current symbol table, with the same name as +the type used previously. It does not check whether the new type is in any +way compatible with the old type. + +If a suitable type does not exist (at the time the variable is accessed) then +@value{GDBN} will print a message and reset the value to @code{void}. + +If the symbol table is destroyed and recreated multiple times, the content +of the intermediate tables has no effect, @emph{provided that the variable +is not accessed while they are loaded}. @end table One of the ways to use a convenience variable is as a counter to be --------------090909020103060603090208--