OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [gdb/] [objc-lang.c] - Diff between revs 834 and 842

Only display areas with differences | Details | Blame | View Log

Rev 834 Rev 842
/* Objective-C language support routines for GDB, the GNU debugger.
/* Objective-C language support routines for GDB, the GNU debugger.
 
 
   Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
   Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
 
 
   Contributed by Apple Computer, Inc.
   Contributed by Apple Computer, Inc.
   Written by Michael Snyder.
   Written by Michael Snyder.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
#include "defs.h"
#include "defs.h"
#include "symtab.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "gdbtypes.h"
#include "expression.h"
#include "expression.h"
#include "parser-defs.h"
#include "parser-defs.h"
#include "language.h"
#include "language.h"
#include "c-lang.h"
#include "c-lang.h"
#include "objc-lang.h"
#include "objc-lang.h"
#include "exceptions.h"
#include "exceptions.h"
#include "complaints.h"
#include "complaints.h"
#include "value.h"
#include "value.h"
#include "symfile.h"
#include "symfile.h"
#include "objfiles.h"
#include "objfiles.h"
#include "gdb_string.h"         /* for strchr */
#include "gdb_string.h"         /* for strchr */
#include "target.h"             /* for target_has_execution */
#include "target.h"             /* for target_has_execution */
#include "gdbcore.h"
#include "gdbcore.h"
#include "gdbcmd.h"
#include "gdbcmd.h"
#include "frame.h"
#include "frame.h"
#include "gdb_regex.h"
#include "gdb_regex.h"
#include "regcache.h"
#include "regcache.h"
#include "block.h"
#include "block.h"
#include "infcall.h"
#include "infcall.h"
#include "valprint.h"
#include "valprint.h"
#include "gdb_assert.h"
#include "gdb_assert.h"
 
 
#include <ctype.h>
#include <ctype.h>
 
 
struct objc_object {
struct objc_object {
  CORE_ADDR isa;
  CORE_ADDR isa;
};
};
 
 
struct objc_class {
struct objc_class {
  CORE_ADDR isa;
  CORE_ADDR isa;
  CORE_ADDR super_class;
  CORE_ADDR super_class;
  CORE_ADDR name;
  CORE_ADDR name;
  long version;
  long version;
  long info;
  long info;
  long instance_size;
  long instance_size;
  CORE_ADDR ivars;
  CORE_ADDR ivars;
  CORE_ADDR methods;
  CORE_ADDR methods;
  CORE_ADDR cache;
  CORE_ADDR cache;
  CORE_ADDR protocols;
  CORE_ADDR protocols;
};
};
 
 
struct objc_super {
struct objc_super {
  CORE_ADDR receiver;
  CORE_ADDR receiver;
  CORE_ADDR class;
  CORE_ADDR class;
};
};
 
 
struct objc_method {
struct objc_method {
  CORE_ADDR name;
  CORE_ADDR name;
  CORE_ADDR types;
  CORE_ADDR types;
  CORE_ADDR imp;
  CORE_ADDR imp;
};
};
 
 
static const struct objfile_data *objc_objfile_data;
static const struct objfile_data *objc_objfile_data;
 
 
/* Lookup a structure type named "struct NAME", visible in lexical
/* Lookup a structure type named "struct NAME", visible in lexical
   block BLOCK.  If NOERR is nonzero, return zero if NAME is not
   block BLOCK.  If NOERR is nonzero, return zero if NAME is not
   suitably defined.  */
   suitably defined.  */
 
 
struct symbol *
struct symbol *
lookup_struct_typedef (char *name, struct block *block, int noerr)
lookup_struct_typedef (char *name, struct block *block, int noerr)
{
{
  struct symbol *sym;
  struct symbol *sym;
 
 
  sym = lookup_symbol (name, block, STRUCT_DOMAIN, 0);
  sym = lookup_symbol (name, block, STRUCT_DOMAIN, 0);
 
 
  if (sym == NULL)
  if (sym == NULL)
    {
    {
      if (noerr)
      if (noerr)
        return 0;
        return 0;
      else
      else
        error (_("No struct type named %s."), name);
        error (_("No struct type named %s."), name);
    }
    }
  if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT)
  if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT)
    {
    {
      if (noerr)
      if (noerr)
        return 0;
        return 0;
      else
      else
        error (_("This context has class, union or enum %s, not a struct."),
        error (_("This context has class, union or enum %s, not a struct."),
               name);
               name);
    }
    }
  return sym;
  return sym;
}
}
 
 
CORE_ADDR
CORE_ADDR
lookup_objc_class (struct gdbarch *gdbarch, char *classname)
lookup_objc_class (struct gdbarch *gdbarch, char *classname)
{
{
  struct type *char_type = builtin_type (gdbarch)->builtin_char;
  struct type *char_type = builtin_type (gdbarch)->builtin_char;
  struct value * function, *classval;
  struct value * function, *classval;
 
 
  if (! target_has_execution)
  if (! target_has_execution)
    {
    {
      /* Can't call into inferior to lookup class.  */
      /* Can't call into inferior to lookup class.  */
      return 0;
      return 0;
    }
    }
 
 
  if (lookup_minimal_symbol("objc_lookUpClass", 0, 0))
  if (lookup_minimal_symbol("objc_lookUpClass", 0, 0))
    function = find_function_in_inferior("objc_lookUpClass", NULL);
    function = find_function_in_inferior("objc_lookUpClass", NULL);
  else if (lookup_minimal_symbol ("objc_lookup_class", 0, 0))
  else if (lookup_minimal_symbol ("objc_lookup_class", 0, 0))
    function = find_function_in_inferior("objc_lookup_class", NULL);
    function = find_function_in_inferior("objc_lookup_class", NULL);
  else
  else
    {
    {
      complaint (&symfile_complaints, _("no way to lookup Objective-C classes"));
      complaint (&symfile_complaints, _("no way to lookup Objective-C classes"));
      return 0;
      return 0;
    }
    }
 
 
  classval = value_string (classname, strlen (classname) + 1, char_type);
  classval = value_string (classname, strlen (classname) + 1, char_type);
  classval = value_coerce_array (classval);
  classval = value_coerce_array (classval);
  return (CORE_ADDR) value_as_long (call_function_by_hand (function,
  return (CORE_ADDR) value_as_long (call_function_by_hand (function,
                                                           1, &classval));
                                                           1, &classval));
}
}
 
 
CORE_ADDR
CORE_ADDR
lookup_child_selector (struct gdbarch *gdbarch, char *selname)
lookup_child_selector (struct gdbarch *gdbarch, char *selname)
{
{
  struct type *char_type = builtin_type (gdbarch)->builtin_char;
  struct type *char_type = builtin_type (gdbarch)->builtin_char;
  struct value * function, *selstring;
  struct value * function, *selstring;
 
 
  if (! target_has_execution)
  if (! target_has_execution)
    {
    {
      /* Can't call into inferior to lookup selector.  */
      /* Can't call into inferior to lookup selector.  */
      return 0;
      return 0;
    }
    }
 
 
  if (lookup_minimal_symbol("sel_getUid", 0, 0))
  if (lookup_minimal_symbol("sel_getUid", 0, 0))
    function = find_function_in_inferior("sel_getUid", NULL);
    function = find_function_in_inferior("sel_getUid", NULL);
  else if (lookup_minimal_symbol ("sel_get_any_uid", 0, 0))
  else if (lookup_minimal_symbol ("sel_get_any_uid", 0, 0))
    function = find_function_in_inferior("sel_get_any_uid", NULL);
    function = find_function_in_inferior("sel_get_any_uid", NULL);
  else
  else
    {
    {
      complaint (&symfile_complaints, _("no way to lookup Objective-C selectors"));
      complaint (&symfile_complaints, _("no way to lookup Objective-C selectors"));
      return 0;
      return 0;
    }
    }
 
 
  selstring = value_coerce_array (value_string (selname,
  selstring = value_coerce_array (value_string (selname,
                                                strlen (selname) + 1, char_type));
                                                strlen (selname) + 1, char_type));
  return value_as_long (call_function_by_hand (function, 1, &selstring));
  return value_as_long (call_function_by_hand (function, 1, &selstring));
}
}
 
 
struct value *
struct value *
value_nsstring (struct gdbarch *gdbarch, char *ptr, int len)
value_nsstring (struct gdbarch *gdbarch, char *ptr, int len)
{
{
  struct type *char_type = builtin_type (gdbarch)->builtin_char;
  struct type *char_type = builtin_type (gdbarch)->builtin_char;
  struct value *stringValue[3];
  struct value *stringValue[3];
  struct value *function, *nsstringValue;
  struct value *function, *nsstringValue;
  struct symbol *sym;
  struct symbol *sym;
  struct type *type;
  struct type *type;
 
 
  if (!target_has_execution)
  if (!target_has_execution)
    return 0;            /* Can't call into inferior to create NSString.  */
    return 0;            /* Can't call into inferior to create NSString.  */
 
 
  stringValue[2] = value_string(ptr, len, char_type);
  stringValue[2] = value_string(ptr, len, char_type);
  stringValue[2] = value_coerce_array(stringValue[2]);
  stringValue[2] = value_coerce_array(stringValue[2]);
  /* _NSNewStringFromCString replaces "istr" after Lantern2A.  */
  /* _NSNewStringFromCString replaces "istr" after Lantern2A.  */
  if (lookup_minimal_symbol("_NSNewStringFromCString", 0, 0))
  if (lookup_minimal_symbol("_NSNewStringFromCString", 0, 0))
    {
    {
      function = find_function_in_inferior("_NSNewStringFromCString", NULL);
      function = find_function_in_inferior("_NSNewStringFromCString", NULL);
      nsstringValue = call_function_by_hand(function, 1, &stringValue[2]);
      nsstringValue = call_function_by_hand(function, 1, &stringValue[2]);
    }
    }
  else if (lookup_minimal_symbol("istr", 0, 0))
  else if (lookup_minimal_symbol("istr", 0, 0))
    {
    {
      function = find_function_in_inferior("istr", NULL);
      function = find_function_in_inferior("istr", NULL);
      nsstringValue = call_function_by_hand(function, 1, &stringValue[2]);
      nsstringValue = call_function_by_hand(function, 1, &stringValue[2]);
    }
    }
  else if (lookup_minimal_symbol("+[NSString stringWithCString:]", 0, 0))
  else if (lookup_minimal_symbol("+[NSString stringWithCString:]", 0, 0))
    {
    {
      function
      function
        = find_function_in_inferior("+[NSString stringWithCString:]", NULL);
        = find_function_in_inferior("+[NSString stringWithCString:]", NULL);
      type = builtin_type (gdbarch)->builtin_long;
      type = builtin_type (gdbarch)->builtin_long;
 
 
      stringValue[0] = value_from_longest
      stringValue[0] = value_from_longest
        (type, lookup_objc_class (gdbarch, "NSString"));
        (type, lookup_objc_class (gdbarch, "NSString"));
      stringValue[1] = value_from_longest
      stringValue[1] = value_from_longest
        (type, lookup_child_selector (gdbarch, "stringWithCString:"));
        (type, lookup_child_selector (gdbarch, "stringWithCString:"));
      nsstringValue = call_function_by_hand(function, 3, &stringValue[0]);
      nsstringValue = call_function_by_hand(function, 3, &stringValue[0]);
    }
    }
  else
  else
    error (_("NSString: internal error -- no way to create new NSString"));
    error (_("NSString: internal error -- no way to create new NSString"));
 
 
  sym = lookup_struct_typedef("NSString", 0, 1);
  sym = lookup_struct_typedef("NSString", 0, 1);
  if (sym == NULL)
  if (sym == NULL)
    sym = lookup_struct_typedef("NXString", 0, 1);
    sym = lookup_struct_typedef("NXString", 0, 1);
  if (sym == NULL)
  if (sym == NULL)
    type = builtin_type (gdbarch)->builtin_data_ptr;
    type = builtin_type (gdbarch)->builtin_data_ptr;
  else
  else
    type = lookup_pointer_type(SYMBOL_TYPE (sym));
    type = lookup_pointer_type(SYMBOL_TYPE (sym));
 
 
  deprecated_set_value_type (nsstringValue, type);
  deprecated_set_value_type (nsstringValue, type);
  return nsstringValue;
  return nsstringValue;
}
}
 
 
/* Objective-C name demangling.  */
/* Objective-C name demangling.  */
 
 
char *
char *
objc_demangle (const char *mangled, int options)
objc_demangle (const char *mangled, int options)
{
{
  char *demangled, *cp;
  char *demangled, *cp;
 
 
  if (mangled[0] == '_' &&
  if (mangled[0] == '_' &&
     (mangled[1] == 'i' || mangled[1] == 'c') &&
     (mangled[1] == 'i' || mangled[1] == 'c') &&
      mangled[2] == '_')
      mangled[2] == '_')
    {
    {
      cp = demangled = xmalloc(strlen(mangled) + 2);
      cp = demangled = xmalloc(strlen(mangled) + 2);
 
 
      if (mangled[1] == 'i')
      if (mangled[1] == 'i')
        *cp++ = '-';            /* for instance method */
        *cp++ = '-';            /* for instance method */
      else
      else
        *cp++ = '+';            /* for class    method */
        *cp++ = '+';            /* for class    method */
 
 
      *cp++ = '[';              /* opening left brace  */
      *cp++ = '[';              /* opening left brace  */
      strcpy(cp, mangled+3);    /* tack on the rest of the mangled name */
      strcpy(cp, mangled+3);    /* tack on the rest of the mangled name */
 
 
      while (*cp && *cp == '_')
      while (*cp && *cp == '_')
        cp++;                   /* skip any initial underbars in class name */
        cp++;                   /* skip any initial underbars in class name */
 
 
      cp = strchr(cp, '_');
      cp = strchr(cp, '_');
      if (!cp)                  /* find first non-initial underbar */
      if (!cp)                  /* find first non-initial underbar */
        {
        {
          xfree(demangled);     /* not mangled name */
          xfree(demangled);     /* not mangled name */
          return NULL;
          return NULL;
        }
        }
      if (cp[1] == '_') {       /* easy case: no category name     */
      if (cp[1] == '_') {       /* easy case: no category name     */
        *cp++ = ' ';            /* replace two '_' with one ' '    */
        *cp++ = ' ';            /* replace two '_' with one ' '    */
        strcpy(cp, mangled + (cp - demangled) + 2);
        strcpy(cp, mangled + (cp - demangled) + 2);
      }
      }
      else {
      else {
        *cp++ = '(';            /* less easy case: category name */
        *cp++ = '(';            /* less easy case: category name */
        cp = strchr(cp, '_');
        cp = strchr(cp, '_');
        if (!cp)
        if (!cp)
          {
          {
            xfree(demangled);   /* not mangled name */
            xfree(demangled);   /* not mangled name */
            return NULL;
            return NULL;
          }
          }
        *cp++ = ')';
        *cp++ = ')';
        *cp++ = ' ';            /* overwriting 1st char of method name...  */
        *cp++ = ' ';            /* overwriting 1st char of method name...  */
        strcpy(cp, mangled + (cp - demangled)); /* get it back */
        strcpy(cp, mangled + (cp - demangled)); /* get it back */
      }
      }
 
 
      while (*cp && *cp == '_')
      while (*cp && *cp == '_')
        cp++;                   /* skip any initial underbars in method name */
        cp++;                   /* skip any initial underbars in method name */
 
 
      for (; *cp; cp++)
      for (; *cp; cp++)
        if (*cp == '_')
        if (*cp == '_')
          *cp = ':';            /* replace remaining '_' with ':' */
          *cp = ':';            /* replace remaining '_' with ':' */
 
 
      *cp++ = ']';              /* closing right brace */
      *cp++ = ']';              /* closing right brace */
      *cp++ = 0;         /* string terminator */
      *cp++ = 0;         /* string terminator */
      return demangled;
      return demangled;
    }
    }
  else
  else
    return NULL;        /* Not an objc mangled name.  */
    return NULL;        /* Not an objc mangled name.  */
}
}
 
 
/* Print the character C on STREAM as part of the contents of a
/* Print the character C on STREAM as part of the contents of a
   literal string whose delimiter is QUOTER.  Note that that format
   literal string whose delimiter is QUOTER.  Note that that format
   for printing characters and strings is language specific.  */
   for printing characters and strings is language specific.  */
 
 
