Replacing a bogus file with a semi-bogus one (sharing through devo).
[deliverable/binutils-gdb.git] / gdb / jv-lang.c
index 2e722f8d83914116c457118996718bbada1b1144..c8524462c2e5fb43515b76953030a69f47bcfa36 100644 (file)
@@ -1,5 +1,5 @@
 /* Java language support routines for GDB, the GNU debugger.
-   Copyright 1997 Free Software Foundation, Inc.
+   Copyright 1997, 1998 Free Software Foundation, Inc.
 
 This file is part of GDB.
 
@@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "c-lang.h"
 #include "jv-lang.h"
 #include "gdbcore.h"
+#include <ctype.h>
 
 struct type *java_int_type;
 struct type *java_byte_type;
@@ -43,16 +44,17 @@ struct type *java_float_type;
 struct type *java_double_type;
 struct type *java_void_type;
 
-struct type *java_object_type;
+static void java_emit_char PARAMS ((int c, GDB_FILE *stream, int quoter));
 
 /* This objfile contains symtabs that have been dynamically created
    to record dynamically loaded Java classes and dynamically
    compiled java methods. */
-struct objfile *dynamics_objfile = NULL;
 
-struct type *java_link_class_type PARAMS((struct type*, value_ptr));
+static struct objfile *dynamics_objfile = NULL;
 
-struct objfile *
+static struct type *java_link_class_type PARAMS ((struct type *, value_ptr));
+
+static struct objfile *
 get_dynamics_objfile ()
 {
   if (dynamics_objfile == NULL)
@@ -143,7 +145,7 @@ add_class_symbol (type, addr)
     obstack_alloc (&dynamics_objfile->symbol_obstack, sizeof (struct symbol));
   memset (sym, 0, sizeof (struct symbol));
   SYMBOL_LANGUAGE (sym) = language_java;
-  SYMBOL_NAME (sym) = TYPE_NAME (type);
+  SYMBOL_NAME (sym) = TYPE_TAG_NAME (type);
   SYMBOL_CLASS (sym) = LOC_TYPEDEF;
   /*  SYMBOL_VALUE (sym) = valu;*/
   SYMBOL_TYPE (sym) = type;
@@ -177,7 +179,7 @@ java_lookup_class (name)
   type = alloc_type (objfile);
   TYPE_CODE (type) = TYPE_CODE_STRUCT;
   INIT_CPLUS_SPECIFIC (type);
-  TYPE_NAME (type) = obsavestring (name, strlen(name), &objfile->type_obstack);
+  TYPE_TAG_NAME (type) = obsavestring (name, strlen(name), &objfile->type_obstack);
   TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
   TYPE ? = addr;
   return type;
@@ -197,14 +199,15 @@ get_java_utf8_name (obstack, name)
 {
   char *chrs;
   value_ptr temp = name;
-  int name_length = (int) value_as_long
-    (value_struct_elt (&temp, NULL, "length", NULL, "structure"));
-  temp = name;
-  temp = value_struct_elt (&temp, NULL, "data", NULL, "structure");
+  int name_length;
+  CORE_ADDR data_addr;
+  temp = value_struct_elt (&temp, NULL, "length", NULL, "structure");
+  name_length = (int) value_as_long (temp);
+  data_addr = VALUE_ADDRESS (temp) + VALUE_OFFSET (temp)
+    + TYPE_LENGTH (VALUE_TYPE (temp));
   chrs = obstack_alloc (obstack, name_length+1);
   chrs [name_length] = '\0';
-  read_memory_section (VALUE_ADDRESS (temp) + VALUE_OFFSET (temp),
-                      chrs, name_length, NULL);
+  read_memory_section (data_addr, chrs, name_length, NULL);
   return chrs;
 }
 
@@ -212,7 +215,22 @@ value_ptr
 java_class_from_object (obj_val)
      value_ptr obj_val;
 {
-  value_ptr dtable_val = value_struct_elt (&obj_val, NULL, "dtable", NULL, "structure");
+  /* This is all rather inefficient, since the offsets of dtable and
+     class are fixed.  FIXME */
+  value_ptr dtable_val;
+
+  if (TYPE_CODE (VALUE_TYPE (obj_val)) == TYPE_CODE_PTR
+      && TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (obj_val))) == 0)
+    {
+      struct symbol *sym;
+      sym = lookup_symbol ("Hjava_lang_Object", NULL, STRUCT_NAMESPACE,
+                          (int *) 0, (struct symtab **) NULL);
+      if (sym != NULL)
+       obj_val = value_at (VALUE_TYPE (sym),
+                           value_as_pointer (obj_val), NULL);
+    }
+
+  dtable_val = value_struct_elt (&obj_val, NULL, "dtable", NULL, "structure");
   return value_struct_elt (&dtable_val, NULL, "class", NULL, "structure");
 }
 
