[RFA] resubmit: cached function lookup; strict return type analysis

Klee Dienes klee@apple.com
Tue Jan 8 15:18:00 GMT 2002


Hi!  I sent this a while back (12 December), but hadn't heard anything
in a bit, so I figured I'd resubmit.  I've since updated the patch to
use the 'struct value *' and 'struct cached_value *' instead of
'value_ptr' and 'cached_value_ptr', and updated it to be against the
most recent source tree, but otherwise it's the same as the patch I
submitted in December:

------------------------------

The following patch overlaps a bit with the previous one (it requires
the symnbol_generation support), but otherwise it should be
standalone.  I'm mainly submitting it now because it is required by
some of the Objective-C patches, but is significant enough in it's own
right that I wanted to address any issues with it separately rather
than as part of the Objective-C submission.

There are two primary things changed by the patch:

1) is that functions in the target used by GDB ("malloc",
"scm_lookup_cstr", and later a ton of Objective-C functions) now have
their values cached and re-used unless the symbol table has changed
in-between calls.  This is a performance win overall, and a particular
win when dispatching Objective-C method calls and looking up
Objective-C type information from the runtime.

2) is potentially a bit more controversial.  It adds "expected return
type" support to the target function call interface.  The "expected
return type" is specified using cast syntax; it is ignored if actual
type information for the function is available.  If no type
information is provided for a function, the user is now required to
provide an expected return type using the cast syntax, or get an
error.

Some examples:

(gdb) print fabs (3.0)                  (no type information present)
Unable to call function at 0x%lx: no return type information available.
To call this function anyway, you can cast the return type explicitly
(e.g. 'print (float) fabs (3.0)').

(gdb) print (float) fabs (-3.12)        (no type information present)
$1 = 3.11999989

