[Ada] Better handling of dynamic types in ada_value_primitive_packed_val
[deliverable/binutils-gdb.git] / gdb / ada-lang.c
index d166d1cba0297f578aa07115fbc51c37db99a138..2b2c47c933a9570dbbd18907b0eba3cfcef8660a 100644 (file)
@@ -398,7 +398,7 @@ ada_inferior_data_cleanup (struct inferior *inf, void *arg)
 {
   struct ada_inferior_data *data;
 
-  data = inferior_data (inf, ada_inferior_data);
+  data = (struct ada_inferior_data *) inferior_data (inf, ada_inferior_data);
   if (data != NULL)
     xfree (data);
 }
@@ -416,7 +416,7 @@ get_ada_inferior_data (struct inferior *inf)
 {
   struct ada_inferior_data *data;
 
-  data = inferior_data (inf, ada_inferior_data);
+  data = (struct ada_inferior_data *) inferior_data (inf, ada_inferior_data);
   if (data == NULL)
     {
       data = XCNEW (struct ada_inferior_data);
@@ -459,7 +459,8 @@ get_ada_pspace_data (struct program_space *pspace)
 {
   struct ada_pspace_data *data;
 
-  data = program_space_data (pspace, ada_pspace_data_handle);
+  data = ((struct ada_pspace_data *)
+         program_space_data (pspace, ada_pspace_data_handle));
   if (data == NULL)
     {
       data = XCNEW (struct ada_pspace_data);
@@ -474,7 +475,7 @@ get_ada_pspace_data (struct program_space *pspace)
 static void
 ada_pspace_data_cleanup (struct program_space *pspace, void *data)
 {
-  struct ada_pspace_data *pspace_data = data;
+  struct ada_pspace_data *pspace_data = (struct ada_pspace_data *) data;
 
   if (pspace_data->sym_cache != NULL)
     ada_free_symbol_cache (pspace_data->sym_cache);
@@ -1414,7 +1415,7 @@ ada_decode_symbol (const struct general_symbol_info *arg)
 {
   struct general_symbol_info *gsymbol = (struct general_symbol_info *) arg;
   const char **resultp =
-    &gsymbol->language_specific.mangled_lang.demangled_name;
+    &gsymbol->language_specific.demangled_name;
 
   if (!gsymbol->ada_mangled)
     {
@@ -1424,7 +1425,8 @@ ada_decode_symbol (const struct general_symbol_info *arg)
       gsymbol->ada_mangled = 1;
 
       if (obstack != NULL)
-       *resultp = obstack_copy0 (obstack, decoded, strlen (decoded));
+       *resultp
+         = (const char *) obstack_copy0 (obstack, decoded, strlen (decoded));
       else
         {
          /* Sometimes, we can't find a corresponding objfile, in
@@ -2380,6 +2382,124 @@ has_negatives (struct type *type)
     }
 }
 
+/* With SRC being a buffer containing BIT_SIZE bits of data at BIT_OFFSET,
+   unpack that data into UNPACKED. UNPACKED_LEN is the size in bytes of
+   the unpacked buffer.
+
+   IS_BIG_ENDIAN is nonzero if the data is stored in big endian mode,
+   zero otherwise.
+
+   IS_SIGNED_TYPE is nonzero if the data corresponds to a signed type.
+
+   IS_SCALAR is nonzero if the data corresponds to a signed type.  */
+
+static void
+ada_unpack_from_contents (const gdb_byte *src, int bit_offset, int bit_size,
+                         gdb_byte *unpacked, int unpacked_len,
+                         int is_big_endian, int is_signed_type,
+                         int is_scalar)
+{
+  int src_len = (bit_size + bit_offset + HOST_CHAR_BIT - 1) / 8;
+  int src_idx;                  /* Index into the source area */
+  int src_bytes_left;           /* Number of source bytes left to process.  */
+  int srcBitsLeft;              /* Number of source bits left to move */
+  int unusedLS;                 /* Number of bits in next significant
+                                   byte of source that are unused */
+
+  int unpacked_idx;             /* Index into the unpacked buffer */
+  int unpacked_bytes_left;      /* Number of bytes left to set in unpacked.  */
+
+  unsigned long accum;          /* Staging area for bits being transferred */
+  int accumSize;                /* Number of meaningful bits in accum */
+  unsigned char sign;
+
+  /* Transmit bytes from least to most significant; delta is the direction
+     the indices move.  */
+  int delta = is_big_endian ? -1 : 1;
+
+  srcBitsLeft = bit_size;
+  src_bytes_left = src_len;
+  unpacked_bytes_left = unpacked_len;
+  sign = 0;
+
+  if (is_big_endian)
+    {
+      src_idx = src_len - 1;
+      if (is_signed_type
+         && ((src[0] << bit_offset) & (1 << (HOST_CHAR_BIT - 1))))
+        sign = ~0;
+
+      unusedLS =
+        (HOST_CHAR_BIT - (bit_size + bit_offset) % HOST_CHAR_BIT)
+        % HOST_CHAR_BIT;
+
+      if (is_scalar)
+       {
+          accumSize = 0;
+          unpacked_idx = unpacked_len - 1;
+       }
+      else
+       {
+          /* Non-scalar values must be aligned at a byte boundary...  */
+          accumSize =
+            (HOST_CHAR_BIT - bit_size % HOST_CHAR_BIT) % HOST_CHAR_BIT;
+          /* ... And are placed at the beginning (most-significant) bytes
+             of the target.  */
+          unpacked_idx = (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT - 1;
+          unpacked_bytes_left = unpacked_idx + 1;
+       }
+    }
+  else
+    {
+      int sign_bit_offset = (bit_size + bit_offset - 1) % 8;
+
+      src_idx = unpacked_idx = 0;
+      unusedLS = bit_offset;
+      accumSize = 0;
+
+      if (is_signed_type && (src[src_len - 1] & (1 << sign_bit_offset)))
+        sign = ~0;
+    }
+
+  accum = 0;
+  while (src_bytes_left > 0)
+    {
+      /* Mask for removing bits of the next source byte that are not
+         part of the value.  */
+      unsigned int unusedMSMask =
+        (1 << (srcBitsLeft >= HOST_CHAR_BIT ? HOST_CHAR_BIT : srcBitsLeft)) -
+        1;
+      /* Sign-extend bits for this byte.  */
+      unsigned int signMask = sign & ~unusedMSMask;
+
+      accum |=
+        (((src[src_idx] >> unusedLS) & unusedMSMask) | signMask) << accumSize;
+      accumSize += HOST_CHAR_BIT - unusedLS;
+      if (accumSize >= HOST_CHAR_BIT)
+        {
+          unpacked[unpacked_idx] = accum & ~(~0L << HOST_CHAR_BIT);
+          accumSize -= HOST_CHAR_BIT;
+          accum >>= HOST_CHAR_BIT;
+          unpacked_bytes_left -= 1;
+          unpacked_idx += delta;
+        }
+      srcBitsLeft -= HOST_CHAR_BIT - unusedLS;
+      unusedLS = 0;
+      src_bytes_left -= 1;
+      src_idx += delta;
+    }
+  while (unpacked_bytes_left > 0)
+    {
+      accum |= sign << accumSize;
+      unpacked[unpacked_idx] = accum & ~(~0L << HOST_CHAR_BIT);
+      accumSize -= HOST_CHAR_BIT;
+      if (accumSize < 0)
+       accumSize = 0;
+      accum >>= HOST_CHAR_BIT;
+      unpacked_bytes_left -= 1;
+      unpacked_idx += delta;
+    }
+}
 
 /* Create a new value of type TYPE from the contents of OBJ starting
    at byte OFFSET, and bit offset BIT_OFFSET within that byte,
@@ -2396,51 +2516,69 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr,
                                 struct type *type)
 {
   struct value *v;
-  int src,                      /* Index into the source area */
-    targ,                       /* Index into the target area */
-    srcBitsLeft,                /* Number of source bits left to move */
-    nsrc, ntarg,                /* Number of source and target bytes */
-    unusedLS,                   /* Number of bits in next significant
-                                   byte of source that are unused */
-    accumSize;                  /* Number of meaningful bits in accum */
-  unsigned char *bytes;         /* First byte containing data to unpack */
-  unsigned char *unpacked;
-  unsigned long accum;          /* Staging area for bits being transferred */
-  unsigned char sign;
-  int len = (bit_size + bit_offset + HOST_CHAR_BIT - 1) / 8;
-  /* Transmit bytes from least to most significant; delta is the direction
-     the indices move.  */
-  int delta = gdbarch_bits_big_endian (get_type_arch (type)) ? -1 : 1;
+  gdb_byte *src;                /* First byte containing data to unpack */
+  int src_len = (bit_size + bit_offset + HOST_CHAR_BIT - 1) / 8;
+  gdb_byte *unpacked;
+  int is_scalar;
+  const int is_big_endian = gdbarch_bits_big_endian (get_type_arch (type));
+  gdb_byte *staging = NULL;
+  int staging_len = 0;
+  struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
 
   type = ada_check_typedef (type);
 
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_ARRAY:
+    case TYPE_CODE_UNION:
+    case TYPE_CODE_STRUCT:
+      is_scalar = 0;
+      break;
+    default:
+      is_scalar = 1;
+      break;
+    }
+
+  if (obj == NULL)
+    src = (gdb_byte *) valaddr + offset;
+  else
+    src = (gdb_byte *) value_contents (obj) + offset;
+
+  if (is_dynamic_type (type))
+    {
+      /* The length of TYPE might by dynamic, so we need to resolve
+        TYPE in order to know its actual size, which we then use
+        to create the contents buffer of the value we return.
+        The difficulty is that the data containing our object is
+        packed, and therefore maybe not at a byte boundary.  So, what
+        we do, is unpack the data into a byte-aligned buffer, and then
+        use that buffer as our object's value for resolving the type.  */
+      staging_len = (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+      staging = malloc (staging_len);
+      make_cleanup (xfree, staging);
+
+      ada_unpack_from_contents (src, bit_offset, bit_size,
+                               staging, staging_len,
+                               is_big_endian, has_negatives (type),
+                               is_scalar);
+      type = resolve_dynamic_type (type, staging, 0);
+    }
+
   if (obj == NULL)
     {
       v = allocate_value (type);
-      bytes = (unsigned char *) (valaddr + offset);
+      src = (gdb_byte *) valaddr + offset;
     }
   else if (VALUE_LVAL (obj) == lval_memory && value_lazy (obj))
     {
       v = value_at (type, value_address (obj) + offset);
-      type = value_type (v);
-      if (TYPE_LENGTH (type) * HOST_CHAR_BIT < bit_size)
-       {
-         /* This can happen in the case of an array of dynamic objects,
-            where the size of each element changes from element to element.
-            In that case, we're initially given the array stride, but
-            after resolving the element type, we find that its size is
-            less than this stride.  In that case, adjust bit_size to
-            match TYPE's length, and recompute LEN accordingly.  */
-         bit_size = TYPE_LENGTH (type) * HOST_CHAR_BIT;
-         len = TYPE_LENGTH (type) + (bit_offset + HOST_CHAR_BIT - 1) / 8;
-       }
-      bytes = (unsigned char *) alloca (len);
-      read_memory (value_address (v), bytes, len);
+      src = alloca (src_len);
+      read_memory (value_address (v), src, src_len);
     }
   else
     {
       v = allocate_value (type);
-      bytes = (unsigned char *) value_contents (obj) + offset;
+      src = (gdb_byte *) value_contents (obj) + offset;
     }
 
   if (obj != NULL)
@@ -2463,101 +2601,28 @@ ada_value_primitive_packed_val (struct value *obj, const gdb_byte *valaddr,
     }
   else
     set_value_bitsize (v, bit_size);
-  unpacked = (unsigned char *) value_contents (v);
+  unpacked = (gdb_byte *) value_contents (v);
 
-  srcBitsLeft = bit_size;
-  nsrc = len;
-  ntarg = TYPE_LENGTH (type);
-  sign = 0;
   if (bit_size == 0)
     {
       memset (unpacked, 0, TYPE_LENGTH (type));
+      do_cleanups (old_chain);
       return v;
     }
-  else if (gdbarch_bits_big_endian (get_type_arch (type)))
-    {
-      src = len - 1;
-      if (has_negatives (type)
-          && ((bytes[0] << bit_offset) & (1 << (HOST_CHAR_BIT - 1))))
-        sign = ~0;
-
-      unusedLS =
-        (HOST_CHAR_BIT - (bit_size + bit_offset) % HOST_CHAR_BIT)
-        % HOST_CHAR_BIT;
-
-      switch (TYPE_CODE (type))
-        {
-        case TYPE_CODE_ARRAY:
-        case TYPE_CODE_UNION:
-        case TYPE_CODE_STRUCT:
-          /* Non-scalar values must be aligned at a byte boundary...  */
-          accumSize =
-            (HOST_CHAR_BIT - bit_size % HOST_CHAR_BIT) % HOST_CHAR_BIT;
-          /* ... And are placed at the beginning (most-significant) bytes
-             of the target.  */
-          targ = (bit_size + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT - 1;
-          ntarg = targ + 1;
-          break;
-        default:
-          accumSize = 0;
-          targ = TYPE_LENGTH (type) - 1;
-          break;
-        }
-    }
-  else
-    {
-      int sign_bit_offset = (bit_size + bit_offset - 1) % 8;
-
-      src = targ = 0;
-      unusedLS = bit_offset;
-      accumSize = 0;
 
-      if (has_negatives (type) && (bytes[len - 1] & (1 << sign_bit_offset)))
-        sign = ~0;
-    }
-
-  accum = 0;
-  while (nsrc > 0)
+  if (staging != NULL && staging_len == TYPE_LENGTH (type))
     {
-      /* Mask for removing bits of the next source byte that are not
-         part of the value.  */
-      unsigned int unusedMSMask =
-        (1 << (srcBitsLeft >= HOST_CHAR_BIT ? HOST_CHAR_BIT : srcBitsLeft)) -
-        1;
-      /* Sign-extend bits for this byte.  */
-      unsigned int signMask = sign & ~unusedMSMask;
-
-      accum |=
-        (((bytes[src] >> unusedLS) & unusedMSMask) | signMask) << accumSize;
-      accumSize += HOST_CHAR_BIT - unusedLS;
-      if (accumSize >= HOST_CHAR_BIT)
-        {
-          unpacked[targ] = accum & ~(~0L << HOST_CHAR_BIT);
-          accumSize -= HOST_CHAR_BIT;
-          accum >>= HOST_CHAR_BIT;
-          ntarg -= 1;
-          targ += delta;
-        }
-      srcBitsLeft -= HOST_CHAR_BIT - unusedLS;
-      unusedLS = 0;
-      nsrc -= 1;
-      src += delta;
-    }
-  while (ntarg > 0)
-    {
-      accum |= sign << accumSize;
-      unpacked[targ] = accum & ~(~0L << HOST_CHAR_BIT);
-      accumSize -= HOST_CHAR_BIT;
-      if (accumSize < 0)
-       accumSize = 0;
-      accum >>= HOST_CHAR_BIT;
-      ntarg -= 1;
-      targ += delta;
+      /* Small short-cut: If we've unpacked the data into a buffer
+        of the same size as TYPE's length, then we can reuse that,
+        instead of doing the unpacking again.  */
+      memcpy (unpacked, staging, staging_len);
     }
+  else
+    ada_unpack_from_contents (src, bit_offset, bit_size,
+                             unpacked, TYPE_LENGTH (type),
+                             is_big_endian, has_negatives (type), is_scalar);
 
-  if (is_dynamic_type (value_type (v)))
-    v = value_from_contents_and_address (value_type (v), value_contents (v),
-                                        0);
+  do_cleanups (old_chain);
   return v;
 }
 
@@ -2657,7 +2722,7 @@ ada_value_assign (struct value *toval, struct value *fromval)
       int len = (value_bitpos (toval)
                 + bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
       int from_size;
-      gdb_byte *buffer = alloca (len);
+      gdb_byte *buffer = (gdb_byte *) alloca (len);
       struct value *val;
       CORE_ADDR to_addr = value_address (toval);
 
@@ -2757,14 +2822,27 @@ ada_value_subscript (struct value *arr, int arity, struct value **ind)
 
 /* Assuming ARR is a pointer to a GDB array, the value of the element
    of *ARR at the ARITY indices given in IND.
-   Does not read the entire array into memory.  */
+   Does not read the entire array into memory.
+
+   Note: Unlike what one would expect, this function is used instead of
+   ada_value_subscript for basically all non-packed array types.  The reason
+   for this is that a side effect of doing our own pointer arithmetics instead
+   of relying on value_subscript is that there is no implicit typedef peeling.
+   This is important for arrays of array accesses, where it allows us to
+   preserve the fact that the array's element is an array access, where the
+   access part os encoded in a typedef layer.  */
 
 static struct value *
 ada_value_ptr_subscript (struct value *arr, int arity, struct value **ind)
 {
   int k;
+  struct value *array_ind = ada_value_ind (arr);
   struct type *type
-    = check_typedef (value_enclosing_type (ada_value_ind (arr)));
+    = check_typedef (value_enclosing_type (array_ind));
+
+  if (TYPE_CODE (type) == TYPE_CODE_ARRAY
+      && TYPE_FIELD_BITSIZE (type, 0) > 0)
+    return value_subscript_packed (array_ind, arity, ind);
 
   for (k = 0; k < arity; k += 1)
     {
@@ -4388,7 +4466,7 @@ value_pointer (struct value *value, struct type *type)
 {
   struct gdbarch *gdbarch = get_type_arch (type);
   unsigned len = TYPE_LENGTH (type);
-  gdb_byte *buf = alloca (len);
+  gdb_byte *buf = (gdb_byte *) alloca (len);
   CORE_ADDR addr;
 
   addr = value_address (value);
@@ -4583,7 +4661,8 @@ cache_symbol (const char *name, domain_enum domain, struct symbol *sym,
                                            sizeof (*e));
   e->next = sym_cache->root[h];
   sym_cache->root[h] = e;
-  e->name = copy = obstack_alloc (&sym_cache->cache_space, strlen (name) + 1);
+  e->name = copy
+    = (char *) obstack_alloc (&sym_cache->cache_space, strlen (name) + 1);
   strcpy (copy, name);
   e->sym = sym;
   e->domain = domain;
@@ -4754,7 +4833,7 @@ static struct block_symbol *
 defns_collected (struct obstack *obstackp, int finish)
 {
   if (finish)
-    return obstack_finish (obstackp);
+    return (struct block_symbol *) obstack_finish (obstackp);
   else
     return (struct block_symbol *) obstack_base (obstackp);
 }
@@ -5522,7 +5601,7 @@ add_nonlocal_symbols (struct obstack *obstackp, const char *name,
     {
       ALL_OBJFILES (objfile)
         {
-         char *name1 = alloca (strlen (name) + sizeof ("_ada_"));
+         char *name1 = (char *) alloca (strlen (name) + sizeof ("_ada_"));
          strcpy (name1, "_ada_");
          strcpy (name1 + sizeof ("_ada_") - 1, name);
          data.objfile = objfile;
@@ -5715,7 +5794,7 @@ ada_name_for_lookup (const char *name)
 
   if (name[0] == '<' && name[nlen - 1] == '>')
     {
-      canon = xmalloc (nlen - 1);
+      canon = (char *) xmalloc (nlen - 1);
       memcpy (canon, name + 1, nlen - 2);
       canon[nlen - 2] = '\0';
     }
@@ -6316,19 +6395,19 @@ symbol_completion_add (VEC(char_ptr) **sv,
 
   if (word == orig_text)
     {
-      completion = xmalloc (strlen (match) + 5);
+      completion = (char *) xmalloc (strlen (match) + 5);
       strcpy (completion, match);
     }
   else if (word > orig_text)
     {
       /* Return some portion of sym_name.  */
-      completion = xmalloc (strlen (match) + 5);
+      completion = (char *) xmalloc (strlen (match) + 5);
       strcpy (completion, match + (word - orig_text));
     }
   else
     {
       /* Return some of ORIG_TEXT plus sym_name.  */
-      completion = xmalloc (strlen (match) + (orig_text - word) + 5);
+      completion = (char *) xmalloc (strlen (match) + (orig_text - word) + 5);
       strncpy (completion, word, orig_text - word);
       completion[orig_text - word] = '\0';
       strcat (completion, match);
@@ -6355,7 +6434,7 @@ struct add_partial_datum
 static int
 ada_complete_symbol_matcher (const char *name, void *user_data)
 {
-  struct add_partial_datum *data = user_data;
+  struct add_partial_datum *data = (struct add_partial_datum *) user_data;
   
   return symbol_completion_match (name, data->text, data->text_len,
                                   data->wild_match, data->encoded) != NULL;
@@ -8856,7 +8935,8 @@ ada_to_fixed_type_1 (struct type *type, const gdb_byte *valaddr,
         else if (ada_type_name (fixed_record_type) != NULL)
           {
             const char *name = ada_type_name (fixed_record_type);
-            char *xvz_name = alloca (strlen (name) + 7 /* "___XVZ\0" */);
+            char *xvz_name
+             = (char *) alloca (strlen (name) + 7 /* "___XVZ\0" */);
             int xvz_found = 0;
             LONGEST size;
 
@@ -10629,10 +10709,17 @@ ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
           therefore already coerced to a simple array.  Nothing further
           to do.  */
         ;
-      else if (TYPE_CODE (value_type (argvec[0])) == TYPE_CODE_REF
-               || (TYPE_CODE (value_type (argvec[0])) == TYPE_CODE_ARRAY
-                   && VALUE_LVAL (argvec[0]) == lval_memory))
-        argvec[0] = value_addr (argvec[0]);
+      else if (TYPE_CODE (value_type (argvec[0])) == TYPE_CODE_REF)
+       {
+         /* Make sure we dereference references so that all the code below
+            feels like it's really handling the referenced value.  Wrapping
+            types (for alignment) may be there, so make sure we strip them as
+            well.  */
+         argvec[0] = ada_to_fixed_value (coerce_ref (argvec[0]));
+       }
+      else if (TYPE_CODE (value_type (argvec[0])) == TYPE_CODE_ARRAY
+              && VALUE_LVAL (argvec[0]) == lval_memory)
+       argvec[0] = value_addr (argvec[0]);
 
       type = ada_check_typedef (value_type (argvec[0]));
 
@@ -12668,7 +12755,7 @@ ada_get_next_arg (char **argsp)
 
   /* Make a copy of the current argument and return it.  */
 
-  result = xmalloc (end - args + 1);
+  result = (char *) xmalloc (end - args + 1);
   strncpy (result, args, end - args);
   result[end - args] = '\0';
   
@@ -13108,7 +13195,7 @@ sort_remove_dups_ada_exceptions_list (VEC(ada_exc_info) **exceptions,
 static int
 ada_exc_search_name_matches (const char *search_name, void *user_data)
 {
-  regex_t *preg = user_data;
+  regex_t *preg = (regex_t *) user_data;
 
   if (preg == NULL)
     return 1;
This page took 0.041571 seconds and 4 git commands to generate.