@@ -235,7 +253,7 @@ type_from_class (clas)
   struct type *type;
   char *name;
   value_ptr temp;
-  struct objfile *objfile = get_dynamics_objfile();
+  struct objfile *objfile;
   value_ptr utf8_name;
   char *nptr;
   CORE_ADDR addr;
@@ -252,6 +270,7 @@ type_from_class (clas)
     }
   addr = VALUE_ADDRESS (clas) + VALUE_OFFSET (clas);
 
+#if 0
   get_java_class_symtab ();
   bl = BLOCKVECTOR_BLOCK (BLOCKVECTOR (class_symtab), GLOBAL_BLOCK);
   for (i = BLOCK_NSYMS (bl);  --i >= 0; )
@@ -260,7 +279,9 @@ type_from_class (clas)
       if (SYMBOL_VALUE_ADDRESS (sym) == addr)
        return SYMBOL_TYPE (sym);
     }
+#endif
 
+  objfile = get_dynamics_objfile();
   if (java_class_is_primitive (clas))
     {
       value_ptr sig;
@@ -274,6 +295,15 @@ type_from_class (clas)
   temp = clas;
   utf8_name = value_struct_elt (&temp, NULL, "name", NULL, "structure");
   name = get_java_utf8_name (&objfile->type_obstack, utf8_name);
+  for (nptr = name;  *nptr != 0;  nptr++)
+    {
+      if (*nptr == '/')
+       *nptr = '.';
+    }
+
+  type = java_lookup_class (name);
+  if (type != NULL)
+    return type;
 
   type = alloc_type (objfile);
   TYPE_CODE (type) = TYPE_CODE_STRUCT;
@@ -288,14 +318,9 @@ type_from_class (clas)
       VALUE_TYPE (temp) = lookup_pointer_type (VALUE_TYPE (clas));
       TYPE_TARGET_TYPE (type) = type_from_class (temp);
     }
-  for (nptr = name;  *nptr != 0;  nptr++)
-    {
-      if (*nptr == '/')
-       *nptr = '.';
-    }
 
   ALLOCATE_CPLUS_STRUCT_TYPE (type);
-  TYPE_NAME (type) = name;
+  TYPE_TAG_NAME (type) = name;
 
   add_class_symtab_symbol (add_class_symbol (type, addr));
   return java_link_class_type (type, clas);
@@ -310,7 +335,7 @@ java_link_class_type (type, clas)
 {
   value_ptr temp;
   char *unqualified_name;
-  char *name = TYPE_NAME (type);
+  char *name = TYPE_TAG_NAME (type);
   int ninterfaces, nfields, nmethods;
   int type_is_object = 0;
   struct fn_field *fn_fields;
@@ -346,6 +371,7 @@ java_link_class_type (type, clas)
   temp = clas;
   nfields = value_as_long (value_struct_elt (&temp, NULL, "nfields", NULL, "structure"));
   nfields += TYPE_N_BASECLASSES (type);
+  nfields++;  /* Add one for dummy "class" field. */
   TYPE_NFIELDS (type) = nfields;
   TYPE_FIELDS (type) = (struct field *)
     TYPE_ALLOC (type, sizeof (struct field) * nfields);
@@ -376,11 +402,25 @@ java_link_class_type (type, clas)
     }
 
 