(gdb) print (int) fabs (-3.12)          (no type information present)
$2 = 1074329026
(here, the return value of `fabs' has been interpreted as an int
... not cast to one)

(gdb) print (int) fabs (-3.12)          (type information present)
$3 = -3
(since type information was available, the return value was
interpreted as a float, then cast to an int).

(gdb) print (struct stat) fabs (-3.12)  (no type information present)
Cannot access memory at address 0xf5c28f6
(this causes an error, since the struct return convention is being
misused)

  struct s { int i; int j; };
  struct s f (void) { struct s ss = { 3, 1 }; return ss; }

(gdb) print f ()                        (no type information present)
Unable to call function at 0x%lx: no return type information available.
To call this function anyway, you can cast the return type explicitly
(e.g. 'print (float) fabs (3.0)').

(gdb) print (struct s) f (3.0)          (no type information present)
$4 = {i = 3, j = 1}

(gdb) print (float) f (3.0)             (no type information present)
Program received signal SIGSEGV, Segmentation fault.
0x0804841d in f ()
(here we lied to GDB about the return type, causing it to generate
incorrect struct return code).

Compare this to the old behavior:

(gdb) print fabs (3.0)                  (no type information present)
$1 = 1074266112
(GDB has no type information available, so it assumes 'int').

(gdb) print (float) fabs (-3.12)        (no type information present)
$2 = 1.07426611e+09
(GDB still assumes the function returns 'int', then casts the result
to a float).

  struct s { int i; int j; };
  struct s f (void) { struct s ss = { 3, 1 }; return ss; }

(gdb) print f ()
Program received signal SIGSEGV, Segmentation fault.
0x0804841d in f ()
(here there is no way out ... no matter what we pass in as the return
value to f(), GDB will generate the calling convention for a function
returning int)

The reason I suggest 2) might be controversial is that the old
behavior can be convenient in the general case.  A lot of functions
*do* return int, and when debugging programs without symbols, it can
be annoying to have to declare the return type, just to make the rare
case when functions return floats/structs behave correctly.  But I'd
argue that it's not *that* big a deal to cast a return value, and
correctness must always take priority.

We've been using a variant of this patch at Apple for a little over a
year; it seems to be working.  The test suite shows four additional
unexpected successes when I run it with this patch, but I figure
that's probably OK.

I haven't included documentation patches ... where (if anywhere) would
you suggest I include them?  I wasn't able to find a compelling spot.
Or perhaps one could argue that the new behavior is simply "correct,"
and the new message you get from print fabs (3.0) is enough.

------------------------------

2001-12-12  Klee Dienes <kdienes@apple.com>

        * breakpoint.c (breakpoint_re_set, breakpoint_re_set_all,
        breakpoint_update): Instead of re-parsing all deferred breakpoints
        every time breakpoint_re_set is called, increment a generation
        number.  When breakpoints need to be up-to-date, call
        breakpoint_update.  This prevents unnecessary re-parsing of
        breakpoint information (and massive future-break spam) when
        multiple shared libraries are loaded at the same time.

        * breakpoint.h: export symbol_generation, breakpoint_update.

        * eval.c (evaluate_subexp_standard): when called with
        EVAL_AVOID_SIDE_EFFECTS, return the passed-in `expect_type' if the
        type of the evaluated expression is unknown.  Also update to use
        the new `call_function_by_hand_expecting_type' interface.

        * gdbtypes.c, gdbtypes.h: add new type
        builtin_type_voidptrfuncptr.

        * parse.c, parse.h: export msym_{text,data,unknown}_symbol_type.
        Make them of type TYPE_CODE_ERROR instead of TYPE_CODE_INT.

        * scm-lang.c (scm_lookup_name): update to use new interface to
        find_function_in_inferior.

        * valops.c (create_cached_function, lookup_cached_function): add.
        These functions create a new data type (a `cached_value'), whose
        purpose is to store the lookup of commonly used symbols GDB needs
        from the inferior.  For example, evaluating the expression 'print
        "hello"' causes GDB to call `malloc' in the target.  Looking up
        the symbol for `malloc' takes a non-trivial amount of time, and
        has no need to be done if the symbols have not changed.
        create/lookup_cached_function allow GDB to cache the results of
        these lookups; re-looking them up only when the symbols have
        changed.
        (find_function_in_inferior): add a default type as second
        argument.  This type will be used for the returned value if no
        type information is available for the function (previously, the
        type was assumed to be (char *) (*).
        (hand_function_call): add new `expect_type' parameter.  This type
        will be used as the return type for the function if no type
        information is available.
        (call_function_by_hand_expecting_type): like
        call_function_by_hand, but uses the new `expect_type' interface to
        hand_function_call.
        (call_function_by_hand): implement as a wrapper to
        call_function_by_hand_expecting_type.
        (value_allocate_space_in_inferior): use new cached_function
        interface.
        (find_function_addr): if asked the return type of a function with
        type TYPE_CODE_ERROR, return TYPE_CODE_ERROR.

        * value.h (call_function_by_hand_expecting_type): add.
        (cached_value) add.
        (create_cached_function) add.
        (lookup_cached_function) add.
        (find_function_in_inferior) update to new signature.


Index: gdb/breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.57
diff -u -r1.57 breakpoint.c
--- breakpoint.c        2001/11/11 16:39:59     1.57
+++ breakpoint.c        2002/01/08 22:43:28
@@ -70,8 +70,12 @@
 
 static void ignore_command (char *, int);
 
+void breakpoint_update (void);
+
 static int breakpoint_re_set_one (PTR);
 
+static void breakpoint_re_set_all (void);
+
 static void clear_command (char *, int);
 
 static void catch_command (char *, int);
@@ -720,6 +724,7 @@
   static char message1[] = "Error inserting catchpoint %d:\n";
   static char message[sizeof (message1) + 30];
 
+  breakpoint_update ();
 
   ALL_BREAKPOINTS_SAFE (b, temp)
   {
@@ -7187,9 +7192,26 @@
   return 0;
 }
 
-/* Re-set all breakpoints after symbols have been re-loaded.  */
+unsigned int symbol_generation = 1;
+static unsigned int breakpoint_generation = 0;
+
+void breakpoint_update (void)
+{
+  if (breakpoint_generation != symbol_generation) {
+    breakpoint_re_set_all ();
+    breakpoint_generation = symbol_generation;
+  }
+}
+
 void
 breakpoint_re_set (void)
+{
+  symbol_generation++;
+}
+
+/* Re-set all breakpoints after symbols have been re-loaded.  */
+static void
+breakpoint_re_set_all (void)
 {
   struct breakpoint *b, *temp;
   enum language save_language;
Index: gdb/breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.10
diff -u -r1.10 breakpoint.h
--- breakpoint.h        2001/10/20 23:54:29     1.10
+++ breakpoint.h        2002/01/08 22:43:28
@@ -305,6 +305,8 @@
 
 typedef struct bpstats *bpstat;
 
+extern unsigned int symbol_generation;
+
 /* Interface:  */
 /* Clear a bpstat so that it says we are not at any breakpoint.
    Also free any storage that is part of a bpstat.  */
@@ -525,6 +527,8 @@
 extern int breakpoint_thread_match (CORE_ADDR, ptid_t);
 
 extern void until_break_command (char *, int);
+
+extern void breakpoint_update (void);
 
 extern void breakpoint_re_set (void);
 
Index: gdb/c-valprint.c
===================================================================
RCS file: /cvs/src/src/gdb/c-valprint.c,v
retrieving revision 1.11
diff -u -r1.11 c-valprint.c
--- c-valprint.c        2001/11/10 20:44:37     1.11
+++ c-valprint.c        2002/01/08 22:43:28
@@ -449,7 +449,7 @@
       break;
 
     case TYPE_CODE_ERROR:
-      fprintf_filtered (stream, "<error type>");
+      fprintf_filtered (stream, "<unknown type>");
       break;
 
     case TYPE_CODE_UNDEF:
Index: gdb/eval.c
===================================================================
RCS file: /cvs/src/src/gdb/eval.c,v
retrieving revision 1.19
diff -u -r1.19 eval.c
--- eval.c      2002/01/04 17:51:38     1.19
+++ eval.c      2002/01/08 22:43:29
@@ -928,15 +928,20 @@
             gdb isn't asked for it's opinion (ie. through "whatis"),
             it won't offer it. */
 
-         struct type *ftype =
+         struct type *type =
          TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0]));
 
-         if (ftype)
-           return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0])));
+         if (type)
+           {
+             if ((TYPE_CODE (type) == TYPE_CODE_ERROR) && expect_type)
+               return allocate_value (expect_type);
+             else
+               return allocate_value (type);
+           }
          else
            error ("Expression of type other than \"Function returning ...\" used as function");
        }
-      return call_function_by_hand (argvec[0], nargs, argvec + 1);
+      return call_function_by_hand_expecting_type (argvec[0], expect_type, nargs, argvec + 1);
       /* pai: FIXME save value from call_function_by_hand, then adjust pc by adjust_fn_pc if +ve  */
 
     case OP_F77_UNDETERMINED_ARGLIST:
Index: gdb/gdbtypes.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.c,v
retrieving revision 1.35
diff -u -r1.35 gdbtypes.c
--- gdbtypes.c  2001/12/20 03:26:08     1.35
+++ gdbtypes.c  2002/01/08 22:43:29
@@ -96,6 +96,7 @@
 struct type *builtin_type_void_func_ptr;
 struct type *builtin_type_CORE_ADDR;
 struct type *builtin_type_bfd_vma;
+struct type *builtin_type_voidptrfuncptr;
 
 int opaque_type_resolution = 1;
 int overload_debug = 0;
@@ -3209,6 +3210,8 @@
     init_type (TYPE_CODE_INT, TARGET_BFD_VMA_BIT / 8,
               TYPE_FLAG_UNSIGNED,
               "__bfd_vma", (struct objfile *) NULL);
+  builtin_type_voidptrfuncptr =
+    lookup_pointer_type (lookup_function_type (lookup_pointer_type (builtin_type_void)));
 }
 
 
Index: gdb/gdbtypes.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.h,v
retrieving revision 1.21
diff -u -r1.21 gdbtypes.h
--- gdbtypes.h  2001/12/10 06:17:01     1.21
+++ gdbtypes.h  2002/01/08 22:43:30
@@ -930,6 +930,7 @@
    bit address type even though the TARGET has a 64 bit pointer type
    (cf MIPS). */
 extern struct type *builtin_type_bfd_vma;
+extern struct type *builtin_type_voidptrfuncptr;
 
 /* Explicit sizes - see C9X <intypes.h> for naming scheme */
 extern struct type *builtin_type_int8;
Index: gdb/parse.c
===================================================================
RCS file: /cvs/src/src/gdb/parse.c,v
retrieving revision 1.17
diff -u -r1.17 parse.c
--- parse.c     2001/11/15 01:55:59     1.17
+++ parse.c     2002/01/08 22:43:30
@@ -399,9 +399,9 @@
    based on the language, but they no longer have names like "int", so
    the initial rationale is gone.  */
 
-static struct type *msym_text_symbol_type;
-static struct type *msym_data_symbol_type;
-static struct type *msym_unknown_symbol_type;
+struct type *msym_text_symbol_type;
+struct type *msym_data_symbol_type;
+struct type *msym_unknown_symbol_type;
 
 void
 write_exp_msymbol (struct minimal_symbol *msymbol, 
@@ -1359,13 +1359,13 @@
   int i;
 
   msym_text_symbol_type =
-    init_type (TYPE_CODE_FUNC, 1, 0, "<text variable, no debug info>", NULL);
-  TYPE_TARGET_TYPE (msym_text_symbol_type) = builtin_type_int;
+    init_type (TYPE_CODE_FUNC, 0, 0, "<text variable, no debug info>", NULL);
+  TYPE_TARGET_TYPE (msym_text_symbol_type) = builtin_type_error;
   msym_data_symbol_type =
-    init_type (TYPE_CODE_INT, TARGET_INT_BIT / HOST_CHAR_BIT, 0,
+    init_type (TYPE_CODE_ERROR, 0, 0,
               "<data variable, no debug info>", NULL);
   msym_unknown_symbol_type =
-    init_type (TYPE_CODE_INT, 1, 0,
+    init_type (TYPE_CODE_ERROR, 0, 0,
               "<variable (not text or data), no debug info>",
               NULL);
 
Index: gdb/parser-defs.h
===================================================================
RCS file: /cvs/src/src/gdb/parser-defs.h,v
retrieving revision 1.6
diff -u -r1.6 parser-defs.h
--- parser-defs.h       2001/11/15 01:55:59     1.6
+++ parser-defs.h       2002/01/08 22:43:30
@@ -39,6 +39,10 @@
 extern int expout_size;
 extern int expout_ptr;
 
+extern struct type *msym_text_symbol_type;
+extern struct type *msym_data_symbol_type;
+extern struct type *msym_unknown_symbol_type;
+
 /* If this is nonzero, this block is used as the lexical context
    for symbol names.  */
 
Index: gdb/scm-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/scm-lang.c,v
retrieving revision 1.7
diff -u -r1.7 scm-lang.c
--- scm-lang.c  2002/01/04 05:20:08     1.7
+++ scm-lang.c  2002/01/08 22:43:30
@@ -169,7 +169,7 @@
     /* FIXME in this case, we should try lookup_symbol first */
     args[2] = value_from_longest (builtin_type_scm, SCM_EOL);
 
-  func = find_function_in_inferior ("scm_lookup_cstr");
+  func = find_function_in_inferior ("scm_lookup_cstr", builtin_type_voidptrfuncptr);
   val = call_function_by_hand (func, 3, args);
   if (!value_logical_not (val))
     return value_ind (val);
@@ -192,7 +192,7 @@
   write_memory (iaddr, str, len);
   /* FIXME - should find and pass env */
   write_memory (iaddr + len, "", 1);
-  func = find_function_in_inferior ("scm_evstr");
+  func = find_function_in_inferior ("scm_evstr", builtin_type_voidptrfuncptr);
   return call_function_by_hand (func, 1, &addr);
 }
 
Index: gdb/valops.c
===================================================================
RCS file: /cvs/src/src/gdb/valops.c,v
retrieving revision 1.49
diff -u -r1.49 valops.c
--- valops.c    2002/01/08 02:09:31     1.49
+++ valops.c    2002/01/08 22:43:31
@@ -33,6 +33,7 @@
 #include "gdbcmd.h"
 #include "regcache.h"
 #include "cp-abi.h"
+#include "parser-defs.h"
 
 #include <errno.h>
 #include "gdb_string.h"
@@ -89,11 +90,49 @@
 int unwind_on_signal_p = 0;
 

 
+struct cached_value *
+create_cached_function (char *name, struct type *type)
+{
+  struct cached_value cached_value *ptr;
+
+  ptr = (struct cached_value *) xmalloc (sizeof (struct cached_value));
+  ptr->name = xstrdup (name);
+  ptr->type = type;
+  memset (&ptr->val, 0, sizeof (struct value));
+  ptr->generation = (unsigned int) -1;
+
+  return ptr;
+}
+
+struct value *
+lookup_cached_function (struct cached_value *cval)
+{
+  struct value *val = NULL;
+  struct value *next = NULL;
+
+  if (cval->generation != symbol_generation)
+    {
+      val = find_function_in_inferior (cval->name, cval->type);
+      cval->val = *val;
+      cval->val.next = NULL;
+      cval->generation = symbol_generation;
+    }
+
+  val = allocate_value (cval->val.type);
+  next = val->next;
+  *val = cval->val;
+  val->next = next;
+
+  return val;
+}
 
-/* Find the address of function name NAME in the inferior.  */
+/* Find the address of function name NAME in the inferior.  If no type
+   information is available for NAME, use `type' as the type for the
+   resulting value.
+*/
 
 struct value *
-find_function_in_inferior (char *name)
+find_function_in_inferior (char *name, struct type *type)
 {
   register struct symbol *sym;
   sym = lookup_symbol (name, 0, VAR_NAMESPACE, 0, NULL);
@@ -111,20 +150,18 @@
       struct minimal_symbol *msymbol = lookup_minimal_symbol (name, NULL, NULL);
       if (msymbol != NULL)
        {
-         struct type *type;
-         CORE_ADDR maddr;
-         type = lookup_pointer_type (builtin_type_char);
-         type = lookup_function_type (type);
-         type = lookup_pointer_type (type);
-         maddr = SYMBOL_VALUE_ADDRESS (msymbol);
-         return value_from_pointer (type, maddr);
+         if (type != NULL)
+           return value_from_longest (type, (LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
+         else
+           return value_from_longest (lookup_pointer_type (msym_text_symbol_type),
+                                      (LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
        }
       else
        {
          if (!target_has_execution)
            error ("evaluation of this expression requires the target program to be active");
          else
-           error ("evaluation of this expression requires the program to have a function \"%s\".", name);
+           error ("evaluation of this expression requires the program to have a function named \"%s\".", name);
        }
     }
 }
@@ -136,10 +173,14 @@
 value_allocate_space_in_inferior (int len)
 {
   struct value *blocklen;
-  struct value *val = find_function_in_inferior ("malloc");
+  struct value *val;
+  static struct cached_value *fval = NULL;
+  
+  if (fval == NULL) 
+    fval = create_cached_function ("malloc", builtin_type_voidptrfuncptr); 
 
   blocklen = value_from_longest (builtin_type_int, (LONGEST) len);
-  val = call_function_by_hand (val, 1, &blocklen);
+  val = call_function_by_hand (lookup_cached_function (fval), 1, &blocklen);
   if (value_logical_not (val))
     {
       if (!target_has_execution)
@@ -1261,6 +1302,11 @@
 
       value_type = builtin_type_int;
     }
+  else if (code == TYPE_CODE_ERROR)
+    {
+      value_type = builtin_type_error;
+      funaddr = (CORE_ADDR) -1;
+    }
   else
     error ("Invalid data type for function to be called.");
 
@@ -1287,7 +1333,8 @@
    ARGS is modified to contain coerced values. */
 
 static struct value *
-hand_function_call (struct value *function, int nargs, struct value **args)
+hand_function_call (struct value *function,
+                   struct type *expect_type, int nargs, struct value **args)
 {
   register CORE_ADDR sp;
   register int i;
@@ -1334,6 +1381,32 @@
   inf_status = save_inferior_status (1);
   old_chain = make_cleanup_restore_inferior_status (inf_status);
 
+  funaddr = find_function_addr (function, &value_type);
+  CHECK_TYPEDEF (value_type);
+  
+  if ((value_type == NULL) || (value_type->code == TYPE_CODE_ERROR))
+    value_type = expect_type;
+  
+  if ((value_type == NULL) || (value_type->code == TYPE_CODE_ERROR))
+    error ("Unable to call function at 0x%lx: no return type information available.\n"
+           "To call this function anyway, you can cast the return type explicitly\n"
+          "(e.g. 'print (float) fabs (3.0)')",
+           (unsigned long) funaddr);
+
+  CHECK_TYPEDEF (value_type);
+
+  {
+    struct block *b = block_for_pc (funaddr);
+    /* If compiled without -g, assume GCC 2.  */
+    using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b));
+  }
+
+  /* Are we returning a value using a structure return or a normal
+     value return? */
+
+  struct_return = using_struct_return (function, funaddr, value_type,
+                                      using_gcc);
+
   /* PUSH_DUMMY_FRAME is responsible for saving the inferior registers
      (and POP_FRAME for restoring them).  (At least on most machines)
      they are saved on the stack in the inferior.  */
@@ -1354,21 +1427,6 @@
       sp += sizeof_dummy1;
     }
 
-  funaddr = find_function_addr (function, &value_type);
-  CHECK_TYPEDEF (value_type);
-
-  {
-    struct block *b = block_for_pc (funaddr);
-    /* If compiled without -g, assume GCC 2.  */
-    using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b));
-  }
-
-  /* Are we returning a value using a structure return or a normal
-     value return? */
-
-  struct_return = using_struct_return (function, funaddr, value_type,
-                                      using_gcc);
-
   /* Create a call sequence customized for this function
      and the number of arguments for it.  */
   for (i = 0; i < (int) (SIZEOF_CALL_DUMMY_WORDS / sizeof (dummy[0])); i++)
@@ -1786,16 +1844,23 @@
 }
 
 struct value *
