Example #1
0
static struct value *
gnuv3_get_vtable (struct gdbarch *gdbarch,
		  struct type *container_type, CORE_ADDR container_addr)
{
  struct type *vtable_type = gdbarch_data (gdbarch,
					   vtable_type_gdbarch_data);
  struct type *vtable_pointer_type;
  struct value *vtable_pointer;
  CORE_ADDR vtable_address;

  /* If this type does not have a virtual table, don't read the first
     field.  */
  if (!gnuv3_dynamic_class (check_typedef (container_type)))
    return NULL;

  /* We do not consult the debug information to find the virtual table.
     The ABI specifies that it is always at offset zero in any class,
     and debug information may not represent it.

     We avoid using value_contents on principle, because the object might
     be large.  */

  /* Find the type "pointer to virtual table".  */
  vtable_pointer_type = lookup_pointer_type (vtable_type);

  /* Load it from the start of the class.  */
  vtable_pointer = value_at (vtable_pointer_type, container_addr);
  vtable_address = value_as_address (vtable_pointer);

  /* Correct it to point at the start of the virtual table, rather
     than the address point.  */
  return value_at_lazy (vtable_type,
			vtable_address
			- vtable_address_point_offset (gdbarch));
}
Example #2
0
static void
m2_print_unbounded_array (struct type *type, const gdb_byte *valaddr,
			  int embedded_offset, CORE_ADDR address,
			  struct ui_file *stream, int recurse,
			  const struct value_print_options *options)
{
  CORE_ADDR addr;
  LONGEST len;
  struct value *val;

  type = check_typedef (type);

  addr = unpack_pointer (TYPE_FIELD_TYPE (type, 0),
			 (TYPE_FIELD_BITPOS (type, 0) / 8) +
			 valaddr + embedded_offset);

  val = value_at_lazy (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, 0)),
		       addr);
  len = unpack_field_as_long (type, valaddr + embedded_offset, 1);

  fprintf_filtered (stream, "{");  
  m2_print_array_contents (value_type (val),
			   value_contents_for_printing (val),
			   value_embedded_offset (val), addr, stream,
			   recurse, val, options, len);
  fprintf_filtered (stream, ", HIGH = %d}", (int) len);
}
static struct value *
gnuv3_get_vtable (struct gdbarch *gdbarch, struct value *container)
{
  struct type *vtable_type = gdbarch_data (gdbarch, vtable_type_gdbarch_data);
  struct type *vtable_pointer_type;
  struct value *vtable_pointer;
  CORE_ADDR vtable_pointer_address, vtable_address;

  /* We do not consult the debug information to find the virtual table.
     The ABI specifies that it is always at offset zero in any class,
     and debug information may not represent it.  We won't issue an
     error if there's a class with virtual functions but no virtual table
     pointer, but something's already gone seriously wrong if that
     happens.

     We avoid using value_contents on principle, because the object might
     be large.  */

  /* Find the type "pointer to virtual table".  */
  vtable_pointer_type = lookup_pointer_type (vtable_type);

  /* Load it from the start of the class.  */
  vtable_pointer_address = value_as_address (value_addr (container));
  vtable_pointer = value_at (vtable_pointer_type, vtable_pointer_address);
  vtable_address = value_as_address (vtable_pointer);

  /* Correct it to point at the start of the virtual table, rather
     than the address point.  */
  return value_at_lazy (vtable_type,
			vtable_address - vtable_address_point_offset (gdbarch));
}
Example #4
0
static PyObject *
stpy_convert_to_value (PyObject *self, PyObject *args)
{
  lazy_string_object *self_string = (lazy_string_object *) self;
  struct value *val = NULL;

  if (self_string->address == 0)
    {
      PyErr_SetString (gdbpy_gdb_memory_error,
		       _("Cannot create a value from NULL."));
      return NULL;
    }

  TRY
    {
      struct type *type = type_object_to_type (self_string->type);
      struct type *realtype;

      gdb_assert (type != NULL);
      realtype = check_typedef (type);
      switch (TYPE_CODE (realtype))
	{
	case TYPE_CODE_PTR:
	  /* If a length is specified we need to convert this to an array
	     of the specified size.  */
	  if (self_string->length != -1)
	    {
	      /* PR 20786: There's no way to specify an array of length zero.
		 Record a length of [0,-1] which is how Ada does it.  Anything
		 we do is broken, but this is one possible solution.  */
	      type = lookup_array_range_type (TYPE_TARGET_TYPE (realtype),
					      0, self_string->length - 1);
	      val = value_at_lazy (type, self_string->address);
	    }
	  else
	    val = value_from_pointer (type, self_string->address);
	  break;
	default:
	  val = value_at_lazy (type, self_string->address);
	  break;
	}
    }
  CATCH (except, RETURN_MASK_ALL)
    {
      GDB_PY_HANDLE_EXCEPTION (except);
    }
Example #5
0
static PyObject *
stpy_convert_to_value  (PyObject *self, PyObject *args)
{
  lazy_string_object *self_string = (lazy_string_object *) self;
  struct value *val = NULL;
  volatile struct gdb_exception except;

  if (self_string->address == 0)
    {
      PyErr_SetString (PyExc_MemoryError,
		       _("Cannot create a value from NULL."));
      return NULL;
    }

  TRY_CATCH (except, RETURN_MASK_ALL)
    {
      val = value_at_lazy (self_string->type, self_string->address);
    }
static SCM
gdbscm_lazy_string_to_value (SCM self)
{
    SCM ls_scm = lsscm_get_lazy_string_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
    lazy_string_smob *ls_smob = (lazy_string_smob *) SCM_SMOB_DATA (ls_scm);
    struct value *value = NULL;
    volatile struct gdb_exception except;

    if (ls_smob->address == 0)
    {
        gdbscm_throw (gdbscm_make_out_of_range_error (FUNC_NAME, SCM_ARG1, self,
                      _("cannot create a value from NULL")));
    }

    TRY_CATCH (except, RETURN_MASK_ALL)
    {
        value = value_at_lazy (ls_smob->type, ls_smob->address);
    }
Example #7
0
/* Standard implementation of print_subexp for use in language_defn
   vectors.  */
void
print_subexp_standard (struct expression *exp, int *pos,
		       struct ui_file *stream, enum precedence prec)
{
  unsigned tem;
  const struct op_print *op_print_tab;
  int pc;
  unsigned nargs;
  char *op_str;
  int assign_modify = 0;
  enum exp_opcode opcode;
  enum precedence myprec = PREC_NULL;
  /* Set to 1 for a right-associative operator.  */
  int assoc = 0;
  struct value *val;
  char *tempstr = NULL;

  op_print_tab = exp->language_defn->la_op_print_tab;
  pc = (*pos)++;
  opcode = exp->elts[pc].opcode;
  switch (opcode)
    {
      /* Common ops */

    case OP_SCOPE:
      myprec = PREC_PREFIX;
      assoc = 0;
      fputs_filtered (type_name_no_tag (exp->elts[pc + 1].type), stream);
      fputs_filtered ("::", stream);
      nargs = longest_to_int (exp->elts[pc + 2].longconst);
      (*pos) += 4 + BYTES_TO_EXP_ELEM (nargs + 1);
      fputs_filtered (&exp->elts[pc + 3].string, stream);
      return;

    case OP_LONG:
      (*pos) += 3;
      value_print (value_from_longest (exp->elts[pc + 1].type,
				       exp->elts[pc + 2].longconst),
		   stream, 0, Val_no_prettyprint);
      return;

    case OP_DOUBLE:
      (*pos) += 3;
      value_print (value_from_double (exp->elts[pc + 1].type,
				      exp->elts[pc + 2].doubleconst),
		   stream, 0, Val_no_prettyprint);
      return;

    case OP_VAR_VALUE:
      {
	struct block *b;
	(*pos) += 3;
	b = exp->elts[pc + 1].block;
	if (b != NULL
	    && BLOCK_FUNCTION (b) != NULL
	    && SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)) != NULL)
	  {
	    fputs_filtered (SYMBOL_PRINT_NAME (BLOCK_FUNCTION (b)), stream);
	    fputs_filtered ("::", stream);
	  }
	fputs_filtered (SYMBOL_PRINT_NAME (exp->elts[pc + 2].symbol), stream);
      }
      return;

    case OP_LAST:
      (*pos) += 2;
      fprintf_filtered (stream, "$%d",
			longest_to_int (exp->elts[pc + 1].longconst));
      return;

    case OP_REGISTER:
      {
	int regnum = longest_to_int (exp->elts[pc + 1].longconst);
	const char *name = user_reg_map_regnum_to_name (current_gdbarch,
							regnum);
	(*pos) += 2;
	fprintf_filtered (stream, "$%s", name);
	return;
      }

    case OP_BOOL:
      (*pos) += 2;
      fprintf_filtered (stream, "%s",
			longest_to_int (exp->elts[pc + 1].longconst)
			? "TRUE" : "FALSE");
      return;

    case OP_INTERNALVAR:
      (*pos) += 2;
      fprintf_filtered (stream, "$%s",
			internalvar_name (exp->elts[pc + 1].internalvar));
      return;

    case OP_FUNCALL:
      (*pos) += 2;
      nargs = longest_to_int (exp->elts[pc + 1].longconst);
      print_subexp (exp, pos, stream, PREC_SUFFIX);
      fputs_filtered (" (", stream);
      for (tem = 0; tem < nargs; tem++)
	{
	  if (tem != 0)
	    fputs_filtered (", ", stream);
	  print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
	}
      fputs_filtered (")", stream);
      return;

    case OP_NAME:
    case OP_EXPRSTRING:
      nargs = longest_to_int (exp->elts[pc + 1].longconst);
      (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
      fputs_filtered (&exp->elts[pc + 2].string, stream);
      return;

    case OP_STRING:
      nargs = longest_to_int (exp->elts[pc + 1].longconst);
      (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
      /* LA_PRINT_STRING will print using the current repeat count threshold.
         If necessary, we can temporarily set it to zero, or pass it as an
         additional parameter to LA_PRINT_STRING.  -fnf */
      LA_PRINT_STRING (stream, &exp->elts[pc + 2].string, nargs, 1, 0);
      return;

    case OP_BITSTRING:
      nargs = longest_to_int (exp->elts[pc + 1].longconst);
      (*pos)
	+= 3 + BYTES_TO_EXP_ELEM ((nargs + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT);
      fprintf_unfiltered (stream, "B'<unimplemented>'");
      return;

    case OP_OBJC_NSSTRING:	/* Objective-C Foundation Class NSString constant.  */
      nargs = longest_to_int (exp->elts[pc + 1].longconst);
      (*pos) += 3 + BYTES_TO_EXP_ELEM (nargs + 1);
      fputs_filtered ("@\"", stream);
      LA_PRINT_STRING (stream, &exp->elts[pc + 2].string, nargs, 1, 0);
      fputs_filtered ("\"", stream);
      return;

    case OP_OBJC_MSGCALL:
      {			/* Objective C message (method) call.  */
	char *selector;
	(*pos) += 3;
	nargs = longest_to_int (exp->elts[pc + 2].longconst);
	fprintf_unfiltered (stream, "[");
	print_subexp (exp, pos, stream, PREC_SUFFIX);
	if (0 == target_read_string (exp->elts[pc + 1].longconst,
				     &selector, 1024, NULL))
	  {
	    error (_("bad selector"));
	    return;
	  }
	if (nargs)
	  {
	    char *s, *nextS;
	    s = alloca (strlen (selector) + 1);
	    strcpy (s, selector);
	    for (tem = 0; tem < nargs; tem++)
	      {
		nextS = strchr (s, ':');
		*nextS = '\0';
		fprintf_unfiltered (stream, " %s: ", s);
		s = nextS + 1;
		print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
	      }
	  }
	else
	  {
	    fprintf_unfiltered (stream, " %s", selector);
	  }
	fprintf_unfiltered (stream, "]");
	/* "selector" was malloc'd by target_read_string. Free it.  */
	xfree (selector);
	return;
      }

    case OP_ARRAY:
      (*pos) += 3;
      nargs = longest_to_int (exp->elts[pc + 2].longconst);
      nargs -= longest_to_int (exp->elts[pc + 1].longconst);
      nargs++;
      tem = 0;
      if (exp->elts[pc + 4].opcode == OP_LONG
	  && exp->elts[pc + 5].type == builtin_type_char
	  && exp->language_defn->la_language == language_c)
	{
	  /* Attempt to print C character arrays using string syntax.
	     Walk through the args, picking up one character from each
	     of the OP_LONG expression elements.  If any array element
	     does not match our expection of what we should find for
	     a simple string, revert back to array printing.  Note that
	     the last expression element is an explicit null terminator
	     byte, which doesn't get printed. */
	  tempstr = alloca (nargs);
	  pc += 4;
	  while (tem < nargs)
	    {
	      if (exp->elts[pc].opcode != OP_LONG
		  || exp->elts[pc + 1].type != builtin_type_char)
		{
		  /* Not a simple array of char, use regular array printing. */
		  tem = 0;
		  break;
		}
	      else
		{
		  tempstr[tem++] =
		    longest_to_int (exp->elts[pc + 2].longconst);
		  pc += 4;
		}
	    }
	}
      if (tem > 0)
	{
	  LA_PRINT_STRING (stream, tempstr, nargs - 1, 1, 0);
	  (*pos) = pc;
	}
      else
	{
	  fputs_filtered (" {", stream);
	  for (tem = 0; tem < nargs; tem++)
	    {
	      if (tem != 0)
		{
		  fputs_filtered (", ", stream);
		}
	      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
	    }
	  fputs_filtered ("}", stream);
	}
      return;

    case OP_LABELED:
      tem = longest_to_int (exp->elts[pc + 1].longconst);
      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
      /* Gcc support both these syntaxes.  Unsure which is preferred.  */
#if 1
      fputs_filtered (&exp->elts[pc + 2].string, stream);
      fputs_filtered (": ", stream);
#else
      fputs_filtered (".", stream);
      fputs_filtered (&exp->elts[pc + 2].string, stream);
      fputs_filtered ("=", stream);
#endif
      print_subexp (exp, pos, stream, PREC_SUFFIX);
      return;

    case TERNOP_COND:
      if ((int) prec > (int) PREC_COMMA)
	fputs_filtered ("(", stream);
      /* Print the subexpressions, forcing parentheses
         around any binary operations within them.
         This is more parentheses than are strictly necessary,
         but it looks clearer.  */
      print_subexp (exp, pos, stream, PREC_HYPER);
      fputs_filtered (" ? ", stream);
      print_subexp (exp, pos, stream, PREC_HYPER);
      fputs_filtered (" : ", stream);
      print_subexp (exp, pos, stream, PREC_HYPER);
      if ((int) prec > (int) PREC_COMMA)
	fputs_filtered (")", stream);
      return;

    case TERNOP_SLICE:
    case TERNOP_SLICE_COUNT:
      print_subexp (exp, pos, stream, PREC_SUFFIX);
      fputs_filtered ("(", stream);
      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
      fputs_filtered (opcode == TERNOP_SLICE ? " : " : " UP ", stream);
      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
      fputs_filtered (")", stream);
      return;

    case STRUCTOP_STRUCT:
      tem = longest_to_int (exp->elts[pc + 1].longconst);
      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
      print_subexp (exp, pos, stream, PREC_SUFFIX);
      fputs_filtered (".", stream);
      fputs_filtered (&exp->elts[pc + 2].string, stream);
      return;

      /* Will not occur for Modula-2 */
    case STRUCTOP_PTR:
      tem = longest_to_int (exp->elts[pc + 1].longconst);
      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
      print_subexp (exp, pos, stream, PREC_SUFFIX);
      fputs_filtered ("->", stream);
      fputs_filtered (&exp->elts[pc + 2].string, stream);
      return;

    case BINOP_SUBSCRIPT:
      print_subexp (exp, pos, stream, PREC_SUFFIX);
      fputs_filtered ("[", stream);
      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
      fputs_filtered ("]", stream);
      return;

    case UNOP_POSTINCREMENT:
      print_subexp (exp, pos, stream, PREC_SUFFIX);
      fputs_filtered ("++", stream);
      return;

    case UNOP_POSTDECREMENT:
      print_subexp (exp, pos, stream, PREC_SUFFIX);
      fputs_filtered ("--", stream);
      return;

    case UNOP_CAST:
      (*pos) += 2;
      if ((int) prec > (int) PREC_PREFIX)
	fputs_filtered ("(", stream);
      fputs_filtered ("(", stream);
      type_print (exp->elts[pc + 1].type, "", stream, 0);
      fputs_filtered (") ", stream);
      print_subexp (exp, pos, stream, PREC_PREFIX);
      if ((int) prec > (int) PREC_PREFIX)
	fputs_filtered (")", stream);
      return;

    case UNOP_MEMVAL:
      (*pos) += 2;
      if ((int) prec > (int) PREC_PREFIX)
	fputs_filtered ("(", stream);
      if (TYPE_CODE (exp->elts[pc + 1].type) == TYPE_CODE_FUNC &&
	  exp->elts[pc + 3].opcode == OP_LONG)
	{
	  /* We have a minimal symbol fn, probably.  It's encoded
	     as a UNOP_MEMVAL (function-type) of an OP_LONG (int, address).
	     Swallow the OP_LONG (including both its opcodes); ignore
	     its type; print the value in the type of the MEMVAL.  */
	  (*pos) += 4;
	  val = value_at_lazy (exp->elts[pc + 1].type,
			       (CORE_ADDR) exp->elts[pc + 5].longconst);
	  value_print (val, stream, 0, Val_no_prettyprint);
	}
      else
	{
	  fputs_filtered ("{", stream);
	  type_print (exp->elts[pc + 1].type, "", stream, 0);
	  fputs_filtered ("} ", stream);
	  print_subexp (exp, pos, stream, PREC_PREFIX);
	}
      if ((int) prec > (int) PREC_PREFIX)
	fputs_filtered (")", stream);
      return;

    case BINOP_ASSIGN_MODIFY:
      opcode = exp->elts[pc + 1].opcode;
      (*pos) += 2;
      myprec = PREC_ASSIGN;
      assoc = 1;
      assign_modify = 1;
      op_str = "???";
      for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
	if (op_print_tab[tem].opcode == opcode)
	  {
	    op_str = op_print_tab[tem].string;
	    break;
	  }
      if (op_print_tab[tem].opcode != opcode)
	/* Not found; don't try to keep going because we don't know how
	   to interpret further elements.  */
	error (_("Invalid expression"));
      break;

      /* C++ ops */

    case OP_THIS:
      ++(*pos);
      fputs_filtered ("this", stream);
      return;

      /* Objective-C ops */

    case OP_OBJC_SELF:
      ++(*pos);
      fputs_filtered ("self", stream);	/* The ObjC equivalent of "this".  */
      return;

      /* Modula-2 ops */

    case MULTI_SUBSCRIPT:
      (*pos) += 2;
      nargs = longest_to_int (exp->elts[pc + 1].longconst);
      print_subexp (exp, pos, stream, PREC_SUFFIX);
      fprintf_unfiltered (stream, " [");
      for (tem = 0; tem < nargs; tem++)
	{
	  if (tem != 0)
	    fprintf_unfiltered (stream, ", ");
	  print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
	}
      fprintf_unfiltered (stream, "]");
      return;

    case BINOP_VAL:
      (*pos) += 2;
      fprintf_unfiltered (stream, "VAL(");
      type_print (exp->elts[pc + 1].type, "", stream, 0);
      fprintf_unfiltered (stream, ",");
      print_subexp (exp, pos, stream, PREC_PREFIX);
      fprintf_unfiltered (stream, ")");
      return;

    case BINOP_INCL:
    case BINOP_EXCL:
      error (_("print_subexp:  Not implemented."));

      /* Default ops */

    default:
      op_str = "???";
      for (tem = 0; op_print_tab[tem].opcode != OP_NULL; tem++)
	if (op_print_tab[tem].opcode == opcode)
	  {
	    op_str = op_print_tab[tem].string;
	    myprec = op_print_tab[tem].precedence;
	    assoc = op_print_tab[tem].right_assoc;
	    break;
	  }
      if (op_print_tab[tem].opcode != opcode)
	/* Not found; don't try to keep going because we don't know how
	   to interpret further elements.  For example, this happens
	   if opcode is OP_TYPE.  */
	error (_("Invalid expression"));
    }

  /* Note that PREC_BUILTIN will always emit parentheses. */
  if ((int) myprec < (int) prec)
    fputs_filtered ("(", stream);
  if ((int) opcode > (int) BINOP_END)
    {
      if (assoc)
	{
	  /* Unary postfix operator.  */
	  print_subexp (exp, pos, stream, PREC_SUFFIX);
	  fputs_filtered (op_str, stream);
	}
      else
	{
	  /* Unary prefix operator.  */
	  fputs_filtered (op_str, stream);
	  if (myprec == PREC_BUILTIN_FUNCTION)
	    fputs_filtered ("(", stream);
	  print_subexp (exp, pos, stream, PREC_PREFIX);
	  if (myprec == PREC_BUILTIN_FUNCTION)
	    fputs_filtered (")", stream);
	}
    }
  else
    {
      /* Binary operator.  */
      /* Print left operand.
         If operator is right-associative,
         increment precedence for this operand.  */
      print_subexp (exp, pos, stream,
		    (enum precedence) ((int) myprec + assoc));
      /* Print the operator itself.  */
      if (assign_modify)
	fprintf_filtered (stream, " %s= ", op_str);
      else if (op_str[0] == ',')
	fprintf_filtered (stream, "%s ", op_str);
      else
	fprintf_filtered (stream, " %s ", op_str);
      /* Print right operand.
         If operator is left-associative,
         increment precedence for this operand.  */
      print_subexp (exp, pos, stream,
		    (enum precedence) ((int) myprec + !assoc));
    }

  if ((int) myprec < (int) prec)
    fputs_filtered (")", stream);
}
/* Compute the offset of the baseclass which is
   the INDEXth baseclass of class TYPE,
   for value at VALADDR (in host) at ADDRESS (in target).
   The result is the offset of the baseclass value relative
   to (the address of)(ARG) + OFFSET.

   -1 is returned on error. */
static int
gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr,
			CORE_ADDR address)
{
  struct gdbarch *gdbarch;
  struct type *vtable_type;
  struct type *ptr_type;
  struct value *vtable;
  struct type *vbasetype;
  struct value *offset_val, *vbase_array;
  CORE_ADDR vtable_address;
  long int cur_base_offset, base_offset;
  int vbasetype_vptr_fieldno;

  /* Determine architecture.  */
  gdbarch = get_class_arch (type);
  vtable_type = gdbarch_data (gdbarch, vtable_type_gdbarch_data);
  ptr_type = builtin_type (gdbarch)->builtin_data_ptr;

  /* If it isn't a virtual base, this is easy.  The offset is in the
     type definition.  */
  if (!BASETYPE_VIA_VIRTUAL (type, index))
    return TYPE_BASECLASS_BITPOS (type, index) / 8;

  /* To access a virtual base, we need to use the vbase offset stored in
     our vtable.  Recent GCC versions provide this information.  If it isn't
     available, we could get what we needed from RTTI, or from drawing the
     complete inheritance graph based on the debug info.  Neither is
     worthwhile.  */
  cur_base_offset = TYPE_BASECLASS_BITPOS (type, index) / 8;
  if (cur_base_offset >= - vtable_address_point_offset (gdbarch))
    error (_("Expected a negative vbase offset (old compiler?)"));

  cur_base_offset = cur_base_offset + vtable_address_point_offset (gdbarch);
  if ((- cur_base_offset) % TYPE_LENGTH (ptr_type) != 0)
    error (_("Misaligned vbase offset."));
  cur_base_offset = cur_base_offset / ((int) TYPE_LENGTH (ptr_type));

  /* We're now looking for the cur_base_offset'th entry (negative index)
     in the vcall_and_vbase_offsets array.  We used to cast the object to
     its TYPE_VPTR_BASETYPE, and reference the vtable as TYPE_VPTR_FIELDNO;
     however, that cast can not be done without calling baseclass_offset again
     if the TYPE_VPTR_BASETYPE is a virtual base class, as described in the
     v3 C++ ABI Section 2.4.I.2.b.  Fortunately the ABI guarantees that the
     vtable pointer will be located at the beginning of the object, so we can
     bypass the casting.  Verify that the TYPE_VPTR_FIELDNO is in fact at the
     start of whichever baseclass it resides in, as a sanity measure - iff
     we have debugging information for that baseclass.  */

  vbasetype = check_typedef (TYPE_VPTR_BASETYPE (type));
  vbasetype_vptr_fieldno = get_vptr_fieldno (vbasetype, NULL);

  if (vbasetype_vptr_fieldno >= 0
      && TYPE_FIELD_BITPOS (vbasetype, vbasetype_vptr_fieldno) != 0)
    error (_("Illegal vptr offset in class %s"),
	   TYPE_NAME (vbasetype) ? TYPE_NAME (vbasetype) : "<unknown>");

  vtable_address = value_as_address (value_at_lazy (ptr_type, address));
  vtable
    = value_at_lazy (vtable_type,
		     vtable_address - vtable_address_point_offset (gdbarch));
  offset_val = value_from_longest (builtin_type_int32, cur_base_offset);
  vbase_array = value_field (vtable, vtable_field_vcall_and_vbase_offsets);
  base_offset = value_as_long (value_subscript (vbase_array, offset_val));
  return base_offset;
}
static struct type *
gnuv3_rtti_type (struct value *value,
                 int *full_p, int *top_p, int *using_enc_p)
{
  struct gdbarch *gdbarch;
  struct type *vtable_type;
  struct type *values_type = check_typedef (value_type (value));
  CORE_ADDR vtable_address;
  struct value *vtable;
  struct minimal_symbol *vtable_symbol;
  const char *vtable_symbol_name;
  const char *class_name;
  struct type *run_time_type;
  struct type *base_type;
  LONGEST offset_to_top;
  struct type *values_type_vptr_basetype;
  int values_type_vptr_fieldno;

  /* We only have RTTI for class objects.  */
  if (TYPE_CODE (values_type) != TYPE_CODE_CLASS)
    return NULL;

  /* This routine may be called for Java types that do not have
     a proper objfile.  Just return NULL for those.  */
  if (!TYPE_OBJFILE (values_type)
      || !TYPE_OBJFILE (values_type)->obfd)
    return NULL;

  /* Determine architecture.  */
  gdbarch = get_class_arch (values_type);
  vtable_type = gdbarch_data (gdbarch, vtable_type_gdbarch_data);

  /* If we can't find the virtual table pointer for values_type, we
     can't find the RTTI.  */
  values_type_vptr_fieldno = get_vptr_fieldno (values_type,
					       &values_type_vptr_basetype);
  if (values_type_vptr_fieldno == -1)
    return NULL;

  if (using_enc_p)
    *using_enc_p = 0;

  /* Fetch VALUE's virtual table pointer, and tweak it to point at
     an instance of our imaginary gdb_gnu_v3_abi_vtable structure.  */
  base_type = check_typedef (values_type_vptr_basetype);
  if (values_type != base_type)
    {
      value = value_cast (base_type, value);
      if (using_enc_p)
	*using_enc_p = 1;
    }
  vtable_address
    = value_as_address (value_field (value, values_type_vptr_fieldno));
  vtable
    = value_at_lazy (vtable_type,
		     vtable_address - vtable_address_point_offset (gdbarch));
  
  /* Find the linker symbol for this vtable.  */
  vtable_symbol
    = lookup_minimal_symbol_by_pc (value_address (vtable)
                                   + value_embedded_offset (vtable));
  if (! vtable_symbol)
    return NULL;
  
  /* The symbol's demangled name should be something like "vtable for
     CLASS", where CLASS is the name of the run-time type of VALUE.
     If we didn't like this approach, we could instead look in the
     type_info object itself to get the class name.  But this way
     should work just as well, and doesn't read target memory.  */
  vtable_symbol_name = SYMBOL_DEMANGLED_NAME (vtable_symbol);
  if (vtable_symbol_name == NULL
      || strncmp (vtable_symbol_name, "vtable for ", 11))
    {
      warning (_("can't find linker symbol for virtual table for `%s' value"),
	       TYPE_NAME (values_type));
      if (vtable_symbol_name)
	warning (_("  found `%s' instead"), vtable_symbol_name);
      return NULL;
    }
  class_name = vtable_symbol_name + 11;

  /* Try to look up the class name as a type name.  */
  /* FIXME: chastain/2003-11-26: block=NULL is bogus.  See pr gdb/1465. */
  run_time_type = cp_lookup_rtti_type (class_name, NULL);
  if (run_time_type == NULL)
    return NULL;

  /* Get the offset from VALUE to the top of the complete object.
     NOTE: this is the reverse of the meaning of *TOP_P.  */
  offset_to_top
    = value_as_long (value_field (vtable, vtable_field_offset_to_top));

  if (full_p)
    *full_p = (- offset_to_top == value_embedded_offset (value)
               && (TYPE_LENGTH (value_enclosing_type (value))
                   >= TYPE_LENGTH (run_time_type)));
  if (top_p)
    *top_p = - offset_to_top;

  return run_time_type;
}