-  temp = clas;
-  temp = value_struct_elt (&temp, NULL, "bfsize", NULL, "structure");
-  TYPE_LENGTH (type) = JAVA_OBJECT_SIZE + value_as_long (temp);
+  if (name[0] == '[' && tsuper != NULL)
+    {
+      TYPE_LENGTH (type) = TYPE_LENGTH (tsuper) + 4;  /* size with "length" */
+    }
+  else
+    {
+      temp = clas;
+      temp = value_struct_elt (&temp, NULL, "bfsize", NULL, "structure");
+      TYPE_LENGTH (type) = value_as_long (temp);
+    }
 
   fields = NULL;
+  nfields--;  /* First set up dummy "class" field. */
+  SET_FIELD_PHYSADDR (TYPE_FIELD (type, nfields),
+                     VALUE_ADDRESS (clas) + VALUE_OFFSET (clas));
+  TYPE_FIELD_NAME (type, nfields) = "class";
+  TYPE_FIELD_TYPE (type, nfields) = VALUE_TYPE (clas);
+  SET_TYPE_FIELD_PRIVATE (type, nfields);
+  
   for (i = TYPE_N_BASECLASSES (type);  i < nfields;  i++)
     {
       int accflags;
@@ -403,6 +443,8 @@ java_link_class_type (type, clas)
       temp = field;
       accflags = value_as_long (value_struct_elt (&temp, NULL, "accflags",
                                                  NULL, "structure"));
+      temp = field;
+      temp = value_struct_elt (&temp, NULL, "info", NULL, "structure");
       boffset = value_as_long (value_struct_elt (&temp, NULL, "boffset",
                                                  NULL, "structure"));
       if (accflags & 0x0001) /* public access */
@@ -418,13 +460,9 @@ java_link_class_type (type, clas)
          SET_TYPE_FIELD_PROTECTED (type, i);
        }
       if (accflags & 0x0008)  /* ACC_STATIC */
-       {
-         TYPE_FIELD_BITPOS (type, i) = -1;
-         /* Hack for TYPE_FIELD_STATIC_PHYSNAME to prevent a crash. FIXME. */
-         type->fields[i].bitsize = (long) "???";
-       }
+       SET_FIELD_PHYSADDR(TYPE_FIELD(type, i), boffset);
       else
-       TYPE_FIELD_BITPOS (type, i) = 8 * (JAVA_OBJECT_SIZE + boffset);
+       TYPE_FIELD_BITPOS (type, i) = 8 * boffset;
       if (accflags & 0x8000) /* FIELD_UNRESOLVED_FLAG */
        {
          TYPE_FIELD_TYPE (type, i) = get_java_object_type (); /* FIXME */
@@ -523,7 +561,9 @@ java_link_class_type (type, clas)
   return type;
 }
 
-struct type*
+static struct type *java_object_type;
+
+struct type *
 get_java_object_type ()
 {
   return java_object_type;
@@ -542,7 +582,7 @@ is_object_type (type)
        return 0;
       while (TYPE_N_BASECLASSES (ttype) > 0)
        ttype = TYPE_BASECLASS (ttype, 0);
-      name = TYPE_NAME (ttype);
+      name = TYPE_TAG_NAME (ttype);
       if (name != NULL && strcmp (name, "java.lang.Object") == 0)
        return 1;
       name = TYPE_NFIELDS (ttype) > 0 ? TYPE_FIELD_NAME (ttype, 0) : (char*)0;
@@ -575,6 +615,68 @@ java_primitive_type (signature)
   error ("unknown signature '%c' for primitive type", (char) signature);
 }
 