-call_function_by_hand (struct value *function, int nargs, struct value **args)
+call_function_by_hand (struct value *function, 
+                      struct tyep *expect_type, int nargs, struct value **args)
 {
   if (CALL_DUMMY_P)
     {
-      return hand_function_call (function, nargs, args);
+      return hand_function_call (function, expect_type, nargs, args);
     }
   else
     {
       error ("Cannot invoke functions on this machine.");
     }
+}
+
+struct value *
+call_function_by_hand (struct value *function, int nargs, struct value **args)
+{
+  call_function_by_hand_expecting_type (function, NULL, nargs, args);
 }
 

 
Index: gdb/value.h
===================================================================
RCS file: /cvs/src/src/gdb/value.h,v
retrieving revision 1.26
diff -u -r1.26 value.h
--- value.h     2002/01/04 23:21:38     1.26
+++ value.h     2002/01/08 22:43:32
@@ -466,7 +466,7 @@
 
 /* C++ */
 
-extern struct value *value_of_this (int complain);
+extern struct value *value_of_local (char *name, int complain);
 
 extern struct value *value_x_binop (struct value *arg1, struct value *arg2,
                                    enum exp_opcode op,
@@ -529,6 +529,9 @@
 extern void print_variable_value (struct symbol * var,
                                  struct frame_info * frame,
                                  struct ui_file *stream);
+extern void
+print_variable_value (struct symbol *var, struct frame_info *frame,
+                     struct ui_file *stream);
 
 extern int check_field (struct value *, const char *);
 
@@ -554,6 +557,11 @@
 extern struct value *call_function_by_hand (struct value *, int,
                                            struct value **);
 
+extern struct value *
+call_function_by_hand_expecting_type (struct value *,
+                                     struct type *, int,
+                                     struct value **, int);
+
 extern int default_coerce_float_to_double (struct type *, struct type *);
 
 extern int standard_coerce_float_to_double (struct type *, struct type *);
@@ -563,13 +571,26 @@
 
 extern void find_rt_vbase_offset (struct type *, struct type *, char *, int,
                                  int *, int *);
+
+extern CORE_ADDR find_function_addr (struct value *, struct type **);
 
-extern struct value *find_function_in_inferior (char *);
+extern struct value *find_function_in_inferior (char *, struct type *);
 
 extern struct value *value_allocate_space_in_inferior (int);
 
 extern CORE_ADDR default_push_arguments (int nargs, struct value ** args,
                                         CORE_ADDR sp, int struct_return,
                                         CORE_ADDR struct_addr);
+struct cached_value
+{
+  char *name;
+  struct type *type;
+  struct value val;
+  unsigned int generation;
+};
+
+extern struct cached_value *create_cached_function (char *, struct type *);
+
+extern struct value *lookup_cached_function (struct cached_value *cval);
 
 #endif /* !defined (VALUE_H) */
Index: gdb/testsuite/gdb.asm/asm-source.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.asm/asm-source.exp,v
retrieving revision 1.16
diff -u -r1.16 asm-source.exp
--- asm-source.exp      2001/12/20 22:12:20     1.16
+++ asm-source.exp      2002/01/08 22:43:32
@@ -215,10 +215,12 @@
        "Make selected stack frame return now\?.*" "y"
 
 # See if we can look at a global variable
-gdb_test "print globalvar" ".* = 11" "look at global variable"
+gdb_test "print globalvar" ".* = (11|<unknown type>)" "look at global variable"
+gdb_test "print (int) globalvar" ".* = 11" "look at global variable"
 
 # See if we can look at a static variable
-gdb_test "print staticvar" ".* = 5" "look at static variable"
+gdb_test "print staticvar" ".* = (5|<unknown type>)" "look at static variable"
+gdb_test "print (int) staticvar" ".* = 5" "look at static variable"
 
 # See if we can look at a static function
 gdb_test "disassem foostatic" ".*<foostatic>:.*End of assembler dump." \
Index: gdb/testsuite/gdb.base/nodebug.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/nodebug.exp,v
retrieving revision 1.2
diff -u -r1.2 nodebug.exp
--- nodebug.exp 2001/03/06 08:21:50     1.2
+++ nodebug.exp 2002/01/08 22:43:36
@@ -77,23 +77,24 @@
     gdb_test "whatis top" \
        "(<(text variable|function), no debug info>|short \\(int\\)|short \\(\\))"
     if {!$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "ptype top" "(short|int) \\((|void|int|<non-float parameter>|<non-float parameter>, <non-float parameter>)\\)"
+    gdb_test "ptype top" "(short|int|<unknown type>) \\((|void|int|<non-float parameter>|<non-float parameter>, <non-float parameter>)\\)"
     
     if {!$gcc_compiled} then { setup_xfail "mips-sgi-irix5*" }
     setup_xfail "mips-sgi-irix6*"
     gdb_test "p middle" \
-       "\{(<(text variable|function), no debug info>|short \\(int\\)|short \\(\\))\} \[0-9a-fx]* <middle(\\(int\\)|)>"
+       "\{(<(text variable|function), no debug info>|<unknown type>|short \\(int\\)|short \\(\\))\} \[0-9a-fx]* <middle(\\(int\\)|)>"
     if {!$gcc_compiled} then { setup_xfail "mips-sgi-irix5*" }
     setup_xfail "mips-sgi-irix6*"
     gdb_test "whatis middle" \
-       "(<(text variable|function), no debug info>|short \\(int\\)|short \\(\\))"
+       "(<(text variable|function), no debug info>|<unknown type>|short \\(int\\)|short \\(\\))"
     setup_xfail "mips-sgi-irix6*"
-    gdb_test "ptype middle" "(short|int) \\((|void|int|<non-float parameter>|<non-float parameter>, <non-float parameter>)\\)"
+    gdb_test "ptype middle" "(short|int|<unknown type>) \\((|void|int|<non-float parameter>|<non-float parameter>, <non-float parameter>)\\)"
     
-    gdb_test "p dataglobal" "= 3"
+    gdb_test "p dataglobal" "(= 3|<unknown type>)"
+    gdb_test "p (int) dataglobal" "= 3"
     gdb_test "whatis dataglobal" \
-       "<(data variable|variable), no debug info>|int"
-    gdb_test "ptype dataglobal" "<(data variable|variable), no debug info>|int"
+       "<(data variable|variable), no debug info>|<unknown type>|int"
+    gdb_test "ptype dataglobal" "<(data variable|variable), no debug info>|<unknown type>|int"
     
     # The only symbol xcoff puts out for statics is for the TOC entry.
     # Possible, but hairy, for gdb to deal.  Right now it doesn't, it
@@ -102,37 +103,40 @@
     setup_xfail "powerpc*-*-aix*"
     if {!$gcc_compiled} then { setup_xfail "hppa*-*-hpux*" }
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "p datalocal" "= 4"
+    gdb_test "p datalocal" "(= 4|<unknown type>)"
+    gdb_test "p (int) datalocal" "4"
     setup_xfail "rs6000*-*-aix*"
     setup_xfail "powerpc*-*-aix*"
     if {!$gcc_compiled} then { setup_xfail "hppa*-*-hpux*" }
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "whatis datalocal" "<(data variable|variable), no debug info>"
+    gdb_test "whatis datalocal" "<(data variable|variable), no debug info>|<unknown type>"
     setup_xfail "rs6000*-*-aix*"
     setup_xfail "powerpc*-*-aix*"
     if {!$gcc_compiled} then { setup_xfail "hppa*-*-hpux*" }
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "ptype datalocal" "<(data variable|variable), no debug info>"
+    gdb_test "ptype datalocal" "<(data variable|variable), no debug info>|<unknown type>"
     
-    gdb_test "p bssglobal" "= 0"
-    gdb_test "whatis bssglobal" "<(data variable|variable), no debug info>|int"
-    gdb_test "ptype bssglobal" "<(data variable|variable), no debug info>|int"
+    gdb_test "p bssglobal" "(= 0|<unknown type>)"
+    gdb_test "p (int) bssglobal" "= 0"
+    gdb_test "whatis bssglobal" "<(data variable|variable), no debug info>|<unknown type>|int"
+    gdb_test "ptype bssglobal" "<(data variable|variable), no debug info>|<unknown type>|int"
     
     setup_xfail "rs6000*-*-aix*"
     setup_xfail "powerpc*-*-aix*"
     if {!$gcc_compiled} then { setup_xfail "hppa*-*-hpux*" }
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "p bsslocal" "= 0"
+    gdb_test "p bsslocal" "(= 0|<unknown type>)"
+    gdb_test "p (int) bsslocal" "= 0"
     setup_xfail "rs6000*-*-aix*"
     setup_xfail "powerpc*-*-aix*"
     if {!$gcc_compiled} then { setup_xfail "hppa*-*-hpux*" }
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "whatis bsslocal" "<(data variable|variable), no debug info>"
+    gdb_test "whatis bsslocal" "<(data variable|variable), no debug info>|<unknown type>"
     setup_xfail "rs6000*-*-aix*"
     setup_xfail "powerpc*-*-aix*"
     if {!$gcc_compiled} then { setup_xfail "hppa*-*-hpux*" }
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
-    gdb_test "ptype bsslocal" "<(data variable|variable), no debug info>"
+    gdb_test "ptype bsslocal" "<(data variable|variable), no debug info>|<unknown type>"
     
     if {$gcc_compiled} then { setup_xfail "mips-sgi-irix6*" }
     gdb_test "backtrace 10" "#0.*inner.*#1.*middle.*#2.*top.*#3.*main.*" \
@@ -167,7 +171,9 @@
            # We need to up this because this can be really slow on some boards.
            # (malloc() is called as part of the test).
            set timeout 60;    
-           gdb_test {p/c array_index("abcdef",2)} " = 99 'c'"
+           gdb_test {p/c (int) array_index("abcdef",2)} " = 99 'c'"
+           gdb_test {p/c array_index("abcdef",2)} \
+               "Unable to call function .* no return type information available.*"
        }
     }



More information about the Gdb-patches mailing list