static void
static void
objc_emit_char (int c, struct type *type, struct ui_file *stream, int quoter)
objc_emit_char (int c, struct type *type, struct ui_file *stream, int quoter)
{
{
 
 
  c &= 0xFF;                    /* Avoid sign bit follies.  */
  c &= 0xFF;                    /* Avoid sign bit follies.  */
 
 
  if (PRINT_LITERAL_FORM (c))
  if (PRINT_LITERAL_FORM (c))
    {
    {
      if (c == '\\' || c == quoter)
      if (c == '\\' || c == quoter)
        {
        {
          fputs_filtered ("\\", stream);
          fputs_filtered ("\\", stream);
        }
        }
      fprintf_filtered (stream, "%c", c);
      fprintf_filtered (stream, "%c", c);
    }
    }
  else
  else
    {
    {
      switch (c)
      switch (c)
        {
        {
        case '\n':
        case '\n':
          fputs_filtered ("\\n", stream);
          fputs_filtered ("\\n", stream);
          break;
          break;
        case '\b':
        case '\b':
          fputs_filtered ("\\b", stream);
          fputs_filtered ("\\b", stream);
          break;
          break;
        case '\t':
        case '\t':
          fputs_filtered ("\\t", stream);
          fputs_filtered ("\\t", stream);
          break;
          break;
        case '\f':
        case '\f':
          fputs_filtered ("\\f", stream);
          fputs_filtered ("\\f", stream);
          break;
          break;
        case '\r':
        case '\r':
          fputs_filtered ("\\r", stream);
          fputs_filtered ("\\r", stream);
          break;
          break;
        case '\033':
        case '\033':
          fputs_filtered ("\\e", stream);
          fputs_filtered ("\\e", stream);
          break;
          break;
        case '\007':
        case '\007':
          fputs_filtered ("\\a", stream);
          fputs_filtered ("\\a", stream);
          break;
          break;
        default:
        default:
          fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
          fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
          break;
          break;
        }
        }
    }
    }
}
}
 
 
static void
static void
objc_printchar (int c, struct type *type, struct ui_file *stream)
objc_printchar (int c, struct type *type, struct ui_file *stream)
{
{
  fputs_filtered ("'", stream);
  fputs_filtered ("'", stream);
  objc_emit_char (c, type, stream, '\'');
  objc_emit_char (c, type, stream, '\'');
  fputs_filtered ("'", stream);
  fputs_filtered ("'", stream);
}
}
 
 
/* Print the character string STRING, printing at most LENGTH
/* Print the character string STRING, printing at most LENGTH
   characters.  Printing stops early if the number hits print_max;
   characters.  Printing stops early if the number hits print_max;
   repeat counts are printed as appropriate.  Print ellipses at the
   repeat counts are printed as appropriate.  Print ellipses at the
   end if we had to stop before printing LENGTH characters, or if
   end if we had to stop before printing LENGTH characters, or if
   FORCE_ELLIPSES.  */
   FORCE_ELLIPSES.  */
 
 
static void
static void
objc_printstr (struct ui_file *stream, struct type *type,
objc_printstr (struct ui_file *stream, struct type *type,
               const gdb_byte *string, unsigned int length,
               const gdb_byte *string, unsigned int length,
               const char *encoding, int force_ellipses,
               const char *encoding, int force_ellipses,
               const struct value_print_options *options)
               const struct value_print_options *options)
{
{
  unsigned int i;
  unsigned int i;
  unsigned int things_printed = 0;
  unsigned int things_printed = 0;
  int in_quotes = 0;
  int in_quotes = 0;
  int need_comma = 0;
  int need_comma = 0;
  int width = TYPE_LENGTH (type);
  int width = TYPE_LENGTH (type);
 
 
  /* If the string was not truncated due to `set print elements', and
  /* If the string was not truncated due to `set print elements', and
     the last byte of it is a null, we don't print that, in
     the last byte of it is a null, we don't print that, in
     traditional C style.  */
     traditional C style.  */
  if ((!force_ellipses) && length > 0 && string[length-1] == '\0')
  if ((!force_ellipses) && length > 0 && string[length-1] == '\0')
    length--;
    length--;
 
 
  if (length == 0)
  if (length == 0)
    {
    {
      fputs_filtered ("\"\"", stream);
      fputs_filtered ("\"\"", stream);
      return;
      return;
    }
    }
 
 
  for (i = 0; i < length && things_printed < options->print_max; ++i)
  for (i = 0; i < length && things_printed < options->print_max; ++i)
    {
    {
      /* Position of the character we are examining to see whether it
      /* Position of the character we are examining to see whether it
         is repeated.  */
         is repeated.  */
      unsigned int rep1;
      unsigned int rep1;
      /* Number of repetitions we have detected so far.  */
      /* Number of repetitions we have detected so far.  */
      unsigned int reps;
      unsigned int reps;
 
 
      QUIT;
      QUIT;
 
 
      if (need_comma)
      if (need_comma)
        {
        {
          fputs_filtered (", ", stream);
          fputs_filtered (", ", stream);
          need_comma = 0;
          need_comma = 0;
        }
        }
 
 
      rep1 = i + 1;
      rep1 = i + 1;
      reps = 1;
      reps = 1;
      while (rep1 < length && string[rep1] == string[i])
      while (rep1 < length && string[rep1] == string[i])
        {
        {
          ++rep1;
          ++rep1;
          ++reps;
          ++reps;
        }
        }
 
 
      if (reps > options->repeat_count_threshold)
      if (reps > options->repeat_count_threshold)
        {
        {
          if (in_quotes)
          if (in_quotes)
            {
            {
              if (options->inspect_it)
              if (options->inspect_it)
                fputs_filtered ("\\\", ", stream);
                fputs_filtered ("\\\", ", stream);
              else
              else
                fputs_filtered ("\", ", stream);
                fputs_filtered ("\", ", stream);
              in_quotes = 0;
              in_quotes = 0;
            }
            }
          objc_printchar (string[i], type, stream);
          objc_printchar (string[i], type, stream);
          fprintf_filtered (stream, " <repeats %u times>", reps);
          fprintf_filtered (stream, " <repeats %u times>", reps);
          i = rep1 - 1;
          i = rep1 - 1;
          things_printed += options->repeat_count_threshold;
          things_printed += options->repeat_count_threshold;
          need_comma = 1;
          need_comma = 1;
        }
        }
      else
      else
        {
        {
          if (!in_quotes)
          if (!in_quotes)
            {
            {
              if (options->inspect_it)
              if (options->inspect_it)
                fputs_filtered ("\\\"", stream);
                fputs_filtered ("\\\"", stream);
              else
              else
                fputs_filtered ("\"", stream);
                fputs_filtered ("\"", stream);
              in_quotes = 1;
              in_quotes = 1;
            }
            }
          objc_emit_char (string[i], type, stream, '"');
          objc_emit_char (string[i], type, stream, '"');
          ++things_printed;
          ++things_printed;
        }
        }
    }
    }
 
 
  /* Terminate the quotes if necessary.  */
  /* Terminate the quotes if necessary.  */
  if (in_quotes)
  if (in_quotes)
    {
    {
      if (options->inspect_it)
      if (options->inspect_it)
        fputs_filtered ("\\\"", stream);
        fputs_filtered ("\\\"", stream);
      else
      else
        fputs_filtered ("\"", stream);
        fputs_filtered ("\"", stream);
    }
    }
 
 
  if (force_ellipses || i < length)
  if (force_ellipses || i < length)
    fputs_filtered ("...", stream);
    fputs_filtered ("...", stream);
}
}
 
 
/* Determine if we are currently in the Objective-C dispatch function.
/* Determine if we are currently in the Objective-C dispatch function.
   If so, get the address of the method function that the dispatcher
   If so, get the address of the method function that the dispatcher
   would call and use that as the function to step into instead. Also
   would call and use that as the function to step into instead. Also
   skip over the trampoline for the function (if any).  This is better
   skip over the trampoline for the function (if any).  This is better
   for the user since they are only interested in stepping into the
   for the user since they are only interested in stepping into the
   method function anyway.  */
   method function anyway.  */
static CORE_ADDR
static CORE_ADDR
objc_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
objc_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
{
{
  struct gdbarch *gdbarch = get_frame_arch (frame);
  struct gdbarch *gdbarch = get_frame_arch (frame);
  CORE_ADDR real_stop_pc;
  CORE_ADDR real_stop_pc;
  CORE_ADDR method_stop_pc;
  CORE_ADDR method_stop_pc;
 
 
  real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc);
  real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc);
 
 
  if (real_stop_pc != 0)
  if (real_stop_pc != 0)
    find_objc_msgcall (real_stop_pc, &method_stop_pc);
    find_objc_msgcall (real_stop_pc, &method_stop_pc);
  else
  else
    find_objc_msgcall (stop_pc, &method_stop_pc);
    find_objc_msgcall (stop_pc, &method_stop_pc);
 
 
  if (method_stop_pc)
  if (method_stop_pc)
    {
    {
      real_stop_pc = gdbarch_skip_trampoline_code
      real_stop_pc = gdbarch_skip_trampoline_code
                       (gdbarch, frame, method_stop_pc);
                       (gdbarch, frame, method_stop_pc);
      if (real_stop_pc == 0)
      if (real_stop_pc == 0)
        real_stop_pc = method_stop_pc;
        real_stop_pc = method_stop_pc;
    }
    }
 
 
  return real_stop_pc;
  return real_stop_pc;
}
}
 
 
 
 
/* Table mapping opcodes into strings for printing operators
/* Table mapping opcodes into strings for printing operators
   and precedences of the operators.  */
   and precedences of the operators.  */
 
 