+/* Return the demangled name of the Java type signature string SIGNATURE,
+   as a freshly allocated copy. */
+
+char *
+java_demangle_type_signature (signature)
+     char *signature;
+{
+  int array = 0;
+  char *result;
+  char *ptr;
+  int i;
+  while (*signature == '[')
+    {
+      array++;
+      signature++;
+    }
+  switch (signature[0])
+    {
+    case 'L':
+      /* Substract 2 for 'L' and ';', but add 1 for final nul. */
+      result = xmalloc (strlen (signature) - 1 + 2 * array);
+      signature++;
+      ptr = result;
+      for ( ; *signature != ';' && *signature != '\0'; signature++)
+       {
+         if (*signature == '/')
+           *ptr++ = '.';
+         else
+           *ptr++ = *signature;
+       }
+      break;
+    default:
+      ptr = TYPE_NAME (java_primitive_type (signature[0]));
+      i = strlen (ptr);
+      result = xmalloc (i + 1 + 2 * array);
+      strcpy (result, ptr);
+      ptr = result + i;
+      break;
+    }
+  while (--array >= 0)
+    {
+      *ptr++ = '[';
+      *ptr++ = ']';
+    }
+  *ptr = '\0';
+  return result;
+}
+
+struct type *
+java_lookup_type (signature)
+     char *signature;
+{
+  switch (signature[0])
+    {
+    case 'L':
+    case '[':
+      error ("java_lookup_type not fully inmplemented");
+    default:
+      return java_primitive_type (signature[0]);
+    }
+}
+
 /* Return the type of TYPE followed by DIMS pairs of [ ].
    If DIMS == 0, TYPE is returned. */
 
@@ -583,9 +685,16 @@ java_array_type (type, dims)
      struct type *type;
      int dims;
 {
-  if (dims == 0)
-    return type;
-  error ("array types not implemented");
+  struct type *range_type;
+
+  while (dims-- > 0)
+    {
+      range_type = create_range_type (NULL, builtin_type_int, 0, 0);
+
+      type = create_array_type (NULL, type, range_type);
+    }
+
+  return type;
 }
 
 /* Create a Java string in the inferior from a (Utf8) literal. */
@@ -598,6 +707,46 @@ java_value_string (ptr, len)
   error ("not implemented - java_value_string"); /* FIXME */
 }
 
+/* Print the character C on STREAM as part of the contents of a literal
+   string whose delimiter is QUOTER.  Note that that format for printing
+   characters and strings is language specific. */
+
+static void
+java_emit_char (c, stream, quoter)
+     int c;
+     GDB_FILE *stream;
+     int quoter;
+{
+  switch (c)
+    {
+    case '\\':
+    case '\'':
+      fprintf_filtered (stream, "\\%c", c);
+      break;
+    case '\b':
+      fputs_filtered ("\\b", stream);
+      break;
+    case '\t':
+      fputs_filtered ("\\t", stream);
+      break;
+    case '\n':
+      fputs_filtered ("\\n", stream);
+      break;
+    case '\f':
+      fputs_filtered ("\\f", stream);
+      break;
+    case '\r':
+      fputs_filtered ("\\r", stream);
+      break;
+    default:
+      if (isprint (c))
+       fputc_filtered (c, stream);
+      else
+       fprintf_filtered (stream, "\\u%.4x", (unsigned int) c);
+      break;
+    }
+}
+
 static value_ptr
 evaluate_subexp_java (expect_type, exp, pos, noside)
      struct type *expect_type;