static const struct op_print objc_op_print_tab[] =
static const struct op_print objc_op_print_tab[] =
  {
  {
    {",",  BINOP_COMMA, PREC_COMMA, 0},
    {",",  BINOP_COMMA, PREC_COMMA, 0},
    {"=",  BINOP_ASSIGN, PREC_ASSIGN, 1},
    {"=",  BINOP_ASSIGN, PREC_ASSIGN, 1},
    {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
    {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
    {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
    {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
    {"|",  BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
    {"|",  BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
    {"^",  BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
    {"^",  BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
    {"&",  BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
    {"&",  BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
    {"==", BINOP_EQUAL, PREC_EQUAL, 0},
    {"==", BINOP_EQUAL, PREC_EQUAL, 0},
    {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
    {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
    {"<=", BINOP_LEQ, PREC_ORDER, 0},
    {"<=", BINOP_LEQ, PREC_ORDER, 0},
    {">=", BINOP_GEQ, PREC_ORDER, 0},
    {">=", BINOP_GEQ, PREC_ORDER, 0},
    {">",  BINOP_GTR, PREC_ORDER, 0},
    {">",  BINOP_GTR, PREC_ORDER, 0},
    {"<",  BINOP_LESS, PREC_ORDER, 0},
    {"<",  BINOP_LESS, PREC_ORDER, 0},
    {">>", BINOP_RSH, PREC_SHIFT, 0},
    {">>", BINOP_RSH, PREC_SHIFT, 0},
    {"<<", BINOP_LSH, PREC_SHIFT, 0},
    {"<<", BINOP_LSH, PREC_SHIFT, 0},
    {"+",  BINOP_ADD, PREC_ADD, 0},
    {"+",  BINOP_ADD, PREC_ADD, 0},
    {"-",  BINOP_SUB, PREC_ADD, 0},
    {"-",  BINOP_SUB, PREC_ADD, 0},
    {"*",  BINOP_MUL, PREC_MUL, 0},
    {"*",  BINOP_MUL, PREC_MUL, 0},
    {"/",  BINOP_DIV, PREC_MUL, 0},
    {"/",  BINOP_DIV, PREC_MUL, 0},
    {"%",  BINOP_REM, PREC_MUL, 0},
    {"%",  BINOP_REM, PREC_MUL, 0},
    {"@",  BINOP_REPEAT, PREC_REPEAT, 0},
    {"@",  BINOP_REPEAT, PREC_REPEAT, 0},
    {"-",  UNOP_NEG, PREC_PREFIX, 0},
    {"-",  UNOP_NEG, PREC_PREFIX, 0},
    {"!",  UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
    {"!",  UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
    {"~",  UNOP_COMPLEMENT, PREC_PREFIX, 0},
    {"~",  UNOP_COMPLEMENT, PREC_PREFIX, 0},
    {"*",  UNOP_IND, PREC_PREFIX, 0},
    {"*",  UNOP_IND, PREC_PREFIX, 0},
    {"&",  UNOP_ADDR, PREC_PREFIX, 0},
    {"&",  UNOP_ADDR, PREC_PREFIX, 0},
    {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
    {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
    {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
    {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
    {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
    {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
    {NULL, OP_NULL, PREC_NULL, 0}
    {NULL, OP_NULL, PREC_NULL, 0}
};
};
 
 
const struct language_defn objc_language_defn = {
const struct language_defn objc_language_defn = {
  "objective-c",                /* Language name */
  "objective-c",                /* Language name */
  language_objc,
  language_objc,
  range_check_off,
  range_check_off,
  type_check_off,
  type_check_off,
  case_sensitive_on,
  case_sensitive_on,
  array_row_major,
  array_row_major,
  macro_expansion_c,
  macro_expansion_c,
  &exp_descriptor_standard,
  &exp_descriptor_standard,
  objc_parse,
  objc_parse,
  objc_error,
  objc_error,
  null_post_parser,
  null_post_parser,
  objc_printchar,               /* Print a character constant */
  objc_printchar,               /* Print a character constant */
  objc_printstr,                /* Function to print string constant */
  objc_printstr,                /* Function to print string constant */
  objc_emit_char,
  objc_emit_char,
  c_print_type,                 /* Print a type using appropriate syntax */
  c_print_type,                 /* Print a type using appropriate syntax */
  c_print_typedef,              /* Print a typedef using appropriate syntax */
  c_print_typedef,              /* Print a typedef using appropriate syntax */
  c_val_print,                  /* Print a value using appropriate syntax */
  c_val_print,                  /* Print a value using appropriate syntax */
  c_value_print,                /* Print a top-level value */
  c_value_print,                /* Print a top-level value */
  objc_skip_trampoline,         /* Language specific skip_trampoline */
  objc_skip_trampoline,         /* Language specific skip_trampoline */
  "self",                       /* name_of_this */
  "self",                       /* name_of_this */
  basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
  basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
  basic_lookup_transparent_type,/* lookup_transparent_type */
  basic_lookup_transparent_type,/* lookup_transparent_type */
  objc_demangle,                /* Language specific symbol demangler */
  objc_demangle,                /* Language specific symbol demangler */
  NULL,                         /* Language specific class_name_from_physname */
  NULL,                         /* Language specific class_name_from_physname */
  objc_op_print_tab,            /* Expression operators for printing */
  objc_op_print_tab,            /* Expression operators for printing */
  1,                            /* C-style arrays */
  1,                            /* C-style arrays */
  0,                             /* String lower bound */
  0,                             /* String lower bound */
  default_word_break_characters,
  default_word_break_characters,
  default_make_symbol_completion_list,
  default_make_symbol_completion_list,
  c_language_arch_info,
  c_language_arch_info,
  default_print_array_index,
  default_print_array_index,
  default_pass_by_reference,
  default_pass_by_reference,
  default_get_string,
  default_get_string,
  LANG_MAGIC
  LANG_MAGIC
};
};
 
 
/*
/*
 * ObjC:
 * ObjC:
 * Following functions help construct Objective-C message calls
 * Following functions help construct Objective-C message calls
 */
 */
 
 
struct selname          /* For parsing Objective-C.  */
struct selname          /* For parsing Objective-C.  */
  {
  {
    struct selname *next;
    struct selname *next;
    char *msglist_sel;
    char *msglist_sel;
    int msglist_len;
    int msglist_len;
  };
  };
 
 
static int msglist_len;
static int msglist_len;
static struct selname *selname_chain;
static struct selname *selname_chain;
static char *msglist_sel;
static char *msglist_sel;
 
 
void
void
start_msglist(void)
start_msglist(void)
{
{
  struct selname *new =
  struct selname *new =
    (struct selname *) xmalloc (sizeof (struct selname));
    (struct selname *) xmalloc (sizeof (struct selname));
 
 
  new->next = selname_chain;
  new->next = selname_chain;
  new->msglist_len = msglist_len;
  new->msglist_len = msglist_len;
  new->msglist_sel = msglist_sel;
  new->msglist_sel = msglist_sel;
  msglist_len = 0;
  msglist_len = 0;
  msglist_sel = (char *)xmalloc(1);
  msglist_sel = (char *)xmalloc(1);
  *msglist_sel = 0;
  *msglist_sel = 0;
  selname_chain = new;
  selname_chain = new;
}
}
 
 
void
void
add_msglist(struct stoken *str, int addcolon)
add_msglist(struct stoken *str, int addcolon)
{
{
  char *s, *p;
  char *s, *p;
  int len, plen;
  int len, plen;
 
 
  if (str == 0) {                /* Unnamed arg, or...  */
  if (str == 0) {                /* Unnamed arg, or...  */
    if (addcolon == 0) { /* variable number of args.  */
    if (addcolon == 0) { /* variable number of args.  */
      msglist_len++;
      msglist_len++;
      return;
      return;
    }
    }
    p = "";
    p = "";
    plen = 0;
    plen = 0;
  } else {
  } else {
    p = str->ptr;
    p = str->ptr;
    plen = str->length;
    plen = str->length;
  }
  }
  len = plen + strlen(msglist_sel) + 2;
  len = plen + strlen(msglist_sel) + 2;
  s = (char *)xmalloc(len);
  s = (char *)xmalloc(len);
  strcpy(s, msglist_sel);
  strcpy(s, msglist_sel);
  strncat(s, p, plen);
  strncat(s, p, plen);
  xfree(msglist_sel);
  xfree(msglist_sel);
  msglist_sel = s;
  msglist_sel = s;
  if (addcolon) {
  if (addcolon) {
    s[len-2] = ':';
    s[len-2] = ':';
    s[len-1] = 0;
    s[len-1] = 0;
    msglist_len++;
    msglist_len++;
  } else
  } else
    s[len-2] = '\0';
    s[len-2] = '\0';
}
}
 
 
int
int
end_msglist(void)
end_msglist(void)
{
{
  int val = msglist_len;
  int val = msglist_len;
  struct selname *sel = selname_chain;
  struct selname *sel = selname_chain;
  char *p = msglist_sel;
  char *p = msglist_sel;
  CORE_ADDR selid;
  CORE_ADDR selid;
 
 
  selname_chain = sel->next;
  selname_chain = sel->next;
  msglist_len = sel->msglist_len;
  msglist_len = sel->msglist_len;
  msglist_sel = sel->msglist_sel;
  msglist_sel = sel->msglist_sel;
  selid = lookup_child_selector (parse_gdbarch, p);
  selid = lookup_child_selector (parse_gdbarch, p);
  if (!selid)
  if (!selid)
    error (_("Can't find selector \"%s\""), p);
    error (_("Can't find selector \"%s\""), p);
  write_exp_elt_longcst (selid);
  write_exp_elt_longcst (selid);
  xfree(p);
  xfree(p);
  write_exp_elt_longcst (val);  /* Number of args */
  write_exp_elt_longcst (val);  /* Number of args */
  xfree(sel);
  xfree(sel);
 
 
  return val;
  return val;
}
}
 
 
/*
/*
 * Function: specialcmp (char *a, char *b)
 * Function: specialcmp (char *a, char *b)
 *
 *
 * Special strcmp: treats ']' and ' ' as end-of-string.
 * Special strcmp: treats ']' and ' ' as end-of-string.
 * Used for qsorting lists of objc methods (either by class or selector).
 * Used for qsorting lists of objc methods (either by class or selector).
 */
 */
 
 
static int
static int
specialcmp (char *a, char *b)
specialcmp (char *a, char *b)
{
{
  while (*a && *a != ' ' && *a != ']' && *b && *b != ' ' && *b != ']')
  while (*a && *a != ' ' && *a != ']' && *b && *b != ' ' && *b != ']')
    {
    {
      if (*a != *b)
      if (*a != *b)
        return *a - *b;
        return *a - *b;
      a++, b++;
      a++, b++;
    }
    }
  if (*a && *a != ' ' && *a != ']')
  if (*a && *a != ' ' && *a != ']')
    return  1;          /* a is longer therefore greater */
    return  1;          /* a is longer therefore greater */
  if (*b && *b != ' ' && *b != ']')
  if (*b && *b != ' ' && *b != ']')
    return -1;          /* a is shorter therefore lesser */
    return -1;          /* a is shorter therefore lesser */
  return    0;           /* a and b are identical */
  return    0;           /* a and b are identical */
}
}
 
 
/*
/*
 * Function: compare_selectors (const void *, const void *)
 * Function: compare_selectors (const void *, const void *)
 *
 *
 * Comparison function for use with qsort.  Arguments are symbols or
 * Comparison function for use with qsort.  Arguments are symbols or
 * msymbols Compares selector part of objc method name alphabetically.
 * msymbols Compares selector part of objc method name alphabetically.
 */
 */
 
 
static int
static int
compare_selectors (const void *a, const void *b)
compare_selectors (const void *a, const void *b)
{
{
  char *aname, *bname;
  char *aname, *bname;
 
 
  aname = SYMBOL_PRINT_NAME (*(struct symbol **) a);
  aname = SYMBOL_PRINT_NAME (*(struct symbol **) a);
  bname = SYMBOL_PRINT_NAME (*(struct symbol **) b);
  bname = SYMBOL_PRINT_NAME (*(struct symbol **) b);
  if (aname == NULL || bname == NULL)
  if (aname == NULL || bname == NULL)
    error (_("internal: compare_selectors(1)"));
    error (_("internal: compare_selectors(1)"));
 
 
  aname = strchr(aname, ' ');
  aname = strchr(aname, ' ');
  bname = strchr(bname, ' ');
  bname = strchr(bname, ' ');
  if (aname == NULL || bname == NULL)
  if (aname == NULL || bname == NULL)
    error (_("internal: compare_selectors(2)"));
    error (_("internal: compare_selectors(2)"));
 
 
  return specialcmp (aname+1, bname+1);
  return specialcmp (aname+1, bname+1);
}
}
 
 
/*
/*
 * Function: selectors_info (regexp, from_tty)
 * Function: selectors_info (regexp, from_tty)
 *
 *
 * Implements the "Info selectors" command.  Takes an optional regexp
 * Implements the "Info selectors" command.  Takes an optional regexp
 * arg.  Lists all objective c selectors that match the regexp.  Works
 * arg.  Lists all objective c selectors that match the regexp.  Works
 * by grepping thru all symbols for objective c methods.  Output list
 * by grepping thru all symbols for objective c methods.  Output list
 * is sorted and uniqued.
 * is sorted and uniqued.
 */
 */
 
 
static void
static void
selectors_info (char *regexp, int from_tty)
selectors_info (char *regexp, int from_tty)
{
{
  struct objfile        *objfile;
  struct objfile        *objfile;
  struct minimal_symbol *msymbol;
  struct minimal_symbol *msymbol;
  char                  *name;
  char                  *name;
  char                  *val;
  char                  *val;
  int                    matches = 0;
  int                    matches = 0;
  int                    maxlen  = 0;
  int                    maxlen  = 0;
  int                    ix;
  int                    ix;
  char                   myregexp[2048];
  char                   myregexp[2048];
  char                   asel[256];
  char                   asel[256];
  struct symbol        **sym_arr;
  struct symbol        **sym_arr;
  int                    plusminus = 0;
  int                    plusminus = 0;
 
 
  if (regexp == NULL)
  if (regexp == NULL)
    strcpy(myregexp, ".*]");    /* Null input, match all objc methods.  */
    strcpy(myregexp, ".*]");    /* Null input, match all objc methods.  */
  else
  else
    {
    {
      if (*regexp == '+' || *regexp == '-')
      if (*regexp == '+' || *regexp == '-')
        { /* User wants only class methods or only instance methods.  */
        { /* User wants only class methods or only instance methods.  */
          plusminus = *regexp++;
          plusminus = *regexp++;
          while (*regexp == ' ' || *regexp == '\t')
          while (*regexp == ' ' || *regexp == '\t')
            regexp++;
            regexp++;
        }
        }
      if (*regexp == '\0')
      if (*regexp == '\0')
        strcpy(myregexp, ".*]");
        strcpy(myregexp, ".*]");
      else
      else
        {
        {
          strcpy(myregexp, regexp);
          strcpy(myregexp, regexp);
          if (myregexp[strlen(myregexp) - 1] == '$') /* end of selector */
          if (myregexp[strlen(myregexp) - 1] == '$') /* end of selector */
            myregexp[strlen(myregexp) - 1] = ']';    /* end of method name */
            myregexp[strlen(myregexp) - 1] = ']';    /* end of method name */
          else
          else
            strcat(myregexp, ".*]");
            strcat(myregexp, ".*]");
        }
        }
    }
    }
 
 
  if (regexp != NULL)
  if (regexp != NULL)
    {
    {
      val = re_comp (myregexp);
      val = re_comp (myregexp);
      if (val != 0)
      if (val != 0)
        error (_("Invalid regexp (%s): %s"), val, regexp);
        error (_("Invalid regexp (%s): %s"), val, regexp);
    }
    }
 
 
  /* First time thru is JUST to get max length and count.  */
  /* First time thru is JUST to get max length and count.  */
  ALL_MSYMBOLS (objfile, msymbol)
  ALL_MSYMBOLS (objfile, msymbol)
    {
    {
      QUIT;
      QUIT;
      name = SYMBOL_NATURAL_NAME (msymbol);
      name = SYMBOL_NATURAL_NAME (msymbol);
      if (name &&
      if (name &&
         (name[0] == '-' || name[0] == '+') &&
         (name[0] == '-' || name[0] == '+') &&
          name[1] == '[')               /* Got a method name.  */
          name[1] == '[')               /* Got a method name.  */
        {
        {
          /* Filter for class/instance methods.  */
          /* Filter for class/instance methods.  */
          if (plusminus && name[0] != plusminus)
          if (plusminus && name[0] != plusminus)
            continue;
            continue;
          /* Find selector part.  */
          /* Find selector part.  */
          name = (char *) strchr(name+2, ' ');
          name = (char *) strchr(name+2, ' ');
          if (regexp == NULL || re_exec(++name) != 0)
          if (regexp == NULL || re_exec(++name) != 0)
            {
            {
              char *mystart = name;
              char *mystart = name;
              char *myend   = (char *) strchr(mystart, ']');
              char *myend   = (char *) strchr(mystart, ']');
 
 
              if (myend && (myend - mystart > maxlen))
              if (myend && (myend - mystart > maxlen))
                maxlen = myend - mystart;       /* Get longest selector.  */
                maxlen = myend - mystart;       /* Get longest selector.  */
              matches++;
              matches++;
            }
            }
        }
        }
    }
    }
  if (matches)
  if (matches)
    {
    {
      printf_filtered (_("Selectors matching \"%s\":\n\n"),
      printf_filtered (_("Selectors matching \"%s\":\n\n"),
                       regexp ? regexp : "*");
                       regexp ? regexp : "*");
 
 
      sym_arr = alloca (matches * sizeof (struct symbol *));
      sym_arr = alloca (matches * sizeof (struct symbol *));
      matches = 0;
      matches = 0;
      ALL_MSYMBOLS (objfile, msymbol)
      ALL_MSYMBOLS (objfile, msymbol)
        {
        {
          QUIT;
          QUIT;
          name = SYMBOL_NATURAL_NAME (msymbol);
          name = SYMBOL_NATURAL_NAME (msymbol);
          if (name &&
          if (name &&
             (name[0] == '-' || name[0] == '+') &&
             (name[0] == '-' || name[0] == '+') &&
              name[1] == '[')           /* Got a method name.  */
              name[1] == '[')           /* Got a method name.  */
            {
            {
              /* Filter for class/instance methods.  */
              /* Filter for class/instance methods.  */
              if (plusminus && name[0] != plusminus)
              if (plusminus && name[0] != plusminus)
                continue;
                continue;
              /* Find selector part.  */
              /* Find selector part.  */
              name = (char *) strchr(name+2, ' ');
              name = (char *) strchr(name+2, ' ');
              if (regexp == NULL || re_exec(++name) != 0)
              if (regexp == NULL || re_exec(++name) != 0)
                sym_arr[matches++] = (struct symbol *) msymbol;
                sym_arr[matches++] = (struct symbol *) msymbol;
            }
            }
        }
        }
 
 
      qsort (sym_arr, matches, sizeof (struct minimal_symbol *),
      qsort (sym_arr, matches, sizeof (struct minimal_symbol *),
             compare_selectors);
             compare_selectors);
      /* Prevent compare on first iteration.  */
      /* Prevent compare on first iteration.  */
      asel[0] = 0;
      asel[0] = 0;
      for (ix = 0; ix < matches; ix++)   /* Now do the output.  */
      for (ix = 0; ix < matches; ix++)   /* Now do the output.  */
        {
        {
          char *p = asel;
          char *p = asel;
 
 
          QUIT;
          QUIT;
          name = SYMBOL_NATURAL_NAME (sym_arr[ix]);
          name = SYMBOL_NATURAL_NAME (sym_arr[ix]);
          name = strchr (name, ' ') + 1;
          name = strchr (name, ' ') + 1;
          if (p[0] && specialcmp(name, p) == 0)
          if (p[0] && specialcmp(name, p) == 0)
            continue;           /* Seen this one already (not unique).  */
            continue;           /* Seen this one already (not unique).  */
 
 
          /* Copy selector part.  */
          /* Copy selector part.  */
          while (*name && *name != ']')
          while (*name && *name != ']')
            *p++ = *name++;
            *p++ = *name++;
          *p++ = '\0';
          *p++ = '\0';
          /* Print in columns.  */
          /* Print in columns.  */
          puts_filtered_tabular(asel, maxlen + 1, 0);
          puts_filtered_tabular(asel, maxlen + 1, 0);
        }
        }
      begin_line();
      begin_line();
    }
    }
  else
  else
    printf_filtered (_("No selectors matching \"%s\"\n"), regexp ? regexp : "*");
    printf_filtered (_("No selectors matching \"%s\"\n"), regexp ? regexp : "*");
}
}
 
 
/*
/*
 * Function: compare_classes (const void *, const void *)
 * Function: compare_classes (const void *, const void *)
 *
 *
 * Comparison function for use with qsort.  Arguments are symbols or
 * Comparison function for use with qsort.  Arguments are symbols or
 * msymbols Compares class part of objc method name alphabetically.
 * msymbols Compares class part of objc method name alphabetically.
 */
 */
 
 
static int
static int
compare_classes (const void *a, const void *b)
compare_classes (const void *a, const void *b)
{
{
  char *aname, *bname;
  char *aname, *bname;
 
 
  aname = SYMBOL_PRINT_NAME (*(struct symbol **) a);
  aname = SYMBOL_PRINT_NAME (*(struct symbol **) a);
  bname = SYMBOL_PRINT_NAME (*(struct symbol **) b);
  bname = SYMBOL_PRINT_NAME (*(struct symbol **) b);
  if (aname == NULL || bname == NULL)
  if (aname == NULL || bname == NULL)
    error (_("internal: compare_classes(1)"));
    error (_("internal: compare_classes(1)"));
 
 
  return specialcmp (aname+1, bname+1);
  return specialcmp (aname+1, bname+1);
}
}
 
 
/*
/*
 * Function: classes_info(regexp, from_tty)
 * Function: classes_info(regexp, from_tty)
 *
 *
 * Implements the "info classes" command for objective c classes.
 * Implements the "info classes" command for objective c classes.
 * Lists all objective c classes that match the optional regexp.
 * Lists all objective c classes that match the optional regexp.
 * Works by grepping thru the list of objective c methods.  List will
 * Works by grepping thru the list of objective c methods.  List will
 * be sorted and uniqued (since one class may have many methods).
 * be sorted and uniqued (since one class may have many methods).
 * BUGS: will not list a class that has no methods.
 * BUGS: will not list a class that has no methods.
 */
 */
 
 
static void
static void
classes_info (char *regexp, int from_tty)
classes_info (char *regexp, int from_tty)
{
{
  struct objfile        *objfile;
  struct objfile        *objfile;
  struct minimal_symbol *msymbol;
  struct minimal_symbol *msymbol;
  char                  *name;
  char                  *name;
  char                  *val;
  char                  *val;
  int                    matches = 0;
  int                    matches = 0;
  int                    maxlen  = 0;
  int                    maxlen  = 0;
  int                    ix;
  int                    ix;
  char                   myregexp[2048];
  char                   myregexp[2048];
  char                   aclass[256];
  char                   aclass[256];
  struct symbol        **sym_arr;
  struct symbol        **sym_arr;
 
 
  if (regexp == NULL)
  if (regexp == NULL)
    strcpy(myregexp, ".* ");    /* Null input: match all objc classes.  */
    strcpy(myregexp, ".* ");    /* Null input: match all objc classes.  */
  else
  else
    {
    {
      strcpy(myregexp, regexp);
      strcpy(myregexp, regexp);
      if (myregexp[strlen(myregexp) - 1] == '$')
      if (myregexp[strlen(myregexp) - 1] == '$')
        /* In the method name, the end of the class name is marked by ' '.  */
        /* In the method name, the end of the class name is marked by ' '.  */
        myregexp[strlen(myregexp) - 1] = ' ';
        myregexp[strlen(myregexp) - 1] = ' ';
      else
      else
        strcat(myregexp, ".* ");
        strcat(myregexp, ".* ");
    }
    }
 
 
  if (regexp != NULL)
  if (regexp != NULL)
    {
    {
      val = re_comp (myregexp);
      val = re_comp (myregexp);
      if (val != 0)
      if (val != 0)
        error (_("Invalid regexp (%s): %s"), val, regexp);
        error (_("Invalid regexp (%s): %s"), val, regexp);
    }
    }
 
 
  /* First time thru is JUST to get max length and count.  */
  /* First time thru is JUST to get max length and count.  */
  ALL_MSYMBOLS (objfile, msymbol)
  ALL_MSYMBOLS (objfile, msymbol)
    {
    {
      QUIT;
      QUIT;
      name = SYMBOL_NATURAL_NAME (msymbol);
      name = SYMBOL_NATURAL_NAME (msymbol);
      if (name &&
      if (name &&
         (name[0] == '-' || name[0] == '+') &&
         (name[0] == '-' || name[0] == '+') &&
          name[1] == '[')                       /* Got a method name.  */
          name[1] == '[')                       /* Got a method name.  */
        if (regexp == NULL || re_exec(name+2) != 0)
        if (regexp == NULL || re_exec(name+2) != 0)
          {
          {
            /* Compute length of classname part.  */
            /* Compute length of classname part.  */
            char *mystart = name + 2;
            char *mystart = name + 2;
            char *myend   = (char *) strchr(mystart, ' ');
            char *myend   = (char *) strchr(mystart, ' ');
 
 
            if (myend && (myend - mystart > maxlen))
            if (myend && (myend - mystart > maxlen))
              maxlen = myend - mystart;
              maxlen = myend - mystart;
            matches++;
            matches++;
          }
          }
    }
    }
  if (matches)
  if (matches)
    {
    {
      printf_filtered (_("Classes matching \"%s\":\n\n"),
      printf_filtered (_("Classes matching \"%s\":\n\n"),
                       regexp ? regexp : "*");
                       regexp ? regexp : "*");
      sym_arr = alloca (matches * sizeof (struct symbol *));
      sym_arr = alloca (matches * sizeof (struct symbol *));
      matches = 0;
      matches = 0;
      ALL_MSYMBOLS (objfile, msymbol)
      ALL_MSYMBOLS (objfile, msymbol)
        {
        {
          QUIT;
          QUIT;
          name = SYMBOL_NATURAL_NAME (msymbol);
          name = SYMBOL_NATURAL_NAME (msymbol);
          if (name &&
          if (name &&
             (name[0] == '-' || name[0] == '+') &&
             (name[0] == '-' || name[0] == '+') &&
              name[1] == '[')                   /* Got a method name.  */
              name[1] == '[')                   /* Got a method name.  */
            if (regexp == NULL || re_exec(name+2) != 0)
            if (regexp == NULL || re_exec(name+2) != 0)
                sym_arr[matches++] = (struct symbol *) msymbol;
                sym_arr[matches++] = (struct symbol *) msymbol;
        }
        }
 
 
      qsort (sym_arr, matches, sizeof (struct minimal_symbol *),
      qsort (sym_arr, matches, sizeof (struct minimal_symbol *),
             compare_classes);
             compare_classes);
      /* Prevent compare on first iteration.  */
      /* Prevent compare on first iteration.  */
      aclass[0] = 0;
      aclass[0] = 0;
      for (ix = 0; ix < matches; ix++)   /* Now do the output.  */
      for (ix = 0; ix < matches; ix++)   /* Now do the output.  */
        {
        {
          char *p = aclass;
          char *p = aclass;
 
 
          QUIT;
          QUIT;
          name = SYMBOL_NATURAL_NAME (sym_arr[ix]);
          name = SYMBOL_NATURAL_NAME (sym_arr[ix]);
          name += 2;
          name += 2;
          if (p[0] && specialcmp(name, p) == 0)
          if (p[0] && specialcmp(name, p) == 0)
            continue;   /* Seen this one already (not unique).  */
            continue;   /* Seen this one already (not unique).  */
 
 
          /* Copy class part of method name.  */
          /* Copy class part of method name.  */
          while (*name && *name != ' ')
          while (*name && *name != ' ')
            *p++ = *name++;
            *p++ = *name++;
          *p++ = '\0';
          *p++ = '\0';
          /* Print in columns.  */
          /* Print in columns.  */
          puts_filtered_tabular(aclass, maxlen + 1, 0);
          puts_filtered_tabular(aclass, maxlen + 1, 0);
        }
        }
      begin_line();
      begin_line();
    }
    }
  else
  else
    printf_filtered (_("No classes matching \"%s\"\n"), regexp ? regexp : "*");
    printf_filtered (_("No classes matching \"%s\"\n"), regexp ? regexp : "*");
}
}
 
 
/*
/*
 * Function: find_imps (char *selector, struct symbol **sym_arr)
 * Function: find_imps (char *selector, struct symbol **sym_arr)
 *
 *
 * Input:  a string representing a selector
 * Input:  a string representing a selector
 *         a pointer to an array of symbol pointers
 *         a pointer to an array of symbol pointers
 *         possibly a pointer to a symbol found by the caller.
 *         possibly a pointer to a symbol found by the caller.
 *
 *
 * Output: number of methods that implement that selector.  Side
 * Output: number of methods that implement that selector.  Side
 * effects: The array of symbol pointers is filled with matching syms.
 * effects: The array of symbol pointers is filled with matching syms.
 *
 *
 * By analogy with function "find_methods" (symtab.c), builds a list
 * By analogy with function "find_methods" (symtab.c), builds a list
 * of symbols matching the ambiguous input, so that "decode_line_2"
 * of symbols matching the ambiguous input, so that "decode_line_2"
 * (symtab.c) can list them and ask the user to choose one or more.
 * (symtab.c) can list them and ask the user to choose one or more.
 * In this case the matches are objective c methods
 * In this case the matches are objective c methods
 * ("implementations") matching an objective c selector.
 * ("implementations") matching an objective c selector.
 *
 *
 * Note that it is possible for a normal (c-style) function to have
 * Note that it is possible for a normal (c-style) function to have
 * the same name as an objective c selector.  To prevent the selector
 * the same name as an objective c selector.  To prevent the selector
 * from eclipsing the function, we allow the caller (decode_line_1) to
 * from eclipsing the function, we allow the caller (decode_line_1) to
 * search for such a function first, and if it finds one, pass it in
 * search for such a function first, and if it finds one, pass it in
 * to us.  We will then integrate it into the list.  We also search
 * to us.  We will then integrate it into the list.  We also search
 * for one here, among the minsyms.
 * for one here, among the minsyms.
 *
 *
 * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
 * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
 *       into two parts: debuggable (struct symbol) syms, and
 *       into two parts: debuggable (struct symbol) syms, and
 *       non_debuggable (struct minimal_symbol) syms.  The debuggable
 *       non_debuggable (struct minimal_symbol) syms.  The debuggable
 *       ones will come first, before NUM_DEBUGGABLE (which will thus
 *       ones will come first, before NUM_DEBUGGABLE (which will thus
 *       be the index of the first non-debuggable one).
 *       be the index of the first non-debuggable one).
 */
 */
 
 
/*
/*
 * Function: total_number_of_imps (char *selector);
 * Function: total_number_of_imps (char *selector);
 *
 *
 * Input:  a string representing a selector
 * Input:  a string representing a selector
 * Output: number of methods that implement that selector.
 * Output: number of methods that implement that selector.
 *
 *
 * By analogy with function "total_number_of_methods", this allows
 * By analogy with function "total_number_of_methods", this allows
 * decode_line_1 (symtab.c) to detect if there are objective c methods
 * decode_line_1 (symtab.c) to detect if there are objective c methods
 * matching the input, and to allocate an array of pointers to them
 * matching the input, and to allocate an array of pointers to them
 * which can be manipulated by "decode_line_2" (also in symtab.c).
 * which can be manipulated by "decode_line_2" (also in symtab.c).
 */
 */
 
 
char *
char *
parse_selector (char *method, char **selector)
parse_selector (char *method, char **selector)
{
{
  char *s1 = NULL;
  char *s1 = NULL;
  char *s2 = NULL;
  char *s2 = NULL;
  int found_quote = 0;
  int found_quote = 0;
 
 
  char *nselector = NULL;
  char *nselector = NULL;
 
 
  gdb_assert (selector != NULL);
  gdb_assert (selector != NULL);
 
 
  s1 = method;
  s1 = method;
 
 
  while (isspace (*s1))
  while (isspace (*s1))
    s1++;
    s1++;
  if (*s1 == '\'')
  if (*s1 == '\'')
    {
    {
      found_quote = 1;
      found_quote = 1;
      s1++;
      s1++;
    }
    }
  while (isspace (*s1))
  while (isspace (*s1))
    s1++;
    s1++;
 
 
  nselector = s1;
  nselector = s1;
  s2 = s1;
  s2 = s1;
 
 
  for (;;) {
  for (;;) {
    if (isalnum (*s2) || (*s2 == '_') || (*s2 == ':'))
    if (isalnum (*s2) || (*s2 == '_') || (*s2 == ':'))
      *s1++ = *s2;
      *s1++ = *s2;
    else if (isspace (*s2))
    else if (isspace (*s2))
      ;
      ;
    else if ((*s2 == '\0') || (*s2 == '\''))
    else if ((*s2 == '\0') || (*s2 == '\''))
      break;
      break;
    else
    else
      return NULL;
      return NULL;
    s2++;
    s2++;
  }
  }
  *s1++ = '\0';
  *s1++ = '\0';
 
 
  while (isspace (*s2))
  while (isspace (*s2))
    s2++;
    s2++;
  if (found_quote)
  if (found_quote)
    {
    {
      if (*s2 == '\'')
      if (*s2 == '\'')
        s2++;
        s2++;
      while (isspace (*s2))
      while (isspace (*s2))
        s2++;
        s2++;
    }
    }
 
 
  if (selector != NULL)
  if (selector != NULL)
    *selector = nselector;
    *selector = nselector;
 
 
  return s2;
  return s2;
}
}
 
 
char *
char *
parse_method (char *method, char *type, char **class,
parse_method (char *method, char *type, char **class,
              char **category, char **selector)
              char **category, char **selector)
{
{
  char *s1 = NULL;
  char *s1 = NULL;
  char *s2 = NULL;
  char *s2 = NULL;
  int found_quote = 0;
  int found_quote = 0;
 
 
  char ntype = '\0';
  char ntype = '\0';
  char *nclass = NULL;
  char *nclass = NULL;
  char *ncategory = NULL;
  char *ncategory = NULL;
  char *nselector = NULL;
  char *nselector = NULL;
 
 
  gdb_assert (type != NULL);
  gdb_assert (type != NULL);
  gdb_assert (class != NULL);
  gdb_assert (class != NULL);
  gdb_assert (category != NULL);
  gdb_assert (category != NULL);
  gdb_assert (selector != NULL);
  gdb_assert (selector != NULL);
 
 
  s1 = method;
  s1 = method;
 
 
  while (isspace (*s1))
  while (isspace (*s1))
    s1++;
    s1++;
  if (*s1 == '\'')
  if (*s1 == '\'')
    {
    {
      found_quote = 1;
      found_quote = 1;
      s1++;
      s1++;
    }
    }
  while (isspace (*s1))
  while (isspace (*s1))
    s1++;
    s1++;
 
 
  if ((s1[0] == '+') || (s1[0] == '-'))
  if ((s1[0] == '+') || (s1[0] == '-'))
    ntype = *s1++;
    ntype = *s1++;
 
 
  while (isspace (*s1))
  while (isspace (*s1))
    s1++;
    s1++;
 
 
  if (*s1 != '[')
  if (*s1 != '[')
    return NULL;
    return NULL;
  s1++;
  s1++;
 
 
  nclass = s1;
  nclass = s1;
  while (isalnum (*s1) || (*s1 == '_'))
  while (isalnum (*s1) || (*s1 == '_'))
    s1++;
    s1++;
 
 
  s2 = s1;
  s2 = s1;
  while (isspace (*s2))
  while (isspace (*s2))
    s2++;
    s2++;
 
 
  if (*s2 == '(')
  if (*s2 == '(')
    {
    {
      s2++;
      s2++;
      while (isspace (*s2))
      while (isspace (*s2))
        s2++;
        s2++;
      ncategory = s2;
      ncategory = s2;
      while (isalnum (*s2) || (*s2 == '_'))
      while (isalnum (*s2) || (*s2 == '_'))
        s2++;
        s2++;
      *s2++ = '\0';
      *s2++ = '\0';
    }
    }
 
 
  /* Truncate the class name now that we're not using the open paren.  */
  /* Truncate the class name now that we're not using the open paren.  */
  *s1++ = '\0';
  *s1++ = '\0';
 
 
  nselector = s2;
  nselector = s2;
  s1 = s2;
  s1 = s2;
 
 
  for (;;) {
  for (;;) {
    if (isalnum (*s2) || (*s2 == '_') || (*s2 == ':'))
    if (isalnum (*s2) || (*s2 == '_') || (*s2 == ':'))
      *s1++ = *s2;
      *s1++ = *s2;
    else if (isspace (*s2))
    else if (isspace (*s2))
      ;
      ;
    else if (*s2 == ']')
    else if (*s2 == ']')
      break;
      break;
    else
    else
      return NULL;
      return NULL;
    s2++;
    s2++;
  }
  }
  *s1++ = '\0';
  *s1++ = '\0';
  s2++;
  s2++;
 
 
  while (isspace (*s2))
  while (isspace (*s2))
    s2++;
    s2++;
  if (found_quote)
  if (found_quote)
    {
    {
      if (*s2 != '\'')
      if (*s2 != '\'')
        return NULL;
        return NULL;
      s2++;
      s2++;
      while (isspace (*s2))
      while (isspace (*s2))
        s2++;
        s2++;
    }
    }
 
 
  if (type != NULL)
  if (type != NULL)
    *type = ntype;
    *type = ntype;
  if (class != NULL)
  if (class != NULL)
    *class = nclass;
    *class = nclass;
  if (category != NULL)
  if (category != NULL)
    *category = ncategory;
    *category = ncategory;
  if (selector != NULL)
  if (selector != NULL)
    *selector = nselector;
    *selector = nselector;
 
 
  return s2;
  return s2;
}
}
 
 
static void
static void
find_methods (struct symtab *symtab, char type,
find_methods (struct symtab *symtab, char type,
              const char *class, const char *category,
              const char *class, const char *category,
              const char *selector, struct symbol **syms,
              const char *selector, struct symbol **syms,
              unsigned int *nsym, unsigned int *ndebug)
              unsigned int *nsym, unsigned int *ndebug)
{
{
  struct objfile *objfile = NULL;
  struct objfile *objfile = NULL;
  struct minimal_symbol *msymbol = NULL;
  struct minimal_symbol *msymbol = NULL;
  struct block *block = NULL;
  struct block *block = NULL;
  struct symbol *sym = NULL;
  struct symbol *sym = NULL;
 
 
  char *symname = NULL;
  char *symname = NULL;
 
 
  char ntype = '\0';
  char ntype = '\0';
  char *nclass = NULL;
  char *nclass = NULL;
  char *ncategory = NULL;
  char *ncategory = NULL;
  char *nselector = NULL;
  char *nselector = NULL;
 
 
  unsigned int csym = 0;
  unsigned int csym = 0;
  unsigned int cdebug = 0;
  unsigned int cdebug = 0;
 
 
  static char *tmp = NULL;
  static char *tmp = NULL;
  static unsigned int tmplen = 0;
  static unsigned int tmplen = 0;
 
 
  gdb_assert (nsym != NULL);
  gdb_assert (nsym != NULL);
  gdb_assert (ndebug != NULL);
  gdb_assert (ndebug != NULL);
 
 
  if (symtab)
  if (symtab)
    block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
    block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
 
 
  ALL_OBJFILES (objfile)
  ALL_OBJFILES (objfile)
    {
    {
      unsigned int *objc_csym;
      unsigned int *objc_csym;
 
 
      /* The objfile_csym variable counts the number of ObjC methods
      /* The objfile_csym variable counts the number of ObjC methods
         that this objfile defines.  We save that count as a private
         that this objfile defines.  We save that count as a private
         objfile data.  If we have already determined that this objfile
         objfile data.  If we have already determined that this objfile
         provides no ObjC methods, we can skip it entirely.  */
         provides no ObjC methods, we can skip it entirely.  */
 
 
      unsigned int objfile_csym = 0;
      unsigned int objfile_csym = 0;
 
 
      objc_csym = objfile_data (objfile, objc_objfile_data);
      objc_csym = objfile_data (objfile, objc_objfile_data);
      if (objc_csym != NULL && *objc_csym == 0)
      if (objc_csym != NULL && *objc_csym == 0)
        /* There are no ObjC symbols in this objfile.  Skip it entirely.  */
        /* There are no ObjC symbols in this objfile.  Skip it entirely.  */
        continue;
        continue;
 
 
      ALL_OBJFILE_MSYMBOLS (objfile, msymbol)
      ALL_OBJFILE_MSYMBOLS (objfile, msymbol)
        {
        {
          struct gdbarch *gdbarch = get_objfile_arch (objfile);
          struct gdbarch *gdbarch = get_objfile_arch (objfile);
          CORE_ADDR pc = SYMBOL_VALUE_ADDRESS (msymbol);
          CORE_ADDR pc = SYMBOL_VALUE_ADDRESS (msymbol);
 
 
          QUIT;
          QUIT;
 
 
          /* The minimal symbol might point to a function descriptor;
          /* The minimal symbol might point to a function descriptor;
             resolve it to the actual code address instead.  */
             resolve it to the actual code address instead.  */
          pc = gdbarch_convert_from_func_ptr_addr (gdbarch, pc,
          pc = gdbarch_convert_from_func_ptr_addr (gdbarch, pc,
                                                   &current_target);
                                                   &current_target);
 
 
          if (symtab)
          if (symtab)
            if (pc < BLOCK_START (block) || pc >= BLOCK_END (block))
            if (pc < BLOCK_START (block) || pc >= BLOCK_END (block))
              /* Not in the specified symtab.  */
              /* Not in the specified symtab.  */
              continue;
              continue;
 
 
          symname = SYMBOL_NATURAL_NAME (msymbol);
          symname = SYMBOL_NATURAL_NAME (msymbol);
          if (symname == NULL)
          if (symname == NULL)
            continue;
            continue;
 
 
          if ((symname[0] != '-' && symname[0] != '+') || (symname[1] != '['))
          if ((symname[0] != '-' && symname[0] != '+') || (symname[1] != '['))
            /* Not a method name.  */
            /* Not a method name.  */
            continue;
            continue;
 
 
          while ((strlen (symname) + 1) >= tmplen)
          while ((strlen (symname) + 1) >= tmplen)
            {
            {
              tmplen = (tmplen == 0) ? 1024 : tmplen * 2;
              tmplen = (tmplen == 0) ? 1024 : tmplen * 2;
              tmp = xrealloc (tmp, tmplen);
              tmp = xrealloc (tmp, tmplen);
            }
            }
          strcpy (tmp, symname);
          strcpy (tmp, symname);
 
 
          if (parse_method (tmp, &ntype, &nclass, &ncategory, &nselector) == NULL)
          if (parse_method (tmp, &ntype, &nclass, &ncategory, &nselector) == NULL)
            continue;
            continue;
 
 
          objfile_csym++;
          objfile_csym++;
 
 
          if ((type != '\0') && (ntype != type))
          if ((type != '\0') && (ntype != type))
            continue;
            continue;
 
 
          if ((class != NULL)
          if ((class != NULL)
              && ((nclass == NULL) || (strcmp (class, nclass) != 0)))
              && ((nclass == NULL) || (strcmp (class, nclass) != 0)))
            continue;
            continue;
 
 
          if ((category != NULL) &&
          if ((category != NULL) &&
              ((ncategory == NULL) || (strcmp (category, ncategory) != 0)))
              ((ncategory == NULL) || (strcmp (category, ncategory) != 0)))
            continue;
            continue;
 
 
          if ((selector != NULL) &&
          if ((selector != NULL) &&
              ((nselector == NULL) || (strcmp (selector, nselector) != 0)))
              ((nselector == NULL) || (strcmp (selector, nselector) != 0)))
            continue;
            continue;
 
 
          sym = find_pc_function (pc);
          sym = find_pc_function (pc);
          if (sym != NULL)
          if (sym != NULL)
            {
            {
              const char *newsymname = SYMBOL_NATURAL_NAME (sym);
              const char *newsymname = SYMBOL_NATURAL_NAME (sym);
 
 
              if (strcmp (symname, newsymname) == 0)
              if (strcmp (symname, newsymname) == 0)
                {
                {
                  /* Found a high-level method sym: swap it into the
                  /* Found a high-level method sym: swap it into the
                     lower part of sym_arr (below num_debuggable).  */
                     lower part of sym_arr (below num_debuggable).  */
                  if (syms != NULL)
                  if (syms != NULL)
                    {
                    {
                      syms[csym] = syms[cdebug];
                      syms[csym] = syms[cdebug];
                      syms[cdebug] = sym;
                      syms[cdebug] = sym;
                    }
                    }
                  csym++;
                  csym++;
                  cdebug++;
                  cdebug++;
                }
                }
              else
              else
                {
                {
                  warning (
                  warning (
"debugging symbol \"%s\" does not match minimal symbol (\"%s\"); ignoring",
"debugging symbol \"%s\" does not match minimal symbol (\"%s\"); ignoring",
                           newsymname, symname);
                           newsymname, symname);
                  if (syms != NULL)
                  if (syms != NULL)
                    syms[csym] = (struct symbol *) msymbol;
                    syms[csym] = (struct symbol *) msymbol;
                  csym++;
                  csym++;
                }
                }
            }
            }
          else
          else
            {
            {
              /* Found a non-debuggable method symbol.  */
              /* Found a non-debuggable method symbol.  */
              if (syms != NULL)
              if (syms != NULL)
                syms[csym] = (struct symbol *) msymbol;
                syms[csym] = (struct symbol *) msymbol;
              csym++;
              csym++;
            }
            }
        }
        }
      if (objc_csym == NULL)
      if (objc_csym == NULL)
        {
        {
          objc_csym = obstack_alloc (&objfile->objfile_obstack,
          objc_csym = obstack_alloc (&objfile->objfile_obstack,
                                     sizeof (*objc_csym));
                                     sizeof (*objc_csym));
          *objc_csym = objfile_csym;
          *objc_csym = objfile_csym;
          set_objfile_data (objfile, objc_objfile_data, objc_csym);
          set_objfile_data (objfile, objc_objfile_data, objc_csym);
        }
        }
      else
      else
        /* Count of ObjC methods in this objfile should be constant.  */
        /* Count of ObjC methods in this objfile should be constant.  */
        gdb_assert (*objc_csym == objfile_csym);
        gdb_assert (*objc_csym == objfile_csym);
    }
    }
 
 
  if (nsym != NULL)
  if (nsym != NULL)
    *nsym = csym;
    *nsym = csym;
  if (ndebug != NULL)
  if (ndebug != NULL)
    *ndebug = cdebug;
    *ndebug = cdebug;
}
}
 
 
char *find_imps (struct symtab *symtab, struct block *block,
char *find_imps (struct symtab *symtab, struct block *block,
                 char *method, struct symbol **syms,
                 char *method, struct symbol **syms,
                 unsigned int *nsym, unsigned int *ndebug)
                 unsigned int *nsym, unsigned int *ndebug)
{
{
  char type = '\0';
  char type = '\0';
  char *class = NULL;
  char *class = NULL;
  char *category = NULL;
  char *category = NULL;
  char *selector = NULL;
  char *selector = NULL;
 
 
  unsigned int csym = 0;
  unsigned int csym = 0;
  unsigned int cdebug = 0;
  unsigned int cdebug = 0;
 
 
  unsigned int ncsym = 0;
  unsigned int ncsym = 0;
  unsigned int ncdebug = 0;
  unsigned int ncdebug = 0;
 
 
  char *buf = NULL;
  char *buf = NULL;
  char *tmp = NULL;
  char *tmp = NULL;
 
 
  gdb_assert (nsym != NULL);
  gdb_assert (nsym != NULL);
  gdb_assert (ndebug != NULL);
  gdb_assert (ndebug != NULL);
 
 
  if (nsym != NULL)
  if (nsym != NULL)
    *nsym = 0;
    *nsym = 0;
  if (ndebug != NULL)
  if (ndebug != NULL)
    *ndebug = 0;
    *ndebug = 0;
 
 
  buf = (char *) alloca (strlen (method) + 1);
  buf = (char *) alloca (strlen (method) + 1);
  strcpy (buf, method);
  strcpy (buf, method);
  tmp = parse_method (buf, &type, &class, &category, &selector);
  tmp = parse_method (buf, &type, &class, &category, &selector);
 
 
  if (tmp == NULL) {
  if (tmp == NULL) {
 
 
    struct symbol *sym = NULL;
    struct symbol *sym = NULL;
    struct minimal_symbol *msym = NULL;
    struct minimal_symbol *msym = NULL;
 
 
    strcpy (buf, method);
    strcpy (buf, method);
    tmp = parse_selector (buf, &selector);
    tmp = parse_selector (buf, &selector);
 
 
    if (tmp == NULL)
    if (tmp == NULL)
      return NULL;
      return NULL;
 
 
    sym = lookup_symbol (selector, block, VAR_DOMAIN, 0);
    sym = lookup_symbol (selector, block, VAR_DOMAIN, 0);
    if (sym != NULL)
    if (sym != NULL)
      {
      {
        if (syms)
        if (syms)
          syms[csym] = sym;
          syms[csym] = sym;
        csym++;
        csym++;
        cdebug++;
        cdebug++;
      }
      }
 
 
    if (sym == NULL)
    if (sym == NULL)
      msym = lookup_minimal_symbol (selector, 0, 0);
      msym = lookup_minimal_symbol (selector, 0, 0);
 
 
    if (msym != NULL)
    if (msym != NULL)
      {
      {
        if (syms)
        if (syms)
          syms[csym] = (struct symbol *)msym;
          syms[csym] = (struct symbol *)msym;
        csym++;
        csym++;
      }
      }
  }
  }
 
 
  if (syms != NULL)
  if (syms != NULL)
    find_methods (symtab, type, class, category, selector,
    find_methods (symtab, type, class, category, selector,
                  syms + csym, &ncsym, &ncdebug);
                  syms + csym, &ncsym, &ncdebug);
  else
  else
    find_methods (symtab, type, class, category, selector,
    find_methods (symtab, type, class, category, selector,
                  NULL, &ncsym, &ncdebug);
                  NULL, &ncsym, &ncdebug);
 
 
  /* If we didn't find any methods, just return.  */
  /* If we didn't find any methods, just return.  */
  if (ncsym == 0 && ncdebug == 0)
  if (ncsym == 0 && ncdebug == 0)
    return method;
    return method;
 
 
  /* Take debug symbols from the second batch of symbols and swap them
  /* Take debug symbols from the second batch of symbols and swap them
   * with debug symbols from the first batch.  Repeat until either the
   * with debug symbols from the first batch.  Repeat until either the
   * second section is out of debug symbols or the first section is
   * second section is out of debug symbols or the first section is
   * full of debug symbols.  Either way we have all debug symbols
   * full of debug symbols.  Either way we have all debug symbols
   * packed to the beginning of the buffer.
   * packed to the beginning of the buffer.
   */
   */
 
 
  if (syms != NULL)
  if (syms != NULL)
    {
    {
      while ((cdebug < csym) && (ncdebug > 0))
      while ((cdebug < csym) && (ncdebug > 0))
        {
        {
          struct symbol *s = NULL;
          struct symbol *s = NULL;
          /* First non-debugging symbol.  */
          /* First non-debugging symbol.  */
          unsigned int i = cdebug;
          unsigned int i = cdebug;
          /* Last of second batch of debug symbols.  */
          /* Last of second batch of debug symbols.  */
          unsigned int j = csym + ncdebug - 1;
          unsigned int j = csym + ncdebug - 1;
 
 
          s = syms[j];
          s = syms[j];
          syms[j] = syms[i];
          syms[j] = syms[i];
          syms[i] = s;
          syms[i] = s;
 
 
          /* We've moved a symbol from the second debug section to the
          /* We've moved a symbol from the second debug section to the
             first one.  */
             first one.  */
          cdebug++;
          cdebug++;
          ncdebug--;
          ncdebug--;
        }
        }
    }
    }
 
 
  csym += ncsym;
  csym += ncsym;
  cdebug += ncdebug;
  cdebug += ncdebug;
 
 
  if (nsym != NULL)
  if (nsym != NULL)
    *nsym = csym;
    *nsym = csym;
  if (ndebug != NULL)
  if (ndebug != NULL)
    *ndebug = cdebug;
    *ndebug = cdebug;
 
 
  if (syms == NULL)
  if (syms == NULL)
    return method + (tmp - buf);
    return method + (tmp - buf);
 
 
  if (csym > 1)
  if (csym > 1)
    {
    {
      /* Sort debuggable symbols.  */
      /* Sort debuggable symbols.  */
      if (cdebug > 1)
      if (cdebug > 1)
        qsort (syms, cdebug, sizeof (struct minimal_symbol *),
        qsort (syms, cdebug, sizeof (struct minimal_symbol *),
               compare_classes);
               compare_classes);
 
 
      /* Sort minimal_symbols.  */
      /* Sort minimal_symbols.  */
      if ((csym - cdebug) > 1)
      if ((csym - cdebug) > 1)
        qsort (&syms[cdebug], csym - cdebug,
        qsort (&syms[cdebug], csym - cdebug,
               sizeof (struct minimal_symbol *), compare_classes);
               sizeof (struct minimal_symbol *), compare_classes);
    }
    }
  /* Terminate the sym_arr list.  */
  /* Terminate the sym_arr list.  */
  syms[csym] = 0;
  syms[csym] = 0;
 
 
  return method + (tmp - buf);
  return method + (tmp - buf);
}
}
 
 
static void
static void
print_object_command (char *args, int from_tty)
print_object_command (char *args, int from_tty)
{
{
  struct value *object, *function, *description;
  struct value *object, *function, *description;
  CORE_ADDR string_addr, object_addr;
  CORE_ADDR string_addr, object_addr;
  int i = 0;
  int i = 0;
  gdb_byte c = 0;
  gdb_byte c = 0;
 
 
  if (!args || !*args)
  if (!args || !*args)
    error (
    error (
"The 'print-object' command requires an argument (an Objective-C object)");
"The 'print-object' command requires an argument (an Objective-C object)");
 
 
  {
  {
    struct expression *expr = parse_expression (args);
    struct expression *expr = parse_expression (args);
    struct cleanup *old_chain =
    struct cleanup *old_chain =
      make_cleanup (free_current_contents, &expr);
      make_cleanup (free_current_contents, &expr);
    int pc = 0;
    int pc = 0;
 
 
    object = evaluate_subexp (builtin_type (expr->gdbarch)->builtin_data_ptr,
    object = evaluate_subexp (builtin_type (expr->gdbarch)->builtin_data_ptr,
                              expr, &pc, EVAL_NORMAL);
                              expr, &pc, EVAL_NORMAL);
    do_cleanups (old_chain);
    do_cleanups (old_chain);
  }
  }
 
 
  /* Validate the address for sanity.  */
  /* Validate the address for sanity.  */
  object_addr = value_as_long (object);
  object_addr = value_as_long (object);
  read_memory (object_addr, &c, 1);
  read_memory (object_addr, &c, 1);
 
 
  function = find_function_in_inferior ("_NSPrintForDebugger", NULL);
  function = find_function_in_inferior ("_NSPrintForDebugger", NULL);
  if (function == NULL)
  if (function == NULL)
    error (_("Unable to locate _NSPrintForDebugger in child process"));
    error (_("Unable to locate _NSPrintForDebugger in child process"));
 
 
  description = call_function_by_hand (function, 1, &object);
  description = call_function_by_hand (function, 1, &object);
 
 
  string_addr = value_as_long (description);
  string_addr = value_as_long (description);
  if (string_addr == 0)
  if (string_addr == 0)
    error (_("object returns null description"));
    error (_("object returns null description"));
 
 
  read_memory (string_addr + i++, &c, 1);
  read_memory (string_addr + i++, &c, 1);
  if (c != 0)
  if (c != 0)
    do
    do
      { /* Read and print characters up to EOS.  */
      { /* Read and print characters up to EOS.  */
        QUIT;
        QUIT;
        printf_filtered ("%c", c);
        printf_filtered ("%c", c);
        read_memory (string_addr + i++, &c, 1);
        read_memory (string_addr + i++, &c, 1);
      } while (c != 0);
      } while (c != 0);
  else
  else
    printf_filtered(_("<object returns empty description>"));
    printf_filtered(_("<object returns empty description>"));
  printf_filtered ("\n");
  printf_filtered ("\n");
}
}
 
 
/* The data structure 'methcalls' is used to detect method calls (thru
/* The data structure 'methcalls' is used to detect method calls (thru
 * ObjC runtime lib functions objc_msgSend, objc_msgSendSuper, etc.),
 * ObjC runtime lib functions objc_msgSend, objc_msgSendSuper, etc.),
 * and ultimately find the method being called.
 * and ultimately find the method being called.
 */
 */
 
 
struct objc_methcall {
struct objc_methcall {
  char *name;
  char *name;
 /* Return instance method to be called.  */
 /* Return instance method to be called.  */
  int (*stop_at) (CORE_ADDR, CORE_ADDR *);
  int (*stop_at) (CORE_ADDR, CORE_ADDR *);
  /* Start of pc range corresponding to method invocation.  */
  /* Start of pc range corresponding to method invocation.  */
  CORE_ADDR begin;
  CORE_ADDR begin;
  /* End of pc range corresponding to method invocation.  */
  /* End of pc range corresponding to method invocation.  */
  CORE_ADDR end;
  CORE_ADDR end;
};
};
 
 
static int resolve_msgsend (CORE_ADDR pc, CORE_ADDR *new_pc);
static int resolve_msgsend (CORE_ADDR pc, CORE_ADDR *new_pc);
static int resolve_msgsend_stret (CORE_ADDR pc, CORE_ADDR *new_pc);
static int resolve_msgsend_stret (CORE_ADDR pc, CORE_ADDR *new_pc);
static int resolve_msgsend_super (CORE_ADDR pc, CORE_ADDR *new_pc);
static int resolve_msgsend_super (CORE_ADDR pc, CORE_ADDR *new_pc);
static int resolve_msgsend_super_stret (CORE_ADDR pc, CORE_ADDR *new_pc);
static int resolve_msgsend_super_stret (CORE_ADDR pc, CORE_ADDR *new_pc);
 
 
static struct objc_methcall methcalls[] = {
static struct objc_methcall methcalls[] = {
  { "_objc_msgSend", resolve_msgsend, 0, 0},
  { "_objc_msgSend", resolve_msgsend, 0, 0},
  { "_objc_msgSend_stret", resolve_msgsend_stret, 0, 0},
  { "_objc_msgSend_stret", resolve_msgsend_stret, 0, 0},
  { "_objc_msgSendSuper", resolve_msgsend_super, 0, 0},
  { "_objc_msgSendSuper", resolve_msgsend_super, 0, 0},
  { "_objc_msgSendSuper_stret", resolve_msgsend_super_stret, 0, 0},
  { "_objc_msgSendSuper_stret", resolve_msgsend_super_stret, 0, 0},
  { "_objc_getClass", NULL, 0, 0},
  { "_objc_getClass", NULL, 0, 0},
  { "_objc_getMetaClass", NULL, 0, 0}
  { "_objc_getMetaClass", NULL, 0, 0}
};
};
 
 
#define nmethcalls (sizeof (methcalls) / sizeof (methcalls[0]))
#define nmethcalls (sizeof (methcalls) / sizeof (methcalls[0]))
 
 
/* The following function, "find_objc_msgsend", fills in the data
/* The following function, "find_objc_msgsend", fills in the data
 * structure "objc_msgs" by finding the addresses of each of the
 * structure "objc_msgs" by finding the addresses of each of the
 * (currently four) functions that it holds (of which objc_msgSend is
 * (currently four) functions that it holds (of which objc_msgSend is
 * the first).  This must be called each time symbols are loaded, in
 * the first).  This must be called each time symbols are loaded, in
 * case the functions have moved for some reason.
 * case the functions have moved for some reason.
 */
 */
 
 
static void
static void
find_objc_msgsend (void)
find_objc_msgsend (void)
{
{
  unsigned int i;
  unsigned int i;
  for (i = 0; i < nmethcalls; i++) {
  for (i = 0; i < nmethcalls; i++) {
 
 
    struct minimal_symbol *func;
    struct minimal_symbol *func;
 
 
    /* Try both with and without underscore.  */
    /* Try both with and without underscore.  */
    func = lookup_minimal_symbol (methcalls[i].name, NULL, NULL);
    func = lookup_minimal_symbol (methcalls[i].name, NULL, NULL);
    if ((func == NULL) && (methcalls[i].name[0] == '_')) {
    if ((func == NULL) && (methcalls[i].name[0] == '_')) {
      func = lookup_minimal_symbol (methcalls[i].name + 1, NULL, NULL);
      func = lookup_minimal_symbol (methcalls[i].name + 1, NULL, NULL);
    }
    }
    if (func == NULL) {
    if (func == NULL) {
      methcalls[i].begin = 0;
      methcalls[i].begin = 0;
      methcalls[i].end = 0;
      methcalls[i].end = 0;
      continue;
      continue;
    }
    }
 
 
    methcalls[i].begin = SYMBOL_VALUE_ADDRESS (func);
    methcalls[i].begin = SYMBOL_VALUE_ADDRESS (func);
    do {
    do {
      methcalls[i].end = SYMBOL_VALUE_ADDRESS (++func);
      methcalls[i].end = SYMBOL_VALUE_ADDRESS (++func);
    } while (methcalls[i].begin == methcalls[i].end);
    } while (methcalls[i].begin == methcalls[i].end);
  }
  }
}
}
 
 
/* find_objc_msgcall (replaces pc_off_limits)
/* find_objc_msgcall (replaces pc_off_limits)
 *
 *
 * ALL that this function now does is to determine whether the input
 * ALL that this function now does is to determine whether the input
 * address ("pc") is the address of one of the Objective-C message
 * address ("pc") is the address of one of the Objective-C message
 * dispatch functions (mainly objc_msgSend or objc_msgSendSuper), and
 * dispatch functions (mainly objc_msgSend or objc_msgSendSuper), and
 * if so, it returns the address of the method that will be called.
 * if so, it returns the address of the method that will be called.
 *
 *
 * The old function "pc_off_limits" used to do a lot of other things
 * The old function "pc_off_limits" used to do a lot of other things
 * in addition, such as detecting shared library jump stubs and
 * in addition, such as detecting shared library jump stubs and
 * returning the address of the shlib function that would be called.
 * returning the address of the shlib function that would be called.
 * That functionality has been moved into the gdbarch_skip_trampoline_code and
 * That functionality has been moved into the gdbarch_skip_trampoline_code and
 * IN_SOLIB_TRAMPOLINE macros, which are resolved in the target-
 * IN_SOLIB_TRAMPOLINE macros, which are resolved in the target-
 * dependent modules.
 * dependent modules.
 */
 */
 
 
struct objc_submethod_helper_data {
struct objc_submethod_helper_data {
  int (*f) (CORE_ADDR, CORE_ADDR *);
  int (*f) (CORE_ADDR, CORE_ADDR *);
  CORE_ADDR pc;
  CORE_ADDR pc;
  CORE_ADDR *new_pc;
  CORE_ADDR *new_pc;
};
};
 
 
static int
static int
find_objc_msgcall_submethod_helper (void * arg)
find_objc_msgcall_submethod_helper (void * arg)
{
{
  struct objc_submethod_helper_data *s =
  struct objc_submethod_helper_data *s =
    (struct objc_submethod_helper_data *) arg;
    (struct objc_submethod_helper_data *) arg;
 
 
  if (s->f (s->pc, s->new_pc) == 0)
  if (s->f (s->pc, s->new_pc) == 0)
    return 1;
    return 1;
  else
  else
    return 0;
    return 0;
}
}
 
 
static int
static int
find_objc_msgcall_submethod (int (*f) (CORE_ADDR, CORE_ADDR *),
find_objc_msgcall_submethod (int (*f) (CORE_ADDR, CORE_ADDR *),
                             CORE_ADDR pc,
                             CORE_ADDR pc,
                             CORE_ADDR *new_pc)
                             CORE_ADDR *new_pc)
{
{
  struct objc_submethod_helper_data s;
  struct objc_submethod_helper_data s;
 
 
  s.f = f;
  s.f = f;
  s.pc = pc;
  s.pc = pc;
  s.new_pc = new_pc;
  s.new_pc = new_pc;
 
 
  if (catch_errors (find_objc_msgcall_submethod_helper,
  if (catch_errors (find_objc_msgcall_submethod_helper,
                    (void *) &s,
                    (void *) &s,
                    "Unable to determine target of Objective-C method call (ignoring):\n",
                    "Unable to determine target of Objective-C method call (ignoring):\n",
                    RETURN_MASK_ALL) == 0)
                    RETURN_MASK_ALL) == 0)
    return 1;
    return 1;
  else
  else
    return 0;
    return 0;
}
}
 
 
int
int
find_objc_msgcall (CORE_ADDR pc, CORE_ADDR *new_pc)
find_objc_msgcall (CORE_ADDR pc, CORE_ADDR *new_pc)
{
{
  unsigned int i;
  unsigned int i;
 
 
  find_objc_msgsend ();
  find_objc_msgsend ();
  if (new_pc != NULL)
  if (new_pc != NULL)
    {
    {
      *new_pc = 0;
      *new_pc = 0;
    }
    }
 
 
  for (i = 0; i < nmethcalls; i++)
  for (i = 0; i < nmethcalls; i++)
    if ((pc >= methcalls[i].begin) && (pc < methcalls[i].end))
    if ((pc >= methcalls[i].begin) && (pc < methcalls[i].end))
      {
      {
        if (methcalls[i].stop_at != NULL)
        if (methcalls[i].stop_at != NULL)
          return find_objc_msgcall_submethod (methcalls[i].stop_at,
          return find_objc_msgcall_submethod (methcalls[i].stop_at,
                                              pc, new_pc);
                                              pc, new_pc);
        else
        else
          return 0;
          return 0;
      }
      }
 
 
  return 0;
  return 0;
}
}
 
 
extern initialize_file_ftype _initialize_objc_language; /* -Wmissing-prototypes */
extern initialize_file_ftype _initialize_objc_language; /* -Wmissing-prototypes */
 
 
void
void
_initialize_objc_language (void)
_initialize_objc_language (void)
{
{
  add_language (&objc_language_defn);
  add_language (&objc_language_defn);
  add_info ("selectors", selectors_info,    /* INFO SELECTORS command.  */
  add_info ("selectors", selectors_info,    /* INFO SELECTORS command.  */
            _("All Objective-C selectors, or those matching REGEXP."));
            _("All Objective-C selectors, or those matching REGEXP."));
  add_info ("classes", classes_info,        /* INFO CLASSES   command.  */
  add_info ("classes", classes_info,        /* INFO CLASSES   command.  */
            _("All Objective-C classes, or those matching REGEXP."));
            _("All Objective-C classes, or those matching REGEXP."));
  add_com ("print-object", class_vars, print_object_command,
  add_com ("print-object", class_vars, print_object_command,
           _("Ask an Objective-C object to print itself."));
           _("Ask an Objective-C object to print itself."));
  add_com_alias ("po", "print-object", class_vars, 1);
  add_com_alias ("po", "print-object", class_vars, 1);
}
}
 
 
static void
static void
read_objc_method (struct gdbarch *gdbarch, CORE_ADDR addr,
read_objc_method (struct gdbarch *gdbarch, CORE_ADDR addr,
                  struct objc_method *method)
                  struct objc_method *method)
{
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  method->name  = read_memory_unsigned_integer (addr + 0, 4, byte_order);
  method->name  = read_memory_unsigned_integer (addr + 0, 4, byte_order);
  method->types = read_memory_unsigned_integer (addr + 4, 4, byte_order);
  method->types = read_memory_unsigned_integer (addr + 4, 4, byte_order);
  method->imp   = read_memory_unsigned_integer (addr + 8, 4, byte_order);
  method->imp   = read_memory_unsigned_integer (addr + 8, 4, byte_order);
}
}
 
 
static unsigned long
static unsigned long
read_objc_methlist_nmethods (struct gdbarch *gdbarch, CORE_ADDR addr)
read_objc_methlist_nmethods (struct gdbarch *gdbarch, CORE_ADDR addr)
{
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  return read_memory_unsigned_integer (addr + 4, 4, byte_order);
  return read_memory_unsigned_integer (addr + 4, 4, byte_order);
}
}
 
 
static void
static void
read_objc_methlist_method (struct gdbarch *gdbarch, CORE_ADDR addr,
read_objc_methlist_method (struct gdbarch *gdbarch, CORE_ADDR addr,
                           unsigned long num, struct objc_method *method)
                           unsigned long num, struct objc_method *method)
{
{
  gdb_assert (num < read_objc_methlist_nmethods (gdbarch, addr));
  gdb_assert (num < read_objc_methlist_nmethods (gdbarch, addr));
  read_objc_method (gdbarch, addr + 8 + (12 * num), method);
  read_objc_method (gdbarch, addr + 8 + (12 * num), method);
}
}
 
 
static void
static void
read_objc_object (struct gdbarch *gdbarch, CORE_ADDR addr,
read_objc_object (struct gdbarch *gdbarch, CORE_ADDR addr,
                  struct objc_object *object)
                  struct objc_object *object)
{
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  object->isa = read_memory_unsigned_integer (addr, 4, byte_order);
  object->isa = read_memory_unsigned_integer (addr, 4, byte_order);
}
}
 
 
static void
static void
read_objc_super (struct gdbarch *gdbarch, CORE_ADDR addr,
read_objc_super (struct gdbarch *gdbarch, CORE_ADDR addr,
                 struct objc_super *super)
                 struct objc_super *super)
{
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  super->receiver = read_memory_unsigned_integer (addr, 4, byte_order);
  super->receiver = read_memory_unsigned_integer (addr, 4, byte_order);
  super->class = read_memory_unsigned_integer (addr + 4, 4, byte_order);
  super->class = read_memory_unsigned_integer (addr + 4, 4, byte_order);
};
};
 
 
static void
static void
read_objc_class (struct gdbarch *gdbarch, CORE_ADDR addr,
read_objc_class (struct gdbarch *gdbarch, CORE_ADDR addr,
                 struct objc_class *class)
                 struct objc_class *class)
{
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  class->isa = read_memory_unsigned_integer (addr, 4, byte_order);
  class->isa = read_memory_unsigned_integer (addr, 4, byte_order);
  class->super_class = read_memory_unsigned_integer (addr + 4, 4, byte_order);
  class->super_class = read_memory_unsigned_integer (addr + 4, 4, byte_order);
  class->name = read_memory_unsigned_integer (addr + 8, 4, byte_order);
  class->name = read_memory_unsigned_integer (addr + 8, 4, byte_order);
  class->version = read_memory_unsigned_integer (addr + 12, 4, byte_order);
  class->version = read_memory_unsigned_integer (addr + 12, 4, byte_order);
  class->info = read_memory_unsigned_integer (addr + 16, 4, byte_order);
  class->info = read_memory_unsigned_integer (addr + 16, 4, byte_order);
  class->instance_size = read_memory_unsigned_integer (addr + 18, 4, byte_order);
  class->instance_size = read_memory_unsigned_integer (addr + 18, 4, byte_order);
  class->ivars = read_memory_unsigned_integer (addr + 24, 4, byte_order);
  class->ivars = read_memory_unsigned_integer (addr + 24, 4, byte_order);
  class->methods = read_memory_unsigned_integer (addr + 28, 4, byte_order);
  class->methods = read_memory_unsigned_integer (addr + 28, 4, byte_order);
  class->cache = read_memory_unsigned_integer (addr + 32, 4, byte_order);
  class->cache = read_memory_unsigned_integer (addr + 32, 4, byte_order);
  class->protocols = read_memory_unsigned_integer (addr + 36, 4, byte_order);
  class->protocols = read_memory_unsigned_integer (addr + 36, 4, byte_order);
}
}
 
 
static CORE_ADDR
static CORE_ADDR
find_implementation_from_class (struct gdbarch *gdbarch,
find_implementation_from_class (struct gdbarch *gdbarch,
                                CORE_ADDR class, CORE_ADDR sel)
                                CORE_ADDR class, CORE_ADDR sel)
{
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  CORE_ADDR subclass = class;
  CORE_ADDR subclass = class;
 
 
  while (subclass != 0)
  while (subclass != 0)
    {
    {
 
 
      struct objc_class class_str;
      struct objc_class class_str;
      unsigned mlistnum = 0;
      unsigned mlistnum = 0;
 
 
      read_objc_class (gdbarch, subclass, &class_str);
      read_objc_class (gdbarch, subclass, &class_str);
 
 
      for (;;)
      for (;;)
        {
        {
          CORE_ADDR mlist;
          CORE_ADDR mlist;
          unsigned long nmethods;
          unsigned long nmethods;
          unsigned long i;
          unsigned long i;
 
 
          mlist = read_memory_unsigned_integer (class_str.methods +
          mlist = read_memory_unsigned_integer (class_str.methods +
                                                (4 * mlistnum),
                                                (4 * mlistnum),
                                                4, byte_order);
                                                4, byte_order);
          if (mlist == 0)
          if (mlist == 0)
            break;
            break;
 
 
          nmethods = read_objc_methlist_nmethods (gdbarch, mlist);
          nmethods = read_objc_methlist_nmethods (gdbarch, mlist);
 
 
          for (i = 0; i < nmethods; i++)
          for (i = 0; i < nmethods; i++)
            {
            {
              struct objc_method meth_str;
              struct objc_method meth_str;
              read_objc_methlist_method (gdbarch, mlist, i, &meth_str);
              read_objc_methlist_method (gdbarch, mlist, i, &meth_str);
 
 
#if 0
#if 0
              fprintf (stderr,
              fprintf (stderr,
                       "checking method 0x%lx against selector 0x%lx\n",
                       "checking method 0x%lx against selector 0x%lx\n",
                       meth_str.name, sel);
                       meth_str.name, sel);
#endif
#endif
 
 
              if (meth_str.name == sel)
              if (meth_str.name == sel)
                /* FIXME: hppa arch was doing a pointer dereference
                /* FIXME: hppa arch was doing a pointer dereference
                   here. There needs to be a better way to do that.  */
                   here. There needs to be a better way to do that.  */
                return meth_str.imp;
                return meth_str.imp;
            }
            }
          mlistnum++;
          mlistnum++;
        }
        }
      subclass = class_str.super_class;
      subclass = class_str.super_class;
    }
    }
 
 
  return 0;
  return 0;
}
}
 
 
static CORE_ADDR
static CORE_ADDR
find_implementation (struct gdbarch *gdbarch,
find_implementation (struct gdbarch *gdbarch,
                     CORE_ADDR object, CORE_ADDR sel)
                     CORE_ADDR object, CORE_ADDR sel)
{
{
  struct objc_object ostr;
  struct objc_object ostr;
 
 
  if (object == 0)
  if (object == 0)
    return 0;
    return 0;
  read_objc_object (gdbarch, object, &ostr);
  read_objc_object (gdbarch, object, &ostr);
  if (ostr.isa == 0)
  if (ostr.isa == 0)
    return 0;
    return 0;
 
 
  return find_implementation_from_class (gdbarch, ostr.isa, sel);
  return find_implementation_from_class (gdbarch, ostr.isa, sel);
}
}
 
 
static int
static int
resolve_msgsend (CORE_ADDR pc, CORE_ADDR *new_pc)
resolve_msgsend (CORE_ADDR pc, CORE_ADDR *new_pc)
{
{
  struct frame_info *frame = get_current_frame ();
  struct frame_info *frame = get_current_frame ();
  struct gdbarch *gdbarch = get_frame_arch (frame);
  struct gdbarch *gdbarch = get_frame_arch (frame);
  struct type *ptr_type = builtin_type (gdbarch)->builtin_func_ptr;
  struct type *ptr_type = builtin_type (gdbarch)->builtin_func_ptr;
 
 
  CORE_ADDR object;
  CORE_ADDR object;
  CORE_ADDR sel;
  CORE_ADDR sel;
  CORE_ADDR res;
  CORE_ADDR res;
 
 
  object = gdbarch_fetch_pointer_argument (gdbarch, frame, 0, ptr_type);
  object = gdbarch_fetch_pointer_argument (gdbarch, frame, 0, ptr_type);
  sel = gdbarch_fetch_pointer_argument (gdbarch, frame, 1, ptr_type);
  sel = gdbarch_fetch_pointer_argument (gdbarch, frame, 1, ptr_type);
 
 
  res = find_implementation (gdbarch, object, sel);
  res = find_implementation (gdbarch, object, sel);
  if (new_pc != 0)
  if (new_pc != 0)
    *new_pc = res;
    *new_pc = res;
  if (res == 0)
  if (res == 0)
    return 1;
    return 1;
  return 0;
  return 0;
}
}
 
 
static int
static int
resolve_msgsend_stret (CORE_ADDR pc, CORE_ADDR *new_pc)
resolve_msgsend_stret (CORE_ADDR pc, CORE_ADDR *new_pc)
{
{
  struct frame_info *frame = get_current_frame ();
  struct frame_info *frame = get_current_frame ();
  struct gdbarch *gdbarch = get_frame_arch (frame);
  struct gdbarch *gdbarch = get_frame_arch (frame);
  struct type *ptr_type = builtin_type (gdbarch)->builtin_func_ptr;
  struct type *ptr_type = builtin_type (gdbarch)->builtin_func_ptr;
 
 
  CORE_ADDR object;
  CORE_ADDR object;
  CORE_ADDR sel;
  CORE_ADDR sel;
  CORE_ADDR res;
  CORE_ADDR res;
 
 
  object = gdbarch_fetch_pointer_argument (gdbarch, frame, 1, ptr_type);
  object = gdbarch_fetch_pointer_argument (gdbarch, frame, 1, ptr_type);
  sel = gdbarch_fetch_pointer_argument (gdbarch, frame, 2, ptr_type);
  sel = gdbarch_fetch_pointer_argument (gdbarch, frame, 2, ptr_type);
 
 
  res = find_implementation (gdbarch, object, sel);
  res = find_implementation (gdbarch, object, sel);
  if (new_pc != 0)
  if (new_pc != 0)
    *new_pc = res;
    *new_pc = res;
  if (res == 0)
  if (res == 0)
    return 1;
    return 1;
  return 0;
  return 0;
}
}
 
 
static int
static int
resolve_msgsend_super (CORE_ADDR pc, CORE_ADDR *new_pc)
resolve_msgsend_super (CORE_ADDR pc, CORE_ADDR *new_pc)
{
{
  struct frame_info *frame = get_current_frame ();
  struct frame_info *frame = get_current_frame ();
  struct gdbarch *gdbarch = get_frame_arch (frame);
  struct gdbarch *gdbarch = get_frame_arch (frame);
  struct type *ptr_type = builtin_type (gdbarch)->builtin_func_ptr;
  struct type *ptr_type = builtin_type (gdbarch)->builtin_func_ptr;
 
 
  struct objc_super sstr;
  struct objc_super sstr;
 
 
  CORE_ADDR super;
  CORE_ADDR super;
  CORE_ADDR sel;
  CORE_ADDR sel;
  CORE_ADDR res;
  CORE_ADDR res;
 
 
  super = gdbarch_fetch_pointer_argument (gdbarch, frame, 0, ptr_type);
  super = gdbarch_fetch_pointer_argument (gdbarch, frame, 0, ptr_type);
  sel = gdbarch_fetch_pointer_argument (gdbarch, frame, 1, ptr_type);
  sel = gdbarch_fetch_pointer_argument (gdbarch, frame, 1, ptr_type);
 
 
  read_objc_super (gdbarch, super, &sstr);
  read_objc_super (gdbarch, super, &sstr);
  if (sstr.class == 0)
  if (sstr.class == 0)
    return 0;
    return 0;
 
 
  res = find_implementation_from_class (gdbarch, sstr.class, sel);
  res = find_implementation_from_class (gdbarch, sstr.class, sel);
  if (new_pc != 0)
  if (new_pc != 0)
    *new_pc = res;
    *new_pc = res;
  if (res == 0)
  if (res == 0)
    return 1;
    return 1;
  return 0;
  return 0;
}
}
 
 
static int
static int
resolve_msgsend_super_stret (CORE_ADDR pc, CORE_ADDR *new_pc)
resolve_msgsend_super_stret (CORE_ADDR pc, CORE_ADDR *new_pc)
{
{
  struct frame_info *frame = get_current_frame ();
  struct frame_info *frame = get_current_frame ();
  struct gdbarch *gdbarch = get_frame_arch (frame);
  struct gdbarch *gdbarch = get_frame_arch (frame);
  struct type *ptr_type = builtin_type (gdbarch)->builtin_func_ptr;
  struct type *ptr_type = builtin_type (gdbarch)->builtin_func_ptr;
 
 
  struct objc_super sstr;
  struct objc_super sstr;
 
 
  CORE_ADDR super;
  CORE_ADDR super;
  CORE_ADDR sel;
  CORE_ADDR sel;
  CORE_ADDR res;
  CORE_ADDR res;
 
 
  super = gdbarch_fetch_pointer_argument (gdbarch, frame, 1, ptr_type);
  super = gdbarch_fetch_pointer_argument (gdbarch, frame, 1, ptr_type);
  sel = gdbarch_fetch_pointer_argument (gdbarch, frame, 2, ptr_type);
  sel = gdbarch_fetch_pointer_argument (gdbarch, frame, 2, ptr_type);
 
 
  read_objc_super (gdbarch, super, &sstr);
  read_objc_super (gdbarch, super, &sstr);
  if (sstr.class == 0)
  if (sstr.class == 0)
    return 0;
    return 0;
 
 
  res = find_implementation_from_class (gdbarch, sstr.class, sel);
  res = find_implementation_from_class (gdbarch, sstr.class, sel);
  if (new_pc != 0)
  if (new_pc != 0)
    *new_pc = res;
    *new_pc = res;
  if (res == 0)
  if (res == 0)
    return 1;
    return 1;
  return 0;
  return 0;
}
}
 
 
void
void
_initialize_objc_lang (void)
_initialize_objc_lang (void)
{
{
  objc_objfile_data = register_objfile_data ();
  objc_objfile_data = register_objfile_data ();
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.