@@ -607,8 +756,10 @@ evaluate_subexp_java (expect_type, exp, pos, noside)
 {
   int pc = *pos;
   int i;
+  char *name;
   enum exp_opcode op = exp->elts[*pos].opcode;
-  value_ptr arg1;
+  value_ptr arg1, arg2;
+  struct type *type;
   switch (op)
     {
     case UNOP_IND:
@@ -624,6 +775,70 @@ evaluate_subexp_java (expect_type, exp, pos, noside)
       if (noside == EVAL_SKIP)
        goto nosideret;
       return value_ind (arg1);
+
+    case BINOP_SUBSCRIPT:
+      (*pos)++;
+      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      /* If the user attempts to subscript something that is not an
+        array or pointer type (like a plain int variable for example),
+        then report this as an error. */
+      
+      COERCE_REF (arg1);
+      type = check_typedef (VALUE_TYPE (arg1));
+      name = TYPE_NAME (type);
+      if (TYPE_CODE (type) == TYPE_CODE_PTR)
+       {
+         type = check_typedef (TYPE_TARGET_TYPE (type));
+         if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+             && TYPE_TAG_NAME (type) != NULL 
+             && TYPE_TAG_NAME (type)[0] == '[')
+           {
+             CORE_ADDR address;
+             long length, index;
+             struct type *el_type;
+             char buf4[4];
+
+             value_ptr clas = java_class_from_object(arg1);
+             value_ptr temp = clas;
+             /* Get CLASS_ELEMENT_TYPE of the array type. */
+             temp = value_struct_elt (&temp, NULL, "methods",
+                                      NULL, "structure"); 
+             VALUE_TYPE (temp) = VALUE_TYPE (clas);
+             el_type = type_from_class (temp);
+             if (TYPE_CODE (el_type) == TYPE_CODE_STRUCT)
+               el_type = lookup_pointer_type (el_type);
+
+             if (noside == EVAL_AVOID_SIDE_EFFECTS)
+               return value_zero (el_type, VALUE_LVAL (arg1));
+             address = value_as_pointer (arg1);
+             address += JAVA_OBJECT_SIZE;
+             read_memory (address, buf4, 4);
+             length = (long) extract_signed_integer (buf4, 4);
+             index = (long) value_as_long (arg2);
+             if (index >= length || index < 0)
+               error ("array index (%ld) out of bounds (length: %ld)",
+                      index, length);
+             address = (address + 4) + index * TYPE_LENGTH (el_type);
+             return value_at (el_type, address, NULL);
+           }
+       }
+      else if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+       {
+         if (noside == EVAL_AVOID_SIDE_EFFECTS)
+           return value_zero (TYPE_TARGET_TYPE (type), VALUE_LVAL (arg1));
+         else
+           return value_subscript (arg1, arg2);
+       }
+      if (name == NULL)
+       name == TYPE_TAG_NAME (type);
+      if (name)
+       error ("cannot subscript something of type `%s'", name);
+      else
+       error ("cannot subscript requested type");
+
     case OP_STRING:
       (*pos)++;
       i = longest_to_int (exp->elts[pc + 1].longconst);
@@ -631,6 +846,13 @@ evaluate_subexp_java (expect_type, exp, pos, noside)
       if (noside == EVAL_SKIP)
        goto nosideret;
       return java_value_string (&exp->elts[pc + 2].string, i);
+
+    case STRUCTOP_STRUCT:
+      arg1 = evaluate_subexp_standard (expect_type, exp, pos, noside);
+      /* Convert object field (such as TYPE.class) to reference. */
+      if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT)
+       arg1 = value_addr (arg1);
+      return arg1;
     default:
       break;
     }
@@ -711,6 +933,7 @@ const struct language_defn java_language_defn = {
   evaluate_subexp_java,
   c_printchar,                 /* Print a character constant */
   c_printstr,                  /* Function to print string constant */
+  java_emit_char,              /* Function to print a single character */
   java_create_fundamental_type,        /* Create fundamental type in this language */
   java_print_type,             /* Print a type using appropriate syntax */
   java_val_print,              /* Print a value using appropriate syntax */
@@ -720,14 +943,14 @@ const struct language_defn java_language_defn = {
   {"%ld",    "",    "d",  ""}, /* Decimal format info */
   {"0x%lx",  "0x",  "x",  ""}, /* Hex format info */
   java_op_print_tab,           /* expression operators for printing */
-  1,                           /* c-style arrays */
+  0,                           /* not c-style arrays */
   0,                           /* String lower bound */
   &builtin_type_char,          /* Type of string elements */ 
   LANG_MAGIC
 };
 
 void
-_initialize_jave_language ()
+_initialize_java_language ()
 {
 
   java_int_type    = init_type (TYPE_CODE_INT,  4, 0, "int", NULL);
@@ -743,8 +966,9 @@ _initialize_jave_language ()
   add_language (&java_language_defn);
 }
 
-/* Cleanup code that should be urn on every "run".
-   We need some hook to have this actually be called ... FIXME */
+/* Cleanup code that should be run on every "run".
+   We should use make_run_cleanup to have this be called.
+   But will that mess up values in value histry?  FIXME */
 
 void java_rerun_cleanup ()
 {
This page took 0.028169 seconds and 4 git commands to generate.