xref: /openbsd-src/gnu/usr.bin/binutils/gdb/objc-lang.c (revision 11efff7f3ac2b3cfeff0c0cddc14294d9b3aca4f)
1b725ae77Skettenis /* Objective-C language support routines for GDB, the GNU debugger.
2b725ae77Skettenis 
3b725ae77Skettenis    Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
4b725ae77Skettenis 
5b725ae77Skettenis    Contributed by Apple Computer, Inc.
6b725ae77Skettenis    Written by Michael Snyder.
7b725ae77Skettenis 
8b725ae77Skettenis    This file is part of GDB.
9b725ae77Skettenis 
10b725ae77Skettenis    This program is free software; you can redistribute it and/or modify
11b725ae77Skettenis    it under the terms of the GNU General Public License as published by
12b725ae77Skettenis    the Free Software Foundation; either version 2 of the License, or
13b725ae77Skettenis    (at your option) any later version.
14b725ae77Skettenis 
15b725ae77Skettenis    This program is distributed in the hope that it will be useful,
16b725ae77Skettenis    but WITHOUT ANY WARRANTY; without even the implied warranty of
17b725ae77Skettenis    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18b725ae77Skettenis    GNU General Public License for more details.
19b725ae77Skettenis 
20b725ae77Skettenis    You should have received a copy of the GNU General Public License
21b725ae77Skettenis    along with this program; if not, write to the Free Software
22b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
23b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
24b725ae77Skettenis 
25b725ae77Skettenis #include "defs.h"
26b725ae77Skettenis #include "symtab.h"
27b725ae77Skettenis #include "gdbtypes.h"
28b725ae77Skettenis #include "expression.h"
29b725ae77Skettenis #include "parser-defs.h"
30b725ae77Skettenis #include "language.h"
31b725ae77Skettenis #include "c-lang.h"
32b725ae77Skettenis #include "objc-lang.h"
33b725ae77Skettenis #include "complaints.h"
34b725ae77Skettenis #include "value.h"
35b725ae77Skettenis #include "symfile.h"
36b725ae77Skettenis #include "objfiles.h"
37b725ae77Skettenis #include "gdb_string.h"		/* for strchr */
38b725ae77Skettenis #include "target.h"		/* for target_has_execution */
39b725ae77Skettenis #include "gdbcore.h"
40b725ae77Skettenis #include "gdbcmd.h"
41b725ae77Skettenis #include "frame.h"
42b725ae77Skettenis #include "gdb_regex.h"
43b725ae77Skettenis #include "regcache.h"
44b725ae77Skettenis #include "block.h"
45b725ae77Skettenis #include "infcall.h"
46b725ae77Skettenis #include "valprint.h"
47b725ae77Skettenis #include "gdb_assert.h"
48b725ae77Skettenis 
49b725ae77Skettenis #include <ctype.h>
50b725ae77Skettenis 
51b725ae77Skettenis struct objc_object {
52b725ae77Skettenis   CORE_ADDR isa;
53b725ae77Skettenis };
54b725ae77Skettenis 
55b725ae77Skettenis struct objc_class {
56b725ae77Skettenis   CORE_ADDR isa;
57b725ae77Skettenis   CORE_ADDR super_class;
58b725ae77Skettenis   CORE_ADDR name;
59b725ae77Skettenis   long version;
60b725ae77Skettenis   long info;
61b725ae77Skettenis   long instance_size;
62b725ae77Skettenis   CORE_ADDR ivars;
63b725ae77Skettenis   CORE_ADDR methods;
64b725ae77Skettenis   CORE_ADDR cache;
65b725ae77Skettenis   CORE_ADDR protocols;
66b725ae77Skettenis };
67b725ae77Skettenis 
68b725ae77Skettenis struct objc_super {
69b725ae77Skettenis   CORE_ADDR receiver;
70b725ae77Skettenis   CORE_ADDR class;
71b725ae77Skettenis };
72b725ae77Skettenis 
73b725ae77Skettenis struct objc_method {
74b725ae77Skettenis   CORE_ADDR name;
75b725ae77Skettenis   CORE_ADDR types;
76b725ae77Skettenis   CORE_ADDR imp;
77b725ae77Skettenis };
78b725ae77Skettenis 
79b725ae77Skettenis /* Lookup a structure type named "struct NAME", visible in lexical
80b725ae77Skettenis    block BLOCK.  If NOERR is nonzero, return zero if NAME is not
81b725ae77Skettenis    suitably defined.  */
82b725ae77Skettenis 
83b725ae77Skettenis struct symbol *
lookup_struct_typedef(char * name,struct block * block,int noerr)84b725ae77Skettenis lookup_struct_typedef (char *name, struct block *block, int noerr)
85b725ae77Skettenis {
86b725ae77Skettenis   struct symbol *sym;
87b725ae77Skettenis 
88b725ae77Skettenis   sym = lookup_symbol (name, block, STRUCT_DOMAIN, 0,
89b725ae77Skettenis 		       (struct symtab **) NULL);
90b725ae77Skettenis 
91b725ae77Skettenis   if (sym == NULL)
92b725ae77Skettenis     {
93b725ae77Skettenis       if (noerr)
94b725ae77Skettenis 	return 0;
95b725ae77Skettenis       else
96b725ae77Skettenis 	error ("No struct type named %s.", name);
97b725ae77Skettenis     }
98b725ae77Skettenis   if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT)
99b725ae77Skettenis     {
100b725ae77Skettenis       if (noerr)
101b725ae77Skettenis 	return 0;
102b725ae77Skettenis       else
103b725ae77Skettenis 	error ("This context has class, union or enum %s, not a struct.",
104b725ae77Skettenis 	       name);
105b725ae77Skettenis     }
106b725ae77Skettenis   return sym;
107b725ae77Skettenis }
108b725ae77Skettenis 
109b725ae77Skettenis CORE_ADDR
lookup_objc_class(char * classname)110b725ae77Skettenis lookup_objc_class (char *classname)
111b725ae77Skettenis {
112b725ae77Skettenis   struct value * function, *classval;
113b725ae77Skettenis 
114b725ae77Skettenis   if (! target_has_execution)
115b725ae77Skettenis     {
116b725ae77Skettenis       /* Can't call into inferior to lookup class.  */
117b725ae77Skettenis       return 0;
118b725ae77Skettenis     }
119b725ae77Skettenis 
120b725ae77Skettenis   if (lookup_minimal_symbol("objc_lookUpClass", 0, 0))
121b725ae77Skettenis     function = find_function_in_inferior("objc_lookUpClass");
122b725ae77Skettenis   else if (lookup_minimal_symbol ("objc_lookup_class", 0, 0))
123b725ae77Skettenis     function = find_function_in_inferior("objc_lookup_class");
124b725ae77Skettenis   else
125b725ae77Skettenis     {
126b725ae77Skettenis       complaint (&symfile_complaints, "no way to lookup Objective-C classes");
127b725ae77Skettenis       return 0;
128b725ae77Skettenis     }
129b725ae77Skettenis 
130b725ae77Skettenis   classval = value_string (classname, strlen (classname) + 1);
131b725ae77Skettenis   classval = value_coerce_array (classval);
132b725ae77Skettenis   return (CORE_ADDR) value_as_long (call_function_by_hand (function,
133b725ae77Skettenis 							   1, &classval));
134b725ae77Skettenis }
135b725ae77Skettenis 
136b725ae77Skettenis CORE_ADDR
lookup_child_selector(char * selname)137b725ae77Skettenis lookup_child_selector (char *selname)
138b725ae77Skettenis {
139b725ae77Skettenis   struct value * function, *selstring;
140b725ae77Skettenis 
141b725ae77Skettenis   if (! target_has_execution)
142b725ae77Skettenis     {
143b725ae77Skettenis       /* Can't call into inferior to lookup selector.  */
144b725ae77Skettenis       return 0;
145b725ae77Skettenis     }
146b725ae77Skettenis 
147b725ae77Skettenis   if (lookup_minimal_symbol("sel_getUid", 0, 0))
148b725ae77Skettenis     function = find_function_in_inferior("sel_getUid");
149b725ae77Skettenis   else if (lookup_minimal_symbol ("sel_get_any_uid", 0, 0))
150b725ae77Skettenis     function = find_function_in_inferior("sel_get_any_uid");
151b725ae77Skettenis   else
152b725ae77Skettenis     {
153b725ae77Skettenis       complaint (&symfile_complaints, "no way to lookup Objective-C selectors");
154b725ae77Skettenis       return 0;
155b725ae77Skettenis     }
156b725ae77Skettenis 
157b725ae77Skettenis   selstring = value_coerce_array (value_string (selname,
158b725ae77Skettenis 						strlen (selname) + 1));
159b725ae77Skettenis   return value_as_long (call_function_by_hand (function, 1, &selstring));
160b725ae77Skettenis }
161b725ae77Skettenis 
162b725ae77Skettenis struct value *
value_nsstring(char * ptr,int len)163b725ae77Skettenis value_nsstring (char *ptr, int len)
164b725ae77Skettenis {
165b725ae77Skettenis   struct value *stringValue[3];
166b725ae77Skettenis   struct value *function, *nsstringValue;
167b725ae77Skettenis   struct symbol *sym;
168b725ae77Skettenis   struct type *type;
169b725ae77Skettenis 
170b725ae77Skettenis   if (!target_has_execution)
171b725ae77Skettenis     return 0;		/* Can't call into inferior to create NSString.  */
172b725ae77Skettenis 
173b725ae77Skettenis   sym = lookup_struct_typedef("NSString", 0, 1);
174b725ae77Skettenis   if (sym == NULL)
175b725ae77Skettenis     sym = lookup_struct_typedef("NXString", 0, 1);
176b725ae77Skettenis   if (sym == NULL)
177b725ae77Skettenis     type = lookup_pointer_type(builtin_type_void);
178b725ae77Skettenis   else
179b725ae77Skettenis     type = lookup_pointer_type(SYMBOL_TYPE (sym));
180b725ae77Skettenis 
181b725ae77Skettenis   stringValue[2] = value_string(ptr, len);
182b725ae77Skettenis   stringValue[2] = value_coerce_array(stringValue[2]);
183b725ae77Skettenis   /* _NSNewStringFromCString replaces "istr" after Lantern2A.  */
184b725ae77Skettenis   if (lookup_minimal_symbol("_NSNewStringFromCString", 0, 0))
185b725ae77Skettenis     {
186b725ae77Skettenis       function = find_function_in_inferior("_NSNewStringFromCString");
187b725ae77Skettenis       nsstringValue = call_function_by_hand(function, 1, &stringValue[2]);
188b725ae77Skettenis     }
189b725ae77Skettenis   else if (lookup_minimal_symbol("istr", 0, 0))
190b725ae77Skettenis     {
191b725ae77Skettenis       function = find_function_in_inferior("istr");
192b725ae77Skettenis       nsstringValue = call_function_by_hand(function, 1, &stringValue[2]);
193b725ae77Skettenis     }
194b725ae77Skettenis   else if (lookup_minimal_symbol("+[NSString stringWithCString:]", 0, 0))
195b725ae77Skettenis     {
196b725ae77Skettenis       function = find_function_in_inferior("+[NSString stringWithCString:]");
197b725ae77Skettenis       stringValue[0] = value_from_longest
198b725ae77Skettenis 	(builtin_type_long, lookup_objc_class ("NSString"));
199b725ae77Skettenis       stringValue[1] = value_from_longest
200b725ae77Skettenis 	(builtin_type_long, lookup_child_selector ("stringWithCString:"));
201b725ae77Skettenis       nsstringValue = call_function_by_hand(function, 3, &stringValue[0]);
202b725ae77Skettenis     }
203b725ae77Skettenis   else
204b725ae77Skettenis     error ("NSString: internal error -- no way to create new NSString");
205b725ae77Skettenis 
206b725ae77Skettenis   VALUE_TYPE(nsstringValue) = type;
207b725ae77Skettenis   return nsstringValue;
208b725ae77Skettenis }
209b725ae77Skettenis 
210b725ae77Skettenis /* Objective-C name demangling.  */
211b725ae77Skettenis 
212b725ae77Skettenis char *
objc_demangle(const char * mangled,int options)213b725ae77Skettenis objc_demangle (const char *mangled, int options)
214b725ae77Skettenis {
215b725ae77Skettenis   char *demangled, *cp;
216b725ae77Skettenis 
217b725ae77Skettenis   if (mangled[0] == '_' &&
218b725ae77Skettenis      (mangled[1] == 'i' || mangled[1] == 'c') &&
219b725ae77Skettenis       mangled[2] == '_')
220b725ae77Skettenis     {
221b725ae77Skettenis       cp = demangled = xmalloc(strlen(mangled) + 2);
222b725ae77Skettenis 
223b725ae77Skettenis       if (mangled[1] == 'i')
224b725ae77Skettenis 	*cp++ = '-';		/* for instance method */
225b725ae77Skettenis       else
226b725ae77Skettenis 	*cp++ = '+';		/* for class    method */
227b725ae77Skettenis 
228b725ae77Skettenis       *cp++ = '[';		/* opening left brace  */
229b725ae77Skettenis       strcpy(cp, mangled+3);	/* tack on the rest of the mangled name */
230b725ae77Skettenis 
231b725ae77Skettenis       while (*cp && *cp == '_')
232b725ae77Skettenis 	cp++;			/* skip any initial underbars in class name */
233b725ae77Skettenis 
234b725ae77Skettenis       cp = strchr(cp, '_');
235b725ae77Skettenis       if (!cp)	                /* find first non-initial underbar */
236b725ae77Skettenis 	{
237b725ae77Skettenis 	  xfree(demangled);	/* not mangled name */
238b725ae77Skettenis 	  return NULL;
239b725ae77Skettenis 	}
240b725ae77Skettenis       if (cp[1] == '_') {	/* easy case: no category name     */
241b725ae77Skettenis 	*cp++ = ' ';		/* replace two '_' with one ' '    */
242b725ae77Skettenis 	strcpy(cp, mangled + (cp - demangled) + 2);
243b725ae77Skettenis       }
244b725ae77Skettenis       else {
245b725ae77Skettenis 	*cp++ = '(';		/* less easy case: category name */
246b725ae77Skettenis 	cp = strchr(cp, '_');
247b725ae77Skettenis 	if (!cp)
248b725ae77Skettenis 	  {
249b725ae77Skettenis 	    xfree(demangled);	/* not mangled name */
250b725ae77Skettenis 	    return NULL;
251b725ae77Skettenis 	  }
252b725ae77Skettenis 	*cp++ = ')';
253b725ae77Skettenis 	*cp++ = ' ';		/* overwriting 1st char of method name...  */
254b725ae77Skettenis 	strcpy(cp, mangled + (cp - demangled));	/* get it back */
255b725ae77Skettenis       }
256b725ae77Skettenis 
257b725ae77Skettenis       while (*cp && *cp == '_')
258b725ae77Skettenis 	cp++;			/* skip any initial underbars in method name */
259b725ae77Skettenis 
260b725ae77Skettenis       for (; *cp; cp++)
261b725ae77Skettenis 	if (*cp == '_')
262b725ae77Skettenis 	  *cp = ':';		/* replace remaining '_' with ':' */
263b725ae77Skettenis 
264b725ae77Skettenis       *cp++ = ']';		/* closing right brace */
265b725ae77Skettenis       *cp++ = 0;		/* string terminator */
266b725ae77Skettenis       return demangled;
267b725ae77Skettenis     }
268b725ae77Skettenis   else
269b725ae77Skettenis     return NULL;	/* Not an objc mangled name.  */
270b725ae77Skettenis }
271b725ae77Skettenis 
272b725ae77Skettenis /* Print the character C on STREAM as part of the contents of a
273b725ae77Skettenis    literal string whose delimiter is QUOTER.  Note that that format
274b725ae77Skettenis    for printing characters and strings is language specific.  */
275b725ae77Skettenis 
276b725ae77Skettenis static void
objc_emit_char(int c,struct ui_file * stream,int quoter)277b725ae77Skettenis objc_emit_char (int c, struct ui_file *stream, int quoter)
278b725ae77Skettenis {
279b725ae77Skettenis 
280b725ae77Skettenis   c &= 0xFF;			/* Avoid sign bit follies.  */
281b725ae77Skettenis 
282b725ae77Skettenis   if (PRINT_LITERAL_FORM (c))
283b725ae77Skettenis     {
284b725ae77Skettenis       if (c == '\\' || c == quoter)
285b725ae77Skettenis 	{
286b725ae77Skettenis 	  fputs_filtered ("\\", stream);
287b725ae77Skettenis 	}
288b725ae77Skettenis       fprintf_filtered (stream, "%c", c);
289b725ae77Skettenis     }
290b725ae77Skettenis   else
291b725ae77Skettenis     {
292b725ae77Skettenis       switch (c)
293b725ae77Skettenis 	{
294b725ae77Skettenis 	case '\n':
295b725ae77Skettenis 	  fputs_filtered ("\\n", stream);
296b725ae77Skettenis 	  break;
297b725ae77Skettenis 	case '\b':
298b725ae77Skettenis 	  fputs_filtered ("\\b", stream);
299b725ae77Skettenis 	  break;
300b725ae77Skettenis 	case '\t':
301b725ae77Skettenis 	  fputs_filtered ("\\t", stream);
302b725ae77Skettenis 	  break;
303b725ae77Skettenis 	case '\f':
304b725ae77Skettenis 	  fputs_filtered ("\\f", stream);
305b725ae77Skettenis 	  break;
306b725ae77Skettenis 	case '\r':
307b725ae77Skettenis 	  fputs_filtered ("\\r", stream);
308b725ae77Skettenis 	  break;
309b725ae77Skettenis 	case '\033':
310b725ae77Skettenis 	  fputs_filtered ("\\e", stream);
311b725ae77Skettenis 	  break;
312b725ae77Skettenis 	case '\007':
313b725ae77Skettenis 	  fputs_filtered ("\\a", stream);
314b725ae77Skettenis 	  break;
315b725ae77Skettenis 	default:
316b725ae77Skettenis 	  fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
317b725ae77Skettenis 	  break;
318b725ae77Skettenis 	}
319b725ae77Skettenis     }
320b725ae77Skettenis }
321b725ae77Skettenis 
322b725ae77Skettenis static void
objc_printchar(int c,struct ui_file * stream)323b725ae77Skettenis objc_printchar (int c, struct ui_file *stream)
324b725ae77Skettenis {
325b725ae77Skettenis   fputs_filtered ("'", stream);
326b725ae77Skettenis   objc_emit_char (c, stream, '\'');
327b725ae77Skettenis   fputs_filtered ("'", stream);
328b725ae77Skettenis }
329b725ae77Skettenis 
330b725ae77Skettenis /* Print the character string STRING, printing at most LENGTH
331b725ae77Skettenis    characters.  Printing stops early if the number hits print_max;
332b725ae77Skettenis    repeat counts are printed as appropriate.  Print ellipses at the
333b725ae77Skettenis    end if we had to stop before printing LENGTH characters, or if
334b725ae77Skettenis    FORCE_ELLIPSES.  */
335b725ae77Skettenis 
336b725ae77Skettenis static void
objc_printstr(struct ui_file * stream,char * string,unsigned int length,int width,int force_ellipses)337b725ae77Skettenis objc_printstr (struct ui_file *stream, char *string,
338b725ae77Skettenis 	       unsigned int length, int width, int force_ellipses)
339b725ae77Skettenis {
340b725ae77Skettenis   unsigned int i;
341b725ae77Skettenis   unsigned int things_printed = 0;
342b725ae77Skettenis   int in_quotes = 0;
343b725ae77Skettenis   int need_comma = 0;
344b725ae77Skettenis 
345b725ae77Skettenis   /* If the string was not truncated due to `set print elements', and
346b725ae77Skettenis      the last byte of it is a null, we don't print that, in
347b725ae77Skettenis      traditional C style.  */
348b725ae77Skettenis   if ((!force_ellipses) && length > 0 && string[length-1] == '\0')
349b725ae77Skettenis     length--;
350b725ae77Skettenis 
351b725ae77Skettenis   if (length == 0)
352b725ae77Skettenis     {
353b725ae77Skettenis       fputs_filtered ("\"\"", stream);
354b725ae77Skettenis       return;
355b725ae77Skettenis     }
356b725ae77Skettenis 
357b725ae77Skettenis   for (i = 0; i < length && things_printed < print_max; ++i)
358b725ae77Skettenis     {
359b725ae77Skettenis       /* Position of the character we are examining to see whether it
360b725ae77Skettenis 	 is repeated.  */
361b725ae77Skettenis       unsigned int rep1;
362b725ae77Skettenis       /* Number of repetitions we have detected so far.  */
363b725ae77Skettenis       unsigned int reps;
364b725ae77Skettenis 
365b725ae77Skettenis       QUIT;
366b725ae77Skettenis 
367b725ae77Skettenis       if (need_comma)
368b725ae77Skettenis 	{
369b725ae77Skettenis 	  fputs_filtered (", ", stream);
370b725ae77Skettenis 	  need_comma = 0;
371b725ae77Skettenis 	}
372b725ae77Skettenis 
373b725ae77Skettenis       rep1 = i + 1;
374b725ae77Skettenis       reps = 1;
375b725ae77Skettenis       while (rep1 < length && string[rep1] == string[i])
376b725ae77Skettenis 	{
377b725ae77Skettenis 	  ++rep1;
378b725ae77Skettenis 	  ++reps;
379b725ae77Skettenis 	}
380b725ae77Skettenis 
381b725ae77Skettenis       if (reps > repeat_count_threshold)
382b725ae77Skettenis 	{
383b725ae77Skettenis 	  if (in_quotes)
384b725ae77Skettenis 	    {
385b725ae77Skettenis 	      if (inspect_it)
386b725ae77Skettenis 		fputs_filtered ("\\\", ", stream);
387b725ae77Skettenis 	      else
388b725ae77Skettenis 		fputs_filtered ("\", ", stream);
389b725ae77Skettenis 	      in_quotes = 0;
390b725ae77Skettenis 	    }
391b725ae77Skettenis 	  objc_printchar (string[i], stream);
392b725ae77Skettenis 	  fprintf_filtered (stream, " <repeats %u times>", reps);
393b725ae77Skettenis 	  i = rep1 - 1;
394b725ae77Skettenis 	  things_printed += repeat_count_threshold;
395b725ae77Skettenis 	  need_comma = 1;
396b725ae77Skettenis 	}
397b725ae77Skettenis       else
398b725ae77Skettenis 	{
399b725ae77Skettenis 	  if (!in_quotes)
400b725ae77Skettenis 	    {
401b725ae77Skettenis 	      if (inspect_it)
402b725ae77Skettenis 		fputs_filtered ("\\\"", stream);
403b725ae77Skettenis 	      else
404b725ae77Skettenis 		fputs_filtered ("\"", stream);
405b725ae77Skettenis 	      in_quotes = 1;
406b725ae77Skettenis 	    }
407b725ae77Skettenis 	  objc_emit_char (string[i], stream, '"');
408b725ae77Skettenis 	  ++things_printed;
409b725ae77Skettenis 	}
410b725ae77Skettenis     }
411b725ae77Skettenis 
412b725ae77Skettenis   /* Terminate the quotes if necessary.  */
413b725ae77Skettenis   if (in_quotes)
414b725ae77Skettenis     {
415b725ae77Skettenis       if (inspect_it)
416b725ae77Skettenis 	fputs_filtered ("\\\"", stream);
417b725ae77Skettenis       else
418b725ae77Skettenis 	fputs_filtered ("\"", stream);
419b725ae77Skettenis     }
420b725ae77Skettenis 
421b725ae77Skettenis   if (force_ellipses || i < length)
422b725ae77Skettenis     fputs_filtered ("...", stream);
423b725ae77Skettenis }
424b725ae77Skettenis 
425b725ae77Skettenis /* Create a fundamental C type using default reasonable for the
426b725ae77Skettenis    current target.
427b725ae77Skettenis 
428b725ae77Skettenis    Some object/debugging file formats (DWARF version 1, COFF, etc) do
429b725ae77Skettenis    not define fundamental types such as "int" or "double".  Others
430b725ae77Skettenis    (stabs or DWARF version 2, etc) do define fundamental types.  For
431b725ae77Skettenis    the formats which don't provide fundamental types, gdb can create
432b725ae77Skettenis    such types using this function.
433b725ae77Skettenis 
434b725ae77Skettenis    FIXME: Some compilers distinguish explicitly signed integral types
435b725ae77Skettenis    (signed short, signed int, signed long) from "regular" integral
436b725ae77Skettenis    types (short, int, long) in the debugging information.  There is
437b725ae77Skettenis    some disagreement as to how useful this feature is.  In particular,
438b725ae77Skettenis    gcc does not support this.  Also, only some debugging formats allow
439b725ae77Skettenis    the distinction to be passed on to a debugger.  For now, we always
440b725ae77Skettenis    just use "short", "int", or "long" as the type name, for both the
441b725ae77Skettenis    implicit and explicitly signed types.  This also makes life easier
442b725ae77Skettenis    for the gdb test suite since we don't have to account for the
443b725ae77Skettenis    differences in output depending upon what the compiler and
444b725ae77Skettenis    debugging format support.  We will probably have to re-examine the
445b725ae77Skettenis    issue when gdb starts taking it's fundamental type information
446b725ae77Skettenis    directly from the debugging information supplied by the compiler.
447b725ae77Skettenis    fnf@cygnus.com */
448b725ae77Skettenis 
449b725ae77Skettenis static struct type *
objc_create_fundamental_type(struct objfile * objfile,int typeid)450b725ae77Skettenis objc_create_fundamental_type (struct objfile *objfile, int typeid)
451b725ae77Skettenis {
452b725ae77Skettenis   struct type *type = NULL;
453b725ae77Skettenis 
454b725ae77Skettenis   switch (typeid)
455b725ae77Skettenis     {
456b725ae77Skettenis       default:
457b725ae77Skettenis 	/* FIXME: For now, if we are asked to produce a type not in
458b725ae77Skettenis 	   this language, create the equivalent of a C integer type
459b725ae77Skettenis 	   with the name "<?type?>".  When all the dust settles from
460b725ae77Skettenis 	   the type reconstruction work, this should probably become
461b725ae77Skettenis 	   an error.  */
462b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
463b725ae77Skettenis 			  TARGET_INT_BIT / TARGET_CHAR_BIT,
464b725ae77Skettenis 			  0, "<?type?>", objfile);
465b725ae77Skettenis         warning ("internal error: no C/C++ fundamental type %d", typeid);
466b725ae77Skettenis 	break;
467b725ae77Skettenis       case FT_VOID:
468b725ae77Skettenis 	type = init_type (TYPE_CODE_VOID,
469b725ae77Skettenis 			  TARGET_CHAR_BIT / TARGET_CHAR_BIT,
470b725ae77Skettenis 			  0, "void", objfile);
471b725ae77Skettenis 	break;
472b725ae77Skettenis       case FT_CHAR:
473b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
474b725ae77Skettenis 			  TARGET_CHAR_BIT / TARGET_CHAR_BIT,
475b725ae77Skettenis 			  0, "char", objfile);
476b725ae77Skettenis 	break;
477b725ae77Skettenis       case FT_SIGNED_CHAR:
478b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
479b725ae77Skettenis 			  TARGET_CHAR_BIT / TARGET_CHAR_BIT,
480b725ae77Skettenis 			  0, "signed char", objfile);
481b725ae77Skettenis 	break;
482b725ae77Skettenis       case FT_UNSIGNED_CHAR:
483b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
484b725ae77Skettenis 			  TARGET_CHAR_BIT / TARGET_CHAR_BIT,
485b725ae77Skettenis 			  TYPE_FLAG_UNSIGNED, "unsigned char", objfile);
486b725ae77Skettenis 	break;
487b725ae77Skettenis       case FT_SHORT:
488b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
489b725ae77Skettenis 			  TARGET_SHORT_BIT / TARGET_CHAR_BIT,
490b725ae77Skettenis 			  0, "short", objfile);
491b725ae77Skettenis 	break;
492b725ae77Skettenis       case FT_SIGNED_SHORT:
493b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
494b725ae77Skettenis 			  TARGET_SHORT_BIT / TARGET_CHAR_BIT,
495b725ae77Skettenis 			  0, "short", objfile);	/* FIXME-fnf */
496b725ae77Skettenis 	break;
497b725ae77Skettenis       case FT_UNSIGNED_SHORT:
498b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
499b725ae77Skettenis 			  TARGET_SHORT_BIT / TARGET_CHAR_BIT,
500b725ae77Skettenis 			  TYPE_FLAG_UNSIGNED, "unsigned short", objfile);
501b725ae77Skettenis 	break;
502b725ae77Skettenis       case FT_INTEGER:
503b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
504b725ae77Skettenis 			  TARGET_INT_BIT / TARGET_CHAR_BIT,
505b725ae77Skettenis 			  0, "int", objfile);
506b725ae77Skettenis 	break;
507b725ae77Skettenis       case FT_SIGNED_INTEGER:
508b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
509b725ae77Skettenis 			  TARGET_INT_BIT / TARGET_CHAR_BIT,
510b725ae77Skettenis 			  0, "int", objfile); /* FIXME -fnf */
511b725ae77Skettenis 	break;
512b725ae77Skettenis       case FT_UNSIGNED_INTEGER:
513b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
514b725ae77Skettenis 			  TARGET_INT_BIT / TARGET_CHAR_BIT,
515b725ae77Skettenis 			  TYPE_FLAG_UNSIGNED, "unsigned int", objfile);
516b725ae77Skettenis 	break;
517b725ae77Skettenis       case FT_LONG:
518b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
519b725ae77Skettenis 			  TARGET_LONG_BIT / TARGET_CHAR_BIT,
520b725ae77Skettenis 			  0, "long", objfile);
521b725ae77Skettenis 	break;
522b725ae77Skettenis       case FT_SIGNED_LONG:
523b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
524b725ae77Skettenis 			  TARGET_LONG_BIT / TARGET_CHAR_BIT,
525b725ae77Skettenis 			  0, "long", objfile); /* FIXME -fnf */
526b725ae77Skettenis 	break;
527b725ae77Skettenis       case FT_UNSIGNED_LONG:
528b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
529b725ae77Skettenis 			  TARGET_LONG_BIT / TARGET_CHAR_BIT,
530b725ae77Skettenis 			  TYPE_FLAG_UNSIGNED, "unsigned long", objfile);
531b725ae77Skettenis 	break;
532b725ae77Skettenis       case FT_LONG_LONG:
533b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
534b725ae77Skettenis 			  TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
535b725ae77Skettenis 			  0, "long long", objfile);
536b725ae77Skettenis 	break;
537b725ae77Skettenis       case FT_SIGNED_LONG_LONG:
538b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
539b725ae77Skettenis 			  TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
540b725ae77Skettenis 			  0, "signed long long", objfile);
541b725ae77Skettenis 	break;
542b725ae77Skettenis       case FT_UNSIGNED_LONG_LONG:
543b725ae77Skettenis 	type = init_type (TYPE_CODE_INT,
544b725ae77Skettenis 			  TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
545b725ae77Skettenis 			  TYPE_FLAG_UNSIGNED, "unsigned long long", objfile);
546b725ae77Skettenis 	break;
547b725ae77Skettenis       case FT_FLOAT:
548b725ae77Skettenis 	type = init_type (TYPE_CODE_FLT,
549b725ae77Skettenis 			  TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
550b725ae77Skettenis 			  0, "float", objfile);
551b725ae77Skettenis 	break;
552b725ae77Skettenis       case FT_DBL_PREC_FLOAT:
553b725ae77Skettenis 	type = init_type (TYPE_CODE_FLT,
554b725ae77Skettenis 			  TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
555b725ae77Skettenis 			  0, "double", objfile);
556b725ae77Skettenis 	break;
557b725ae77Skettenis       case FT_EXT_PREC_FLOAT:
558b725ae77Skettenis 	type = init_type (TYPE_CODE_FLT,
559b725ae77Skettenis 			  TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
560b725ae77Skettenis 			  0, "long double", objfile);
561b725ae77Skettenis 	break;
562b725ae77Skettenis       }
563b725ae77Skettenis   return (type);
564b725ae77Skettenis }
565b725ae77Skettenis 
566b725ae77Skettenis /* Determine if we are currently in the Objective-C dispatch function.
567b725ae77Skettenis    If so, get the address of the method function that the dispatcher
568b725ae77Skettenis    would call and use that as the function to step into instead. Also
569b725ae77Skettenis    skip over the trampoline for the function (if any).  This is better
570b725ae77Skettenis    for the user since they are only interested in stepping into the
571b725ae77Skettenis    method function anyway.  */
572b725ae77Skettenis static CORE_ADDR
objc_skip_trampoline(CORE_ADDR stop_pc)573b725ae77Skettenis objc_skip_trampoline (CORE_ADDR stop_pc)
574b725ae77Skettenis {
575b725ae77Skettenis   CORE_ADDR real_stop_pc;
576b725ae77Skettenis   CORE_ADDR method_stop_pc;
577b725ae77Skettenis 
578b725ae77Skettenis   real_stop_pc = SKIP_TRAMPOLINE_CODE (stop_pc);
579b725ae77Skettenis 
580b725ae77Skettenis   if (real_stop_pc != 0)
581b725ae77Skettenis     find_objc_msgcall (real_stop_pc, &method_stop_pc);
582b725ae77Skettenis   else
583b725ae77Skettenis     find_objc_msgcall (stop_pc, &method_stop_pc);
584b725ae77Skettenis 
585b725ae77Skettenis   if (method_stop_pc)
586b725ae77Skettenis     {
587b725ae77Skettenis       real_stop_pc = SKIP_TRAMPOLINE_CODE (method_stop_pc);
588b725ae77Skettenis       if (real_stop_pc == 0)
589b725ae77Skettenis 	real_stop_pc = method_stop_pc;
590b725ae77Skettenis     }
591b725ae77Skettenis 
592b725ae77Skettenis   return real_stop_pc;
593b725ae77Skettenis }
594b725ae77Skettenis 
595b725ae77Skettenis 
596b725ae77Skettenis /* Table mapping opcodes into strings for printing operators
597b725ae77Skettenis    and precedences of the operators.  */
598b725ae77Skettenis 
599b725ae77Skettenis static const struct op_print objc_op_print_tab[] =
600b725ae77Skettenis   {
601b725ae77Skettenis     {",",  BINOP_COMMA, PREC_COMMA, 0},
602b725ae77Skettenis     {"=",  BINOP_ASSIGN, PREC_ASSIGN, 1},
603b725ae77Skettenis     {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
604b725ae77Skettenis     {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
605b725ae77Skettenis     {"|",  BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
606b725ae77Skettenis     {"^",  BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
607b725ae77Skettenis     {"&",  BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
608b725ae77Skettenis     {"==", BINOP_EQUAL, PREC_EQUAL, 0},
609b725ae77Skettenis     {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
610b725ae77Skettenis     {"<=", BINOP_LEQ, PREC_ORDER, 0},
611b725ae77Skettenis     {">=", BINOP_GEQ, PREC_ORDER, 0},
612b725ae77Skettenis     {">",  BINOP_GTR, PREC_ORDER, 0},
613b725ae77Skettenis     {"<",  BINOP_LESS, PREC_ORDER, 0},
614b725ae77Skettenis     {">>", BINOP_RSH, PREC_SHIFT, 0},
615b725ae77Skettenis     {"<<", BINOP_LSH, PREC_SHIFT, 0},
616b725ae77Skettenis     {"+",  BINOP_ADD, PREC_ADD, 0},
617b725ae77Skettenis     {"-",  BINOP_SUB, PREC_ADD, 0},
618b725ae77Skettenis     {"*",  BINOP_MUL, PREC_MUL, 0},
619b725ae77Skettenis     {"/",  BINOP_DIV, PREC_MUL, 0},
620b725ae77Skettenis     {"%",  BINOP_REM, PREC_MUL, 0},
621b725ae77Skettenis     {"@",  BINOP_REPEAT, PREC_REPEAT, 0},
622b725ae77Skettenis     {"-",  UNOP_NEG, PREC_PREFIX, 0},
623b725ae77Skettenis     {"!",  UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
624b725ae77Skettenis     {"~",  UNOP_COMPLEMENT, PREC_PREFIX, 0},
625b725ae77Skettenis     {"*",  UNOP_IND, PREC_PREFIX, 0},
626b725ae77Skettenis     {"&",  UNOP_ADDR, PREC_PREFIX, 0},
627b725ae77Skettenis     {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
628b725ae77Skettenis     {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
629b725ae77Skettenis     {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
630b725ae77Skettenis     {NULL, OP_NULL, PREC_NULL, 0}
631b725ae77Skettenis };
632b725ae77Skettenis 
633b725ae77Skettenis struct type ** const (objc_builtin_types[]) =
634b725ae77Skettenis {
635b725ae77Skettenis   &builtin_type_int,
636b725ae77Skettenis   &builtin_type_long,
637b725ae77Skettenis   &builtin_type_short,
638b725ae77Skettenis   &builtin_type_char,
639b725ae77Skettenis   &builtin_type_float,
640b725ae77Skettenis   &builtin_type_double,
641b725ae77Skettenis   &builtin_type_void,
642b725ae77Skettenis   &builtin_type_long_long,
643b725ae77Skettenis   &builtin_type_signed_char,
644b725ae77Skettenis   &builtin_type_unsigned_char,
645b725ae77Skettenis   &builtin_type_unsigned_short,
646b725ae77Skettenis   &builtin_type_unsigned_int,
647b725ae77Skettenis   &builtin_type_unsigned_long,
648b725ae77Skettenis   &builtin_type_unsigned_long_long,
649b725ae77Skettenis   &builtin_type_long_double,
650b725ae77Skettenis   &builtin_type_complex,
651b725ae77Skettenis   &builtin_type_double_complex,
652b725ae77Skettenis   0
653b725ae77Skettenis };
654b725ae77Skettenis 
655b725ae77Skettenis const struct language_defn objc_language_defn = {
656b725ae77Skettenis   "objective-c",		/* Language name */
657b725ae77Skettenis   language_objc,
658b725ae77Skettenis   objc_builtin_types,
659b725ae77Skettenis   range_check_off,
660b725ae77Skettenis   type_check_off,
661b725ae77Skettenis   case_sensitive_on,
662*11efff7fSkettenis   array_row_major,
663b725ae77Skettenis   &exp_descriptor_standard,
664b725ae77Skettenis   objc_parse,
665b725ae77Skettenis   objc_error,
666*11efff7fSkettenis   null_post_parser,
667b725ae77Skettenis   objc_printchar,		/* Print a character constant */
668b725ae77Skettenis   objc_printstr,		/* Function to print string constant */
669b725ae77Skettenis   objc_emit_char,
670b725ae77Skettenis   objc_create_fundamental_type,	/* Create fundamental type in this language */
671b725ae77Skettenis   c_print_type,			/* Print a type using appropriate syntax */
672b725ae77Skettenis   c_val_print,			/* Print a value using appropriate syntax */
673b725ae77Skettenis   c_value_print,		/* Print a top-level value */
674b725ae77Skettenis   objc_skip_trampoline, 	/* Language specific skip_trampoline */
675b725ae77Skettenis   value_of_this,		/* value_of_this */
676b725ae77Skettenis   basic_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
677b725ae77Skettenis   basic_lookup_transparent_type,/* lookup_transparent_type */
678b725ae77Skettenis   objc_demangle,		/* Language specific symbol demangler */
679*11efff7fSkettenis   NULL,				/* Language specific class_name_from_physname */
680b725ae77Skettenis   objc_op_print_tab,		/* Expression operators for printing */
681b725ae77Skettenis   1,				/* C-style arrays */
682b725ae77Skettenis   0,				/* String lower bound */
683b725ae77Skettenis   &builtin_type_char,		/* Type of string elements */
684b725ae77Skettenis   default_word_break_characters,
685*11efff7fSkettenis   NULL, /* FIXME: la_language_arch_info.  */
686b725ae77Skettenis   LANG_MAGIC
687b725ae77Skettenis };
688b725ae77Skettenis 
689b725ae77Skettenis /*
690b725ae77Skettenis  * ObjC:
691b725ae77Skettenis  * Following functions help construct Objective-C message calls
692b725ae77Skettenis  */
693b725ae77Skettenis 
694b725ae77Skettenis struct selname		/* For parsing Objective-C.  */
695b725ae77Skettenis   {
696b725ae77Skettenis     struct selname *next;
697b725ae77Skettenis     char *msglist_sel;
698b725ae77Skettenis     int msglist_len;
699b725ae77Skettenis   };
700b725ae77Skettenis 
701b725ae77Skettenis static int msglist_len;
702b725ae77Skettenis static struct selname *selname_chain;
703b725ae77Skettenis static char *msglist_sel;
704b725ae77Skettenis 
705b725ae77Skettenis void
start_msglist(void)706b725ae77Skettenis start_msglist(void)
707b725ae77Skettenis {
708b725ae77Skettenis   struct selname *new =
709b725ae77Skettenis     (struct selname *) xmalloc (sizeof (struct selname));
710b725ae77Skettenis 
711b725ae77Skettenis   new->next = selname_chain;
712b725ae77Skettenis   new->msglist_len = msglist_len;
713b725ae77Skettenis   new->msglist_sel = msglist_sel;
714b725ae77Skettenis   msglist_len = 0;
715b725ae77Skettenis   msglist_sel = (char *)xmalloc(1);
716b725ae77Skettenis   *msglist_sel = 0;
717b725ae77Skettenis   selname_chain = new;
718b725ae77Skettenis }
719b725ae77Skettenis 
720b725ae77Skettenis void
add_msglist(struct stoken * str,int addcolon)721b725ae77Skettenis add_msglist(struct stoken *str, int addcolon)
722b725ae77Skettenis {
723b725ae77Skettenis   char *s, *p;
724b725ae77Skettenis   int len, plen;
725b725ae77Skettenis 
726b725ae77Skettenis   if (str == 0) {		/* Unnamed arg, or...  */
727b725ae77Skettenis     if (addcolon == 0) {	/* variable number of args.  */
728b725ae77Skettenis       msglist_len++;
729b725ae77Skettenis       return;
730b725ae77Skettenis     }
731b725ae77Skettenis     p = "";
732b725ae77Skettenis     plen = 0;
733b725ae77Skettenis   } else {
734b725ae77Skettenis     p = str->ptr;
735b725ae77Skettenis     plen = str->length;
736b725ae77Skettenis   }
737b725ae77Skettenis   len = plen + strlen(msglist_sel) + 2;
738b725ae77Skettenis   s = (char *)xmalloc(len);
739b725ae77Skettenis   strcpy(s, msglist_sel);
740b725ae77Skettenis   strncat(s, p, plen);
741b725ae77Skettenis   xfree(msglist_sel);
742b725ae77Skettenis   msglist_sel = s;
743b725ae77Skettenis   if (addcolon) {
744b725ae77Skettenis     s[len-2] = ':';
745b725ae77Skettenis     s[len-1] = 0;
746b725ae77Skettenis     msglist_len++;
747b725ae77Skettenis   } else
748b725ae77Skettenis     s[len-2] = '\0';
749b725ae77Skettenis }
750b725ae77Skettenis 
751b725ae77Skettenis int
end_msglist(void)752b725ae77Skettenis end_msglist(void)
753b725ae77Skettenis {
754b725ae77Skettenis   int val = msglist_len;
755b725ae77Skettenis   struct selname *sel = selname_chain;
756b725ae77Skettenis   char *p = msglist_sel;
757b725ae77Skettenis   CORE_ADDR selid;
758b725ae77Skettenis 
759b725ae77Skettenis   selname_chain = sel->next;
760b725ae77Skettenis   msglist_len = sel->msglist_len;
761b725ae77Skettenis   msglist_sel = sel->msglist_sel;
762b725ae77Skettenis   selid = lookup_child_selector(p);
763b725ae77Skettenis   if (!selid)
764b725ae77Skettenis     error("Can't find selector \"%s\"", p);
765b725ae77Skettenis   write_exp_elt_longcst (selid);
766b725ae77Skettenis   xfree(p);
767b725ae77Skettenis   write_exp_elt_longcst (val);	/* Number of args */
768b725ae77Skettenis   xfree(sel);
769b725ae77Skettenis 
770b725ae77Skettenis   return val;
771b725ae77Skettenis }
772b725ae77Skettenis 
773b725ae77Skettenis /*
774b725ae77Skettenis  * Function: specialcmp (char *a, char *b)
775b725ae77Skettenis  *
776b725ae77Skettenis  * Special strcmp: treats ']' and ' ' as end-of-string.
777b725ae77Skettenis  * Used for qsorting lists of objc methods (either by class or selector).
778b725ae77Skettenis  */
779b725ae77Skettenis 
780b725ae77Skettenis static int
specialcmp(char * a,char * b)781b725ae77Skettenis specialcmp (char *a, char *b)
782b725ae77Skettenis {
783b725ae77Skettenis   while (*a && *a != ' ' && *a != ']' && *b && *b != ' ' && *b != ']')
784b725ae77Skettenis     {
785b725ae77Skettenis       if (*a != *b)
786b725ae77Skettenis 	return *a - *b;
787b725ae77Skettenis       a++, b++;
788b725ae77Skettenis     }
789b725ae77Skettenis   if (*a && *a != ' ' && *a != ']')
790b725ae77Skettenis     return  1;		/* a is longer therefore greater */
791b725ae77Skettenis   if (*b && *b != ' ' && *b != ']')
792b725ae77Skettenis     return -1;		/* a is shorter therefore lesser */
793b725ae77Skettenis   return    0;		/* a and b are identical */
794b725ae77Skettenis }
795b725ae77Skettenis 
796b725ae77Skettenis /*
797b725ae77Skettenis  * Function: compare_selectors (const void *, const void *)
798b725ae77Skettenis  *
799b725ae77Skettenis  * Comparison function for use with qsort.  Arguments are symbols or
800b725ae77Skettenis  * msymbols Compares selector part of objc method name alphabetically.
801b725ae77Skettenis  */
802b725ae77Skettenis 
803b725ae77Skettenis static int
compare_selectors(const void * a,const void * b)804b725ae77Skettenis compare_selectors (const void *a, const void *b)
805b725ae77Skettenis {
806b725ae77Skettenis   char *aname, *bname;
807b725ae77Skettenis 
808b725ae77Skettenis   aname = SYMBOL_PRINT_NAME (*(struct symbol **) a);
809b725ae77Skettenis   bname = SYMBOL_PRINT_NAME (*(struct symbol **) b);
810b725ae77Skettenis   if (aname == NULL || bname == NULL)
811b725ae77Skettenis     error ("internal: compare_selectors(1)");
812b725ae77Skettenis 
813b725ae77Skettenis   aname = strchr(aname, ' ');
814b725ae77Skettenis   bname = strchr(bname, ' ');
815b725ae77Skettenis   if (aname == NULL || bname == NULL)
816b725ae77Skettenis     error ("internal: compare_selectors(2)");
817b725ae77Skettenis 
818b725ae77Skettenis   return specialcmp (aname+1, bname+1);
819b725ae77Skettenis }
820b725ae77Skettenis 
821b725ae77Skettenis /*
822b725ae77Skettenis  * Function: selectors_info (regexp, from_tty)
823b725ae77Skettenis  *
824b725ae77Skettenis  * Implements the "Info selectors" command.  Takes an optional regexp
825b725ae77Skettenis  * arg.  Lists all objective c selectors that match the regexp.  Works
826b725ae77Skettenis  * by grepping thru all symbols for objective c methods.  Output list
827b725ae77Skettenis  * is sorted and uniqued.
828b725ae77Skettenis  */
829b725ae77Skettenis 
830b725ae77Skettenis static void
selectors_info(char * regexp,int from_tty)831b725ae77Skettenis selectors_info (char *regexp, int from_tty)
832b725ae77Skettenis {
833b725ae77Skettenis   struct objfile	*objfile;
834b725ae77Skettenis   struct minimal_symbol *msymbol;
835b725ae77Skettenis   char                  *name;
836b725ae77Skettenis   char                  *val;
837b725ae77Skettenis   int                    matches = 0;
838b725ae77Skettenis   int                    maxlen  = 0;
839b725ae77Skettenis   int                    ix;
840b725ae77Skettenis   char                   myregexp[2048];
841b725ae77Skettenis   char                   asel[256];
842b725ae77Skettenis   struct symbol        **sym_arr;
843b725ae77Skettenis   int                    plusminus = 0;
844b725ae77Skettenis 
845b725ae77Skettenis   if (regexp == NULL)
846b725ae77Skettenis     strcpy(myregexp, ".*]");	/* Null input, match all objc methods.  */
847b725ae77Skettenis   else
848b725ae77Skettenis     {
849b725ae77Skettenis       if (*regexp == '+' || *regexp == '-')
850b725ae77Skettenis 	{ /* User wants only class methods or only instance methods.  */
851b725ae77Skettenis 	  plusminus = *regexp++;
852b725ae77Skettenis 	  while (*regexp == ' ' || *regexp == '\t')
853b725ae77Skettenis 	    regexp++;
854b725ae77Skettenis 	}
855b725ae77Skettenis       if (*regexp == '\0')
856b725ae77Skettenis 	strcpy(myregexp, ".*]");
857b725ae77Skettenis       else
858b725ae77Skettenis 	{
859b725ae77Skettenis 	  strcpy(myregexp, regexp);
860b725ae77Skettenis 	  if (myregexp[strlen(myregexp) - 1] == '$') /* end of selector */
861b725ae77Skettenis 	    myregexp[strlen(myregexp) - 1] = ']';    /* end of method name */
862b725ae77Skettenis 	  else
863b725ae77Skettenis 	    strcat(myregexp, ".*]");
864b725ae77Skettenis 	}
865b725ae77Skettenis     }
866b725ae77Skettenis 
867b725ae77Skettenis   if (regexp != NULL)
868b725ae77Skettenis     {
869b725ae77Skettenis       val = re_comp (myregexp);
870b725ae77Skettenis       if (val != 0)
871b725ae77Skettenis 	error ("Invalid regexp (%s): %s", val, regexp);
872b725ae77Skettenis     }
873b725ae77Skettenis 
874b725ae77Skettenis   /* First time thru is JUST to get max length and count.  */
875b725ae77Skettenis   ALL_MSYMBOLS (objfile, msymbol)
876b725ae77Skettenis     {
877b725ae77Skettenis       QUIT;
878b725ae77Skettenis       name = SYMBOL_NATURAL_NAME (msymbol);
879b725ae77Skettenis       if (name &&
880b725ae77Skettenis 	 (name[0] == '-' || name[0] == '+') &&
881b725ae77Skettenis 	  name[1] == '[')		/* Got a method name.  */
882b725ae77Skettenis 	{
883b725ae77Skettenis 	  /* Filter for class/instance methods.  */
884b725ae77Skettenis 	  if (plusminus && name[0] != plusminus)
885b725ae77Skettenis 	    continue;
886b725ae77Skettenis 	  /* Find selector part.  */
887b725ae77Skettenis 	  name = (char *) strchr(name+2, ' ');
888b725ae77Skettenis 	  if (regexp == NULL || re_exec(++name) != 0)
889b725ae77Skettenis 	    {
890b725ae77Skettenis 	      char *mystart = name;
891b725ae77Skettenis 	      char *myend   = (char *) strchr(mystart, ']');
892b725ae77Skettenis 
893b725ae77Skettenis 	      if (myend && (myend - mystart > maxlen))
894b725ae77Skettenis 		maxlen = myend - mystart;	/* Get longest selector.  */
895b725ae77Skettenis 	      matches++;
896b725ae77Skettenis 	    }
897b725ae77Skettenis 	}
898b725ae77Skettenis     }
899b725ae77Skettenis   if (matches)
900b725ae77Skettenis     {
901b725ae77Skettenis       printf_filtered ("Selectors matching \"%s\":\n\n",
902b725ae77Skettenis 		       regexp ? regexp : "*");
903b725ae77Skettenis 
904b725ae77Skettenis       sym_arr = alloca (matches * sizeof (struct symbol *));
905b725ae77Skettenis       matches = 0;
906b725ae77Skettenis       ALL_MSYMBOLS (objfile, msymbol)
907b725ae77Skettenis 	{
908b725ae77Skettenis 	  QUIT;
909b725ae77Skettenis 	  name = SYMBOL_NATURAL_NAME (msymbol);
910b725ae77Skettenis 	  if (name &&
911b725ae77Skettenis 	     (name[0] == '-' || name[0] == '+') &&
912b725ae77Skettenis 	      name[1] == '[')		/* Got a method name.  */
913b725ae77Skettenis 	    {
914b725ae77Skettenis 	      /* Filter for class/instance methods.  */
915b725ae77Skettenis 	      if (plusminus && name[0] != plusminus)
916b725ae77Skettenis 		continue;
917b725ae77Skettenis 	      /* Find selector part.  */
918b725ae77Skettenis 	      name = (char *) strchr(name+2, ' ');
919b725ae77Skettenis 	      if (regexp == NULL || re_exec(++name) != 0)
920b725ae77Skettenis 		sym_arr[matches++] = (struct symbol *) msymbol;
921b725ae77Skettenis 	    }
922b725ae77Skettenis 	}
923b725ae77Skettenis 
924b725ae77Skettenis       qsort (sym_arr, matches, sizeof (struct minimal_symbol *),
925b725ae77Skettenis 	     compare_selectors);
926b725ae77Skettenis       /* Prevent compare on first iteration.  */
927b725ae77Skettenis       asel[0] = 0;
928b725ae77Skettenis       for (ix = 0; ix < matches; ix++)	/* Now do the output.  */
929b725ae77Skettenis 	{
930b725ae77Skettenis 	  char *p = asel;
931b725ae77Skettenis 
932b725ae77Skettenis 	  QUIT;
933b725ae77Skettenis 	  name = SYMBOL_NATURAL_NAME (sym_arr[ix]);
934b725ae77Skettenis 	  name = strchr (name, ' ') + 1;
935b725ae77Skettenis 	  if (p[0] && specialcmp(name, p) == 0)
936b725ae77Skettenis 	    continue;		/* Seen this one already (not unique).  */
937b725ae77Skettenis 
938b725ae77Skettenis 	  /* Copy selector part.  */
939b725ae77Skettenis 	  while (*name && *name != ']')
940b725ae77Skettenis 	    *p++ = *name++;
941b725ae77Skettenis 	  *p++ = '\0';
942b725ae77Skettenis 	  /* Print in columns.  */
943b725ae77Skettenis 	  puts_filtered_tabular(asel, maxlen + 1, 0);
944b725ae77Skettenis 	}
945b725ae77Skettenis       begin_line();
946b725ae77Skettenis     }
947b725ae77Skettenis   else
948b725ae77Skettenis     printf_filtered ("No selectors matching \"%s\"\n", regexp ? regexp : "*");
949b725ae77Skettenis }
950b725ae77Skettenis 
951b725ae77Skettenis /*
952b725ae77Skettenis  * Function: compare_classes (const void *, const void *)
953b725ae77Skettenis  *
954b725ae77Skettenis  * Comparison function for use with qsort.  Arguments are symbols or
955b725ae77Skettenis  * msymbols Compares class part of objc method name alphabetically.
956b725ae77Skettenis  */
957b725ae77Skettenis 
958b725ae77Skettenis static int
compare_classes(const void * a,const void * b)959b725ae77Skettenis compare_classes (const void *a, const void *b)
960b725ae77Skettenis {
961b725ae77Skettenis   char *aname, *bname;
962b725ae77Skettenis 
963b725ae77Skettenis   aname = SYMBOL_PRINT_NAME (*(struct symbol **) a);
964b725ae77Skettenis   bname = SYMBOL_PRINT_NAME (*(struct symbol **) b);
965b725ae77Skettenis   if (aname == NULL || bname == NULL)
966b725ae77Skettenis     error ("internal: compare_classes(1)");
967b725ae77Skettenis 
968b725ae77Skettenis   return specialcmp (aname+1, bname+1);
969b725ae77Skettenis }
970b725ae77Skettenis 
971b725ae77Skettenis /*
972b725ae77Skettenis  * Function: classes_info(regexp, from_tty)
973b725ae77Skettenis  *
974b725ae77Skettenis  * Implements the "info classes" command for objective c classes.
975b725ae77Skettenis  * Lists all objective c classes that match the optional regexp.
976b725ae77Skettenis  * Works by grepping thru the list of objective c methods.  List will
977b725ae77Skettenis  * be sorted and uniqued (since one class may have many methods).
978b725ae77Skettenis  * BUGS: will not list a class that has no methods.
979b725ae77Skettenis  */
980b725ae77Skettenis 
981b725ae77Skettenis static void
classes_info(char * regexp,int from_tty)982b725ae77Skettenis classes_info (char *regexp, int from_tty)
983b725ae77Skettenis {
984b725ae77Skettenis   struct objfile	*objfile;
985b725ae77Skettenis   struct minimal_symbol *msymbol;
986b725ae77Skettenis   char                  *name;
987b725ae77Skettenis   char                  *val;
988b725ae77Skettenis   int                    matches = 0;
989b725ae77Skettenis   int                    maxlen  = 0;
990b725ae77Skettenis   int                    ix;
991b725ae77Skettenis   char                   myregexp[2048];
992b725ae77Skettenis   char                   aclass[256];
993b725ae77Skettenis   struct symbol        **sym_arr;
994b725ae77Skettenis 
995b725ae77Skettenis   if (regexp == NULL)
996b725ae77Skettenis     strcpy(myregexp, ".* ");	/* Null input: match all objc classes.  */
997b725ae77Skettenis   else
998b725ae77Skettenis     {
999b725ae77Skettenis       strcpy(myregexp, regexp);
1000b725ae77Skettenis       if (myregexp[strlen(myregexp) - 1] == '$')
1001b725ae77Skettenis 	/* In the method name, the end of the class name is marked by ' '.  */
1002b725ae77Skettenis 	myregexp[strlen(myregexp) - 1] = ' ';
1003b725ae77Skettenis       else
1004b725ae77Skettenis 	strcat(myregexp, ".* ");
1005b725ae77Skettenis     }
1006b725ae77Skettenis 
1007b725ae77Skettenis   if (regexp != NULL)
1008b725ae77Skettenis     {
1009b725ae77Skettenis       val = re_comp (myregexp);
1010b725ae77Skettenis       if (val != 0)
1011b725ae77Skettenis 	error ("Invalid regexp (%s): %s", val, regexp);
1012b725ae77Skettenis     }
1013b725ae77Skettenis 
1014b725ae77Skettenis   /* First time thru is JUST to get max length and count.  */
1015b725ae77Skettenis   ALL_MSYMBOLS (objfile, msymbol)
1016b725ae77Skettenis     {
1017b725ae77Skettenis       QUIT;
1018b725ae77Skettenis       name = SYMBOL_NATURAL_NAME (msymbol);
1019b725ae77Skettenis       if (name &&
1020b725ae77Skettenis 	 (name[0] == '-' || name[0] == '+') &&
1021b725ae77Skettenis 	  name[1] == '[')			/* Got a method name.  */
1022b725ae77Skettenis 	if (regexp == NULL || re_exec(name+2) != 0)
1023b725ae77Skettenis 	  {
1024b725ae77Skettenis 	    /* Compute length of classname part.  */
1025b725ae77Skettenis 	    char *mystart = name + 2;
1026b725ae77Skettenis 	    char *myend   = (char *) strchr(mystart, ' ');
1027b725ae77Skettenis 
1028b725ae77Skettenis 	    if (myend && (myend - mystart > maxlen))
1029b725ae77Skettenis 	      maxlen = myend - mystart;
1030b725ae77Skettenis 	    matches++;
1031b725ae77Skettenis 	  }
1032b725ae77Skettenis     }
1033b725ae77Skettenis   if (matches)
1034b725ae77Skettenis     {
1035b725ae77Skettenis       printf_filtered ("Classes matching \"%s\":\n\n",
1036b725ae77Skettenis 		       regexp ? regexp : "*");
1037b725ae77Skettenis       sym_arr = alloca (matches * sizeof (struct symbol *));
1038b725ae77Skettenis       matches = 0;
1039b725ae77Skettenis       ALL_MSYMBOLS (objfile, msymbol)
1040b725ae77Skettenis 	{
1041b725ae77Skettenis 	  QUIT;
1042b725ae77Skettenis 	  name = SYMBOL_NATURAL_NAME (msymbol);
1043b725ae77Skettenis 	  if (name &&
1044b725ae77Skettenis 	     (name[0] == '-' || name[0] == '+') &&
1045b725ae77Skettenis 	      name[1] == '[')			/* Got a method name.  */
1046b725ae77Skettenis 	    if (regexp == NULL || re_exec(name+2) != 0)
1047b725ae77Skettenis 		sym_arr[matches++] = (struct symbol *) msymbol;
1048b725ae77Skettenis 	}
1049b725ae77Skettenis 
1050b725ae77Skettenis       qsort (sym_arr, matches, sizeof (struct minimal_symbol *),
1051b725ae77Skettenis 	     compare_classes);
1052b725ae77Skettenis       /* Prevent compare on first iteration.  */
1053b725ae77Skettenis       aclass[0] = 0;
1054b725ae77Skettenis       for (ix = 0; ix < matches; ix++)	/* Now do the output.  */
1055b725ae77Skettenis 	{
1056b725ae77Skettenis 	  char *p = aclass;
1057b725ae77Skettenis 
1058b725ae77Skettenis 	  QUIT;
1059b725ae77Skettenis 	  name = SYMBOL_NATURAL_NAME (sym_arr[ix]);
1060b725ae77Skettenis 	  name += 2;
1061b725ae77Skettenis 	  if (p[0] && specialcmp(name, p) == 0)
1062b725ae77Skettenis 	    continue;	/* Seen this one already (not unique).  */
1063b725ae77Skettenis 
1064b725ae77Skettenis 	  /* Copy class part of method name.  */
1065b725ae77Skettenis 	  while (*name && *name != ' ')
1066b725ae77Skettenis 	    *p++ = *name++;
1067b725ae77Skettenis 	  *p++ = '\0';
1068b725ae77Skettenis 	  /* Print in columns.  */
1069b725ae77Skettenis 	  puts_filtered_tabular(aclass, maxlen + 1, 0);
1070b725ae77Skettenis 	}
1071b725ae77Skettenis       begin_line();
1072b725ae77Skettenis     }
1073b725ae77Skettenis   else
1074b725ae77Skettenis     printf_filtered ("No classes matching \"%s\"\n", regexp ? regexp : "*");
1075b725ae77Skettenis }
1076b725ae77Skettenis 
1077b725ae77Skettenis /*
1078b725ae77Skettenis  * Function: find_imps (char *selector, struct symbol **sym_arr)
1079b725ae77Skettenis  *
1080b725ae77Skettenis  * Input:  a string representing a selector
1081b725ae77Skettenis  *         a pointer to an array of symbol pointers
1082b725ae77Skettenis  *         possibly a pointer to a symbol found by the caller.
1083b725ae77Skettenis  *
1084b725ae77Skettenis  * Output: number of methods that implement that selector.  Side
1085b725ae77Skettenis  * effects: The array of symbol pointers is filled with matching syms.
1086b725ae77Skettenis  *
1087b725ae77Skettenis  * By analogy with function "find_methods" (symtab.c), builds a list
1088b725ae77Skettenis  * of symbols matching the ambiguous input, so that "decode_line_2"
1089b725ae77Skettenis  * (symtab.c) can list them and ask the user to choose one or more.
1090b725ae77Skettenis  * In this case the matches are objective c methods
1091b725ae77Skettenis  * ("implementations") matching an objective c selector.
1092b725ae77Skettenis  *
1093b725ae77Skettenis  * Note that it is possible for a normal (c-style) function to have
1094b725ae77Skettenis  * the same name as an objective c selector.  To prevent the selector
1095b725ae77Skettenis  * from eclipsing the function, we allow the caller (decode_line_1) to
1096b725ae77Skettenis  * search for such a function first, and if it finds one, pass it in
1097b725ae77Skettenis  * to us.  We will then integrate it into the list.  We also search
1098b725ae77Skettenis  * for one here, among the minsyms.
1099b725ae77Skettenis  *
1100b725ae77Skettenis  * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
1101b725ae77Skettenis  *       into two parts: debuggable (struct symbol) syms, and
1102b725ae77Skettenis  *       non_debuggable (struct minimal_symbol) syms.  The debuggable
1103b725ae77Skettenis  *       ones will come first, before NUM_DEBUGGABLE (which will thus
1104b725ae77Skettenis  *       be the index of the first non-debuggable one).
1105b725ae77Skettenis  */
1106b725ae77Skettenis 
1107b725ae77Skettenis /*
1108b725ae77Skettenis  * Function: total_number_of_imps (char *selector);
1109b725ae77Skettenis  *
1110b725ae77Skettenis  * Input:  a string representing a selector
1111b725ae77Skettenis  * Output: number of methods that implement that selector.
1112b725ae77Skettenis  *
1113b725ae77Skettenis  * By analogy with function "total_number_of_methods", this allows
1114b725ae77Skettenis  * decode_line_1 (symtab.c) to detect if there are objective c methods
1115b725ae77Skettenis  * matching the input, and to allocate an array of pointers to them
1116b725ae77Skettenis  * which can be manipulated by "decode_line_2" (also in symtab.c).
1117b725ae77Skettenis  */
1118b725ae77Skettenis 
1119b725ae77Skettenis char *
parse_selector(char * method,char ** selector)1120b725ae77Skettenis parse_selector (char *method, char **selector)
1121b725ae77Skettenis {
1122b725ae77Skettenis   char *s1 = NULL;
1123b725ae77Skettenis   char *s2 = NULL;
1124b725ae77Skettenis   int found_quote = 0;
1125b725ae77Skettenis 
1126b725ae77Skettenis   char *nselector = NULL;
1127b725ae77Skettenis 
1128b725ae77Skettenis   gdb_assert (selector != NULL);
1129b725ae77Skettenis 
1130b725ae77Skettenis   s1 = method;
1131b725ae77Skettenis 
1132b725ae77Skettenis   while (isspace (*s1))
1133b725ae77Skettenis     s1++;
1134b725ae77Skettenis   if (*s1 == '\'')
1135b725ae77Skettenis     {
1136b725ae77Skettenis       found_quote = 1;
1137b725ae77Skettenis       s1++;
1138b725ae77Skettenis     }
1139b725ae77Skettenis   while (isspace (*s1))
1140b725ae77Skettenis     s1++;
1141b725ae77Skettenis 
1142b725ae77Skettenis   nselector = s1;
1143b725ae77Skettenis   s2 = s1;
1144b725ae77Skettenis 
1145b725ae77Skettenis   for (;;) {
1146b725ae77Skettenis     if (isalnum (*s2) || (*s2 == '_') || (*s2 == ':'))
1147b725ae77Skettenis       *s1++ = *s2;
1148b725ae77Skettenis     else if (isspace (*s2))
1149b725ae77Skettenis       ;
1150b725ae77Skettenis     else if ((*s2 == '\0') || (*s2 == '\''))
1151b725ae77Skettenis       break;
1152b725ae77Skettenis     else
1153b725ae77Skettenis       return NULL;
1154b725ae77Skettenis     s2++;
1155b725ae77Skettenis   }
1156b725ae77Skettenis   *s1++ = '\0';
1157b725ae77Skettenis 
1158b725ae77Skettenis   while (isspace (*s2))
1159b725ae77Skettenis     s2++;
1160b725ae77Skettenis   if (found_quote)
1161b725ae77Skettenis     {
1162b725ae77Skettenis       if (*s2 == '\'')
1163b725ae77Skettenis 	s2++;
1164b725ae77Skettenis       while (isspace (*s2))
1165b725ae77Skettenis 	s2++;
1166b725ae77Skettenis     }
1167b725ae77Skettenis 
1168b725ae77Skettenis   if (selector != NULL)
1169b725ae77Skettenis     *selector = nselector;
1170b725ae77Skettenis 
1171b725ae77Skettenis   return s2;
1172b725ae77Skettenis }
1173b725ae77Skettenis 
1174b725ae77Skettenis char *
parse_method(char * method,char * type,char ** class,char ** category,char ** selector)1175b725ae77Skettenis parse_method (char *method, char *type, char **class,
1176b725ae77Skettenis 	      char **category, char **selector)
1177b725ae77Skettenis {
1178b725ae77Skettenis   char *s1 = NULL;
1179b725ae77Skettenis   char *s2 = NULL;
1180b725ae77Skettenis   int found_quote = 0;
1181b725ae77Skettenis 
1182b725ae77Skettenis   char ntype = '\0';
1183b725ae77Skettenis   char *nclass = NULL;
1184b725ae77Skettenis   char *ncategory = NULL;
1185b725ae77Skettenis   char *nselector = NULL;
1186b725ae77Skettenis 
1187b725ae77Skettenis   gdb_assert (type != NULL);
1188b725ae77Skettenis   gdb_assert (class != NULL);
1189b725ae77Skettenis   gdb_assert (category != NULL);
1190b725ae77Skettenis   gdb_assert (selector != NULL);
1191b725ae77Skettenis 
1192b725ae77Skettenis   s1 = method;
1193b725ae77Skettenis 
1194b725ae77Skettenis   while (isspace (*s1))
1195b725ae77Skettenis     s1++;
1196b725ae77Skettenis   if (*s1 == '\'')
1197b725ae77Skettenis     {
1198b725ae77Skettenis       found_quote = 1;
1199b725ae77Skettenis       s1++;
1200b725ae77Skettenis     }
1201b725ae77Skettenis   while (isspace (*s1))
1202b725ae77Skettenis     s1++;
1203b725ae77Skettenis 
1204b725ae77Skettenis   if ((s1[0] == '+') || (s1[0] == '-'))
1205b725ae77Skettenis     ntype = *s1++;
1206b725ae77Skettenis 
1207b725ae77Skettenis   while (isspace (*s1))
1208b725ae77Skettenis     s1++;
1209b725ae77Skettenis 
1210b725ae77Skettenis   if (*s1 != '[')
1211b725ae77Skettenis     return NULL;
1212b725ae77Skettenis   s1++;
1213b725ae77Skettenis 
1214b725ae77Skettenis   nclass = s1;
1215b725ae77Skettenis   while (isalnum (*s1) || (*s1 == '_'))
1216b725ae77Skettenis     s1++;
1217b725ae77Skettenis 
1218b725ae77Skettenis   s2 = s1;
1219b725ae77Skettenis   while (isspace (*s2))
1220b725ae77Skettenis     s2++;
1221b725ae77Skettenis 
1222b725ae77Skettenis   if (*s2 == '(')
1223b725ae77Skettenis     {
1224b725ae77Skettenis       s2++;
1225b725ae77Skettenis       while (isspace (*s2))
1226b725ae77Skettenis 	s2++;
1227b725ae77Skettenis       ncategory = s2;
1228b725ae77Skettenis       while (isalnum (*s2) || (*s2 == '_'))
1229b725ae77Skettenis 	s2++;
1230b725ae77Skettenis       *s2++ = '\0';
1231b725ae77Skettenis     }
1232b725ae77Skettenis 
1233b725ae77Skettenis   /* Truncate the class name now that we're not using the open paren.  */
1234b725ae77Skettenis   *s1++ = '\0';
1235b725ae77Skettenis 
1236b725ae77Skettenis   nselector = s2;
1237b725ae77Skettenis   s1 = s2;
1238b725ae77Skettenis 
1239b725ae77Skettenis   for (;;) {
1240b725ae77Skettenis     if (isalnum (*s2) || (*s2 == '_') || (*s2 == ':'))
1241b725ae77Skettenis       *s1++ = *s2;
1242b725ae77Skettenis     else if (isspace (*s2))
1243b725ae77Skettenis       ;
1244b725ae77Skettenis     else if (*s2 == ']')
1245b725ae77Skettenis       break;
1246b725ae77Skettenis     else
1247b725ae77Skettenis       return NULL;
1248b725ae77Skettenis     s2++;
1249b725ae77Skettenis   }
1250b725ae77Skettenis   *s1++ = '\0';
1251b725ae77Skettenis   s2++;
1252b725ae77Skettenis 
1253b725ae77Skettenis   while (isspace (*s2))
1254b725ae77Skettenis     s2++;
1255b725ae77Skettenis   if (found_quote)
1256b725ae77Skettenis     {
1257b725ae77Skettenis       if (*s2 != '\'')
1258b725ae77Skettenis 	return NULL;
1259b725ae77Skettenis       s2++;
1260b725ae77Skettenis       while (isspace (*s2))
1261b725ae77Skettenis 	s2++;
1262b725ae77Skettenis     }
1263b725ae77Skettenis 
1264b725ae77Skettenis   if (type != NULL)
1265b725ae77Skettenis     *type = ntype;
1266b725ae77Skettenis   if (class != NULL)
1267b725ae77Skettenis     *class = nclass;
1268b725ae77Skettenis   if (category != NULL)
1269b725ae77Skettenis     *category = ncategory;
1270b725ae77Skettenis   if (selector != NULL)
1271b725ae77Skettenis     *selector = nselector;
1272b725ae77Skettenis 
1273b725ae77Skettenis   return s2;
1274b725ae77Skettenis }
1275b725ae77Skettenis 
1276b725ae77Skettenis static void
find_methods(struct symtab * symtab,char type,const char * class,const char * category,const char * selector,struct symbol ** syms,unsigned int * nsym,unsigned int * ndebug)1277b725ae77Skettenis find_methods (struct symtab *symtab, char type,
1278b725ae77Skettenis 	      const char *class, const char *category,
1279b725ae77Skettenis 	      const char *selector, struct symbol **syms,
1280b725ae77Skettenis 	      unsigned int *nsym, unsigned int *ndebug)
1281b725ae77Skettenis {
1282b725ae77Skettenis   struct objfile *objfile = NULL;
1283b725ae77Skettenis   struct minimal_symbol *msymbol = NULL;
1284b725ae77Skettenis   struct block *block = NULL;
1285b725ae77Skettenis   struct symbol *sym = NULL;
1286b725ae77Skettenis 
1287b725ae77Skettenis   char *symname = NULL;
1288b725ae77Skettenis 
1289b725ae77Skettenis   char ntype = '\0';
1290b725ae77Skettenis   char *nclass = NULL;
1291b725ae77Skettenis   char *ncategory = NULL;
1292b725ae77Skettenis   char *nselector = NULL;
1293b725ae77Skettenis 
1294b725ae77Skettenis   unsigned int csym = 0;
1295b725ae77Skettenis   unsigned int cdebug = 0;
1296b725ae77Skettenis 
1297b725ae77Skettenis   static char *tmp = NULL;
1298b725ae77Skettenis   static unsigned int tmplen = 0;
1299b725ae77Skettenis 
1300b725ae77Skettenis   gdb_assert (nsym != NULL);
1301b725ae77Skettenis   gdb_assert (ndebug != NULL);
1302b725ae77Skettenis 
1303b725ae77Skettenis   if (symtab)
1304b725ae77Skettenis     block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
1305b725ae77Skettenis 
1306b725ae77Skettenis   ALL_MSYMBOLS (objfile, msymbol)
1307b725ae77Skettenis     {
1308b725ae77Skettenis       QUIT;
1309b725ae77Skettenis 
1310b725ae77Skettenis       if ((msymbol->type != mst_text) && (msymbol->type != mst_file_text))
1311b725ae77Skettenis 	/* Not a function or method.  */
1312b725ae77Skettenis 	continue;
1313b725ae77Skettenis 
1314b725ae77Skettenis       if (symtab)
1315b725ae77Skettenis 	if ((SYMBOL_VALUE_ADDRESS (msymbol) <  BLOCK_START (block)) ||
1316b725ae77Skettenis 	    (SYMBOL_VALUE_ADDRESS (msymbol) >= BLOCK_END (block)))
1317b725ae77Skettenis 	  /* Not in the specified symtab.  */
1318b725ae77Skettenis 	  continue;
1319b725ae77Skettenis 
1320b725ae77Skettenis       symname = SYMBOL_NATURAL_NAME (msymbol);
1321b725ae77Skettenis       if (symname == NULL)
1322b725ae77Skettenis 	continue;
1323b725ae77Skettenis 
1324b725ae77Skettenis       if ((symname[0] != '-' && symname[0] != '+') || (symname[1] != '['))
1325b725ae77Skettenis 	/* Not a method name.  */
1326b725ae77Skettenis 	continue;
1327b725ae77Skettenis 
1328b725ae77Skettenis       while ((strlen (symname) + 1) >= tmplen)
1329b725ae77Skettenis 	{
1330b725ae77Skettenis 	  tmplen = (tmplen == 0) ? 1024 : tmplen * 2;
1331b725ae77Skettenis 	  tmp = xrealloc (tmp, tmplen);
1332b725ae77Skettenis 	}
1333b725ae77Skettenis       strcpy (tmp, symname);
1334b725ae77Skettenis 
1335b725ae77Skettenis       if (parse_method (tmp, &ntype, &nclass, &ncategory, &nselector) == NULL)
1336b725ae77Skettenis 	continue;
1337b725ae77Skettenis 
1338b725ae77Skettenis       if ((type != '\0') && (ntype != type))
1339b725ae77Skettenis 	continue;
1340b725ae77Skettenis 
1341b725ae77Skettenis       if ((class != NULL)
1342b725ae77Skettenis 	  && ((nclass == NULL) || (strcmp (class, nclass) != 0)))
1343b725ae77Skettenis 	continue;
1344b725ae77Skettenis 
1345b725ae77Skettenis       if ((category != NULL) &&
1346b725ae77Skettenis 	  ((ncategory == NULL) || (strcmp (category, ncategory) != 0)))
1347b725ae77Skettenis 	continue;
1348b725ae77Skettenis 
1349b725ae77Skettenis       if ((selector != NULL) &&
1350b725ae77Skettenis 	  ((nselector == NULL) || (strcmp (selector, nselector) != 0)))
1351b725ae77Skettenis 	continue;
1352b725ae77Skettenis 
1353b725ae77Skettenis       sym = find_pc_function (SYMBOL_VALUE_ADDRESS (msymbol));
1354b725ae77Skettenis       if (sym != NULL)
1355b725ae77Skettenis         {
1356b725ae77Skettenis           const char *newsymname = SYMBOL_NATURAL_NAME (sym);
1357b725ae77Skettenis 
1358b725ae77Skettenis           if (strcmp (symname, newsymname) == 0)
1359b725ae77Skettenis             {
1360b725ae77Skettenis               /* Found a high-level method sym: swap it into the
1361b725ae77Skettenis                  lower part of sym_arr (below num_debuggable).  */
1362b725ae77Skettenis               if (syms != NULL)
1363b725ae77Skettenis                 {
1364b725ae77Skettenis                   syms[csym] = syms[cdebug];
1365b725ae77Skettenis                   syms[cdebug] = sym;
1366b725ae77Skettenis                 }
1367b725ae77Skettenis               csym++;
1368b725ae77Skettenis               cdebug++;
1369b725ae77Skettenis             }
1370b725ae77Skettenis           else
1371b725ae77Skettenis             {
1372b725ae77Skettenis               warning (
1373b725ae77Skettenis "debugging symbol \"%s\" does not match minimal symbol (\"%s\"); ignoring",
1374b725ae77Skettenis                        newsymname, symname);
1375b725ae77Skettenis               if (syms != NULL)
1376b725ae77Skettenis                 syms[csym] = (struct symbol *) msymbol;
1377b725ae77Skettenis               csym++;
1378b725ae77Skettenis             }
1379b725ae77Skettenis         }
1380b725ae77Skettenis       else
1381b725ae77Skettenis 	{
1382b725ae77Skettenis 	  /* Found a non-debuggable method symbol.  */
1383b725ae77Skettenis 	  if (syms != NULL)
1384b725ae77Skettenis 	    syms[csym] = (struct symbol *) msymbol;
1385b725ae77Skettenis 	  csym++;
1386b725ae77Skettenis 	}
1387b725ae77Skettenis     }
1388b725ae77Skettenis 
1389b725ae77Skettenis   if (nsym != NULL)
1390b725ae77Skettenis     *nsym = csym;
1391b725ae77Skettenis   if (ndebug != NULL)
1392b725ae77Skettenis     *ndebug = cdebug;
1393b725ae77Skettenis }
1394b725ae77Skettenis 
find_imps(struct symtab * symtab,struct block * block,char * method,struct symbol ** syms,unsigned int * nsym,unsigned int * ndebug)1395b725ae77Skettenis char *find_imps (struct symtab *symtab, struct block *block,
1396b725ae77Skettenis 		 char *method, struct symbol **syms,
1397b725ae77Skettenis 		 unsigned int *nsym, unsigned int *ndebug)
1398b725ae77Skettenis {
1399b725ae77Skettenis   char type = '\0';
1400b725ae77Skettenis   char *class = NULL;
1401b725ae77Skettenis   char *category = NULL;
1402b725ae77Skettenis   char *selector = NULL;
1403b725ae77Skettenis 
1404b725ae77Skettenis   unsigned int csym = 0;
1405b725ae77Skettenis   unsigned int cdebug = 0;
1406b725ae77Skettenis 
1407b725ae77Skettenis   unsigned int ncsym = 0;
1408b725ae77Skettenis   unsigned int ncdebug = 0;
1409b725ae77Skettenis 
1410b725ae77Skettenis   char *buf = NULL;
1411b725ae77Skettenis   char *tmp = NULL;
1412b725ae77Skettenis 
1413b725ae77Skettenis   gdb_assert (nsym != NULL);
1414b725ae77Skettenis   gdb_assert (ndebug != NULL);
1415b725ae77Skettenis 
1416b725ae77Skettenis   if (nsym != NULL)
1417b725ae77Skettenis     *nsym = 0;
1418b725ae77Skettenis   if (ndebug != NULL)
1419b725ae77Skettenis     *ndebug = 0;
1420b725ae77Skettenis 
1421b725ae77Skettenis   buf = (char *) alloca (strlen (method) + 1);
1422b725ae77Skettenis   strcpy (buf, method);
1423b725ae77Skettenis   tmp = parse_method (buf, &type, &class, &category, &selector);
1424b725ae77Skettenis 
1425b725ae77Skettenis   if (tmp == NULL) {
1426b725ae77Skettenis 
1427b725ae77Skettenis     struct symbol *sym = NULL;
1428b725ae77Skettenis     struct minimal_symbol *msym = NULL;
1429b725ae77Skettenis 
1430b725ae77Skettenis     strcpy (buf, method);
1431b725ae77Skettenis     tmp = parse_selector (buf, &selector);
1432b725ae77Skettenis 
1433b725ae77Skettenis     if (tmp == NULL)
1434b725ae77Skettenis       return NULL;
1435b725ae77Skettenis 
1436b725ae77Skettenis     sym = lookup_symbol (selector, block, VAR_DOMAIN, 0, NULL);
1437b725ae77Skettenis     if (sym != NULL)
1438b725ae77Skettenis       {
1439b725ae77Skettenis 	if (syms)
1440b725ae77Skettenis 	  syms[csym] = sym;
1441b725ae77Skettenis 	csym++;
1442b725ae77Skettenis 	cdebug++;
1443b725ae77Skettenis       }
1444b725ae77Skettenis 
1445b725ae77Skettenis     if (sym == NULL)
1446b725ae77Skettenis       msym = lookup_minimal_symbol (selector, 0, 0);
1447b725ae77Skettenis 
1448b725ae77Skettenis     if (msym != NULL)
1449b725ae77Skettenis       {
1450b725ae77Skettenis 	if (syms)
1451b725ae77Skettenis 	  syms[csym] = (struct symbol *)msym;
1452b725ae77Skettenis 	csym++;
1453b725ae77Skettenis       }
1454b725ae77Skettenis   }
1455b725ae77Skettenis 
1456b725ae77Skettenis   if (syms != NULL)
1457b725ae77Skettenis     find_methods (symtab, type, class, category, selector,
1458b725ae77Skettenis 		  syms + csym, &ncsym, &ncdebug);
1459b725ae77Skettenis   else
1460b725ae77Skettenis     find_methods (symtab, type, class, category, selector,
1461b725ae77Skettenis 		  NULL, &ncsym, &ncdebug);
1462b725ae77Skettenis 
1463b725ae77Skettenis   /* If we didn't find any methods, just return.  */
1464b725ae77Skettenis   if (ncsym == 0 && ncdebug == 0)
1465b725ae77Skettenis     return method;
1466b725ae77Skettenis 
1467b725ae77Skettenis   /* Take debug symbols from the second batch of symbols and swap them
1468b725ae77Skettenis    * with debug symbols from the first batch.  Repeat until either the
1469b725ae77Skettenis    * second section is out of debug symbols or the first section is
1470b725ae77Skettenis    * full of debug symbols.  Either way we have all debug symbols
1471b725ae77Skettenis    * packed to the beginning of the buffer.
1472b725ae77Skettenis    */
1473b725ae77Skettenis 
1474b725ae77Skettenis   if (syms != NULL)
1475b725ae77Skettenis     {
1476b725ae77Skettenis       while ((cdebug < csym) && (ncdebug > 0))
1477b725ae77Skettenis 	{
1478b725ae77Skettenis 	  struct symbol *s = NULL;
1479b725ae77Skettenis 	  /* First non-debugging symbol.  */
1480b725ae77Skettenis 	  unsigned int i = cdebug;
1481b725ae77Skettenis 	  /* Last of second batch of debug symbols.  */
1482b725ae77Skettenis 	  unsigned int j = csym + ncdebug - 1;
1483b725ae77Skettenis 
1484b725ae77Skettenis 	  s = syms[j];
1485b725ae77Skettenis 	  syms[j] = syms[i];
1486b725ae77Skettenis 	  syms[i] = s;
1487b725ae77Skettenis 
1488b725ae77Skettenis 	  /* We've moved a symbol from the second debug section to the
1489b725ae77Skettenis              first one.  */
1490b725ae77Skettenis 	  cdebug++;
1491b725ae77Skettenis 	  ncdebug--;
1492b725ae77Skettenis 	}
1493b725ae77Skettenis     }
1494b725ae77Skettenis 
1495b725ae77Skettenis   csym += ncsym;
1496b725ae77Skettenis   cdebug += ncdebug;
1497b725ae77Skettenis 
1498b725ae77Skettenis   if (nsym != NULL)
1499b725ae77Skettenis     *nsym = csym;
1500b725ae77Skettenis   if (ndebug != NULL)
1501b725ae77Skettenis     *ndebug = cdebug;
1502b725ae77Skettenis 
1503b725ae77Skettenis   if (syms == NULL)
1504b725ae77Skettenis     return method + (tmp - buf);
1505b725ae77Skettenis 
1506b725ae77Skettenis   if (csym > 1)
1507b725ae77Skettenis     {
1508b725ae77Skettenis       /* Sort debuggable symbols.  */
1509b725ae77Skettenis       if (cdebug > 1)
1510b725ae77Skettenis 	qsort (syms, cdebug, sizeof (struct minimal_symbol *),
1511b725ae77Skettenis 	       compare_classes);
1512b725ae77Skettenis 
1513b725ae77Skettenis       /* Sort minimal_symbols.  */
1514b725ae77Skettenis       if ((csym - cdebug) > 1)
1515b725ae77Skettenis 	qsort (&syms[cdebug], csym - cdebug,
1516b725ae77Skettenis 	       sizeof (struct minimal_symbol *), compare_classes);
1517b725ae77Skettenis     }
1518b725ae77Skettenis   /* Terminate the sym_arr list.  */
1519b725ae77Skettenis   syms[csym] = 0;
1520b725ae77Skettenis 
1521b725ae77Skettenis   return method + (tmp - buf);
1522b725ae77Skettenis }
1523b725ae77Skettenis 
1524b725ae77Skettenis static void
print_object_command(char * args,int from_tty)1525b725ae77Skettenis print_object_command (char *args, int from_tty)
1526b725ae77Skettenis {
1527b725ae77Skettenis   struct value *object, *function, *description;
1528b725ae77Skettenis   CORE_ADDR string_addr, object_addr;
1529b725ae77Skettenis   int i = 0;
1530b725ae77Skettenis   char c = -1;
1531b725ae77Skettenis 
1532b725ae77Skettenis   if (!args || !*args)
1533b725ae77Skettenis     error (
1534b725ae77Skettenis "The 'print-object' command requires an argument (an Objective-C object)");
1535b725ae77Skettenis 
1536b725ae77Skettenis   {
1537b725ae77Skettenis     struct expression *expr = parse_expression (args);
1538b725ae77Skettenis     struct cleanup *old_chain =
1539b725ae77Skettenis       make_cleanup (free_current_contents, &expr);
1540b725ae77Skettenis     int pc = 0;
1541b725ae77Skettenis 
1542b725ae77Skettenis     object = expr->language_defn->la_exp_desc->evaluate_exp
1543b725ae77Skettenis       (builtin_type_void_data_ptr, expr, &pc, EVAL_NORMAL);
1544b725ae77Skettenis     do_cleanups (old_chain);
1545b725ae77Skettenis   }
1546b725ae77Skettenis 
1547b725ae77Skettenis   /* Validate the address for sanity.  */
1548b725ae77Skettenis   object_addr = value_as_long (object);
1549b725ae77Skettenis   read_memory (object_addr, &c, 1);
1550b725ae77Skettenis 
1551b725ae77Skettenis   function = find_function_in_inferior ("_NSPrintForDebugger");
1552b725ae77Skettenis   if (function == NULL)
1553b725ae77Skettenis     error ("Unable to locate _NSPrintForDebugger in child process");
1554b725ae77Skettenis 
1555b725ae77Skettenis   description = call_function_by_hand (function, 1, &object);
1556b725ae77Skettenis 
1557b725ae77Skettenis   string_addr = value_as_long (description);
1558b725ae77Skettenis   if (string_addr == 0)
1559b725ae77Skettenis     error ("object returns null description");
1560b725ae77Skettenis 
1561b725ae77Skettenis   read_memory (string_addr + i++, &c, 1);
1562b725ae77Skettenis   if (c != '\0')
1563b725ae77Skettenis     do
1564b725ae77Skettenis       { /* Read and print characters up to EOS.  */
1565b725ae77Skettenis 	QUIT;
1566b725ae77Skettenis 	printf_filtered ("%c", c);
1567b725ae77Skettenis 	read_memory (string_addr + i++, &c, 1);
1568b725ae77Skettenis       } while (c != 0);
1569b725ae77Skettenis   else
1570b725ae77Skettenis     printf_filtered("<object returns empty description>");
1571b725ae77Skettenis   printf_filtered ("\n");
1572b725ae77Skettenis }
1573b725ae77Skettenis 
1574b725ae77Skettenis /* The data structure 'methcalls' is used to detect method calls (thru
1575b725ae77Skettenis  * ObjC runtime lib functions objc_msgSend, objc_msgSendSuper, etc.),
1576b725ae77Skettenis  * and ultimately find the method being called.
1577b725ae77Skettenis  */
1578b725ae77Skettenis 
1579b725ae77Skettenis struct objc_methcall {
1580b725ae77Skettenis   char *name;
1581b725ae77Skettenis  /* Return instance method to be called.  */
1582b725ae77Skettenis   int (*stop_at) (CORE_ADDR, CORE_ADDR *);
1583b725ae77Skettenis   /* Start of pc range corresponding to method invocation.  */
1584b725ae77Skettenis   CORE_ADDR begin;
1585b725ae77Skettenis   /* End of pc range corresponding to method invocation.  */
1586b725ae77Skettenis   CORE_ADDR end;
1587b725ae77Skettenis };
1588b725ae77Skettenis 
1589b725ae77Skettenis static int resolve_msgsend (CORE_ADDR pc, CORE_ADDR *new_pc);
1590b725ae77Skettenis static int resolve_msgsend_stret (CORE_ADDR pc, CORE_ADDR *new_pc);
1591b725ae77Skettenis static int resolve_msgsend_super (CORE_ADDR pc, CORE_ADDR *new_pc);
1592b725ae77Skettenis static int resolve_msgsend_super_stret (CORE_ADDR pc, CORE_ADDR *new_pc);
1593b725ae77Skettenis 
1594b725ae77Skettenis static struct objc_methcall methcalls[] = {
1595b725ae77Skettenis   { "_objc_msgSend", resolve_msgsend, 0, 0},
1596b725ae77Skettenis   { "_objc_msgSend_stret", resolve_msgsend_stret, 0, 0},
1597b725ae77Skettenis   { "_objc_msgSendSuper", resolve_msgsend_super, 0, 0},
1598b725ae77Skettenis   { "_objc_msgSendSuper_stret", resolve_msgsend_super_stret, 0, 0},
1599b725ae77Skettenis   { "_objc_getClass", NULL, 0, 0},
1600b725ae77Skettenis   { "_objc_getMetaClass", NULL, 0, 0}
1601b725ae77Skettenis };
1602b725ae77Skettenis 
1603b725ae77Skettenis #define nmethcalls (sizeof (methcalls) / sizeof (methcalls[0]))
1604b725ae77Skettenis 
1605b725ae77Skettenis /* The following function, "find_objc_msgsend", fills in the data
1606b725ae77Skettenis  * structure "objc_msgs" by finding the addresses of each of the
1607b725ae77Skettenis  * (currently four) functions that it holds (of which objc_msgSend is
1608b725ae77Skettenis  * the first).  This must be called each time symbols are loaded, in
1609b725ae77Skettenis  * case the functions have moved for some reason.
1610b725ae77Skettenis  */
1611b725ae77Skettenis 
1612b725ae77Skettenis static void
find_objc_msgsend(void)1613b725ae77Skettenis find_objc_msgsend (void)
1614b725ae77Skettenis {
1615b725ae77Skettenis   unsigned int i;
1616b725ae77Skettenis   for (i = 0; i < nmethcalls; i++) {
1617b725ae77Skettenis 
1618b725ae77Skettenis     struct minimal_symbol *func;
1619b725ae77Skettenis 
1620b725ae77Skettenis     /* Try both with and without underscore.  */
1621b725ae77Skettenis     func = lookup_minimal_symbol (methcalls[i].name, NULL, NULL);
1622b725ae77Skettenis     if ((func == NULL) && (methcalls[i].name[0] == '_')) {
1623b725ae77Skettenis       func = lookup_minimal_symbol (methcalls[i].name + 1, NULL, NULL);
1624b725ae77Skettenis     }
1625b725ae77Skettenis     if (func == NULL) {
1626b725ae77Skettenis       methcalls[i].begin = 0;
1627b725ae77Skettenis       methcalls[i].end = 0;
1628b725ae77Skettenis       continue;
1629b725ae77Skettenis     }
1630b725ae77Skettenis 
1631b725ae77Skettenis     methcalls[i].begin = SYMBOL_VALUE_ADDRESS (func);
1632b725ae77Skettenis     do {
1633b725ae77Skettenis       methcalls[i].end = SYMBOL_VALUE_ADDRESS (++func);
1634b725ae77Skettenis     } while (methcalls[i].begin == methcalls[i].end);
1635b725ae77Skettenis   }
1636b725ae77Skettenis }
1637b725ae77Skettenis 
1638b725ae77Skettenis /* find_objc_msgcall (replaces pc_off_limits)
1639b725ae77Skettenis  *
1640b725ae77Skettenis  * ALL that this function now does is to determine whether the input
1641b725ae77Skettenis  * address ("pc") is the address of one of the Objective-C message
1642b725ae77Skettenis  * dispatch functions (mainly objc_msgSend or objc_msgSendSuper), and
1643b725ae77Skettenis  * if so, it returns the address of the method that will be called.
1644b725ae77Skettenis  *
1645b725ae77Skettenis  * The old function "pc_off_limits" used to do a lot of other things
1646b725ae77Skettenis  * in addition, such as detecting shared library jump stubs and
1647b725ae77Skettenis  * returning the address of the shlib function that would be called.
1648b725ae77Skettenis  * That functionality has been moved into the SKIP_TRAMPOLINE_CODE and
1649b725ae77Skettenis  * IN_SOLIB_TRAMPOLINE macros, which are resolved in the target-
1650b725ae77Skettenis  * dependent modules.
1651b725ae77Skettenis  */
1652b725ae77Skettenis 
1653b725ae77Skettenis struct objc_submethod_helper_data {
1654b725ae77Skettenis   int (*f) (CORE_ADDR, CORE_ADDR *);
1655b725ae77Skettenis   CORE_ADDR pc;
1656b725ae77Skettenis   CORE_ADDR *new_pc;
1657b725ae77Skettenis };
1658b725ae77Skettenis 
1659b725ae77Skettenis static int
find_objc_msgcall_submethod_helper(void * arg)1660b725ae77Skettenis find_objc_msgcall_submethod_helper (void * arg)
1661b725ae77Skettenis {
1662b725ae77Skettenis   struct objc_submethod_helper_data *s =
1663b725ae77Skettenis     (struct objc_submethod_helper_data *) arg;
1664b725ae77Skettenis 
1665b725ae77Skettenis   if (s->f (s->pc, s->new_pc) == 0)
1666b725ae77Skettenis     return 1;
1667b725ae77Skettenis   else
1668b725ae77Skettenis     return 0;
1669b725ae77Skettenis }
1670b725ae77Skettenis 
1671b725ae77Skettenis static int
find_objc_msgcall_submethod(int (* f)(CORE_ADDR,CORE_ADDR *),CORE_ADDR pc,CORE_ADDR * new_pc)1672b725ae77Skettenis find_objc_msgcall_submethod (int (*f) (CORE_ADDR, CORE_ADDR *),
1673b725ae77Skettenis 			     CORE_ADDR pc,
1674b725ae77Skettenis 			     CORE_ADDR *new_pc)
1675b725ae77Skettenis {
1676b725ae77Skettenis   struct objc_submethod_helper_data s;
1677b725ae77Skettenis 
1678b725ae77Skettenis   s.f = f;
1679b725ae77Skettenis   s.pc = pc;
1680b725ae77Skettenis   s.new_pc = new_pc;
1681b725ae77Skettenis 
1682b725ae77Skettenis   if (catch_errors (find_objc_msgcall_submethod_helper,
1683b725ae77Skettenis 		    (void *) &s,
1684b725ae77Skettenis 		    "Unable to determine target of Objective-C method call (ignoring):\n",
1685b725ae77Skettenis 		    RETURN_MASK_ALL) == 0)
1686b725ae77Skettenis     return 1;
1687b725ae77Skettenis   else
1688b725ae77Skettenis     return 0;
1689b725ae77Skettenis }
1690b725ae77Skettenis 
1691b725ae77Skettenis int
find_objc_msgcall(CORE_ADDR pc,CORE_ADDR * new_pc)1692b725ae77Skettenis find_objc_msgcall (CORE_ADDR pc, CORE_ADDR *new_pc)
1693b725ae77Skettenis {
1694b725ae77Skettenis   unsigned int i;
1695b725ae77Skettenis 
1696b725ae77Skettenis   find_objc_msgsend ();
1697b725ae77Skettenis   if (new_pc != NULL)
1698b725ae77Skettenis     {
1699b725ae77Skettenis       *new_pc = 0;
1700b725ae77Skettenis     }
1701b725ae77Skettenis 
1702b725ae77Skettenis   for (i = 0; i < nmethcalls; i++)
1703b725ae77Skettenis     if ((pc >= methcalls[i].begin) && (pc < methcalls[i].end))
1704b725ae77Skettenis       {
1705b725ae77Skettenis 	if (methcalls[i].stop_at != NULL)
1706b725ae77Skettenis 	  return find_objc_msgcall_submethod (methcalls[i].stop_at,
1707b725ae77Skettenis 					      pc, new_pc);
1708b725ae77Skettenis 	else
1709b725ae77Skettenis 	  return 0;
1710b725ae77Skettenis       }
1711b725ae77Skettenis 
1712b725ae77Skettenis   return 0;
1713b725ae77Skettenis }
1714b725ae77Skettenis 
1715b725ae77Skettenis extern initialize_file_ftype _initialize_objc_language; /* -Wmissing-prototypes */
1716b725ae77Skettenis 
1717b725ae77Skettenis void
_initialize_objc_language(void)1718b725ae77Skettenis _initialize_objc_language (void)
1719b725ae77Skettenis {
1720b725ae77Skettenis   add_language (&objc_language_defn);
1721b725ae77Skettenis   add_info ("selectors", selectors_info,    /* INFO SELECTORS command.  */
1722b725ae77Skettenis 	    "All Objective-C selectors, or those matching REGEXP.");
1723b725ae77Skettenis   add_info ("classes", classes_info, 	    /* INFO CLASSES   command.  */
1724b725ae77Skettenis 	    "All Objective-C classes, or those matching REGEXP.");
1725b725ae77Skettenis   add_com ("print-object", class_vars, print_object_command,
1726b725ae77Skettenis 	   "Ask an Objective-C object to print itself.");
1727b725ae77Skettenis   add_com_alias ("po", "print-object", class_vars, 1);
1728b725ae77Skettenis }
1729b725ae77Skettenis 
1730b725ae77Skettenis static void
read_objc_method(CORE_ADDR addr,struct objc_method * method)1731b725ae77Skettenis read_objc_method (CORE_ADDR addr, struct objc_method *method)
1732b725ae77Skettenis {
1733b725ae77Skettenis   method->name  = read_memory_unsigned_integer (addr + 0, 4);
1734b725ae77Skettenis   method->types = read_memory_unsigned_integer (addr + 4, 4);
1735b725ae77Skettenis   method->imp   = read_memory_unsigned_integer (addr + 8, 4);
1736b725ae77Skettenis }
1737b725ae77Skettenis 
1738b725ae77Skettenis static
read_objc_methlist_nmethods(CORE_ADDR addr)1739b725ae77Skettenis unsigned long read_objc_methlist_nmethods (CORE_ADDR addr)
1740b725ae77Skettenis {
1741b725ae77Skettenis   return read_memory_unsigned_integer (addr + 4, 4);
1742b725ae77Skettenis }
1743b725ae77Skettenis 
1744b725ae77Skettenis static void
read_objc_methlist_method(CORE_ADDR addr,unsigned long num,struct objc_method * method)1745b725ae77Skettenis read_objc_methlist_method (CORE_ADDR addr, unsigned long num,
1746b725ae77Skettenis 			   struct objc_method *method)
1747b725ae77Skettenis {
1748b725ae77Skettenis   gdb_assert (num < read_objc_methlist_nmethods (addr));
1749b725ae77Skettenis   read_objc_method (addr + 8 + (12 * num), method);
1750b725ae77Skettenis }
1751b725ae77Skettenis 
1752b725ae77Skettenis static void
read_objc_object(CORE_ADDR addr,struct objc_object * object)1753b725ae77Skettenis read_objc_object (CORE_ADDR addr, struct objc_object *object)
1754b725ae77Skettenis {
1755b725ae77Skettenis   object->isa = read_memory_unsigned_integer (addr, 4);
1756b725ae77Skettenis }
1757b725ae77Skettenis 
1758b725ae77Skettenis static void
read_objc_super(CORE_ADDR addr,struct objc_super * super)1759b725ae77Skettenis read_objc_super (CORE_ADDR addr, struct objc_super *super)
1760b725ae77Skettenis {
1761b725ae77Skettenis   super->receiver = read_memory_unsigned_integer (addr, 4);
1762b725ae77Skettenis   super->class = read_memory_unsigned_integer (addr + 4, 4);
1763b725ae77Skettenis };
1764b725ae77Skettenis 
1765b725ae77Skettenis static void
read_objc_class(CORE_ADDR addr,struct objc_class * class)1766b725ae77Skettenis read_objc_class (CORE_ADDR addr, struct objc_class *class)
1767b725ae77Skettenis {
1768b725ae77Skettenis   class->isa = read_memory_unsigned_integer (addr, 4);
1769b725ae77Skettenis   class->super_class = read_memory_unsigned_integer (addr + 4, 4);
1770b725ae77Skettenis   class->name = read_memory_unsigned_integer (addr + 8, 4);
1771b725ae77Skettenis   class->version = read_memory_unsigned_integer (addr + 12, 4);
1772b725ae77Skettenis   class->info = read_memory_unsigned_integer (addr + 16, 4);
1773b725ae77Skettenis   class->instance_size = read_memory_unsigned_integer (addr + 18, 4);
1774b725ae77Skettenis   class->ivars = read_memory_unsigned_integer (addr + 24, 4);
1775b725ae77Skettenis   class->methods = read_memory_unsigned_integer (addr + 28, 4);
1776b725ae77Skettenis   class->cache = read_memory_unsigned_integer (addr + 32, 4);
1777b725ae77Skettenis   class->protocols = read_memory_unsigned_integer (addr + 36, 4);
1778b725ae77Skettenis }
1779b725ae77Skettenis 
1780b725ae77Skettenis static CORE_ADDR
find_implementation_from_class(CORE_ADDR class,CORE_ADDR sel)1781b725ae77Skettenis find_implementation_from_class (CORE_ADDR class, CORE_ADDR sel)
1782b725ae77Skettenis {
1783b725ae77Skettenis   CORE_ADDR subclass = class;
1784b725ae77Skettenis 
1785b725ae77Skettenis   while (subclass != 0)
1786b725ae77Skettenis     {
1787b725ae77Skettenis 
1788b725ae77Skettenis       struct objc_class class_str;
1789b725ae77Skettenis       unsigned mlistnum = 0;
1790b725ae77Skettenis 
1791b725ae77Skettenis       read_objc_class (subclass, &class_str);
1792b725ae77Skettenis 
1793b725ae77Skettenis       for (;;)
1794b725ae77Skettenis 	{
1795b725ae77Skettenis 	  CORE_ADDR mlist;
1796b725ae77Skettenis 	  unsigned long nmethods;
1797b725ae77Skettenis 	  unsigned long i;
1798b725ae77Skettenis 
1799b725ae77Skettenis 	  mlist = read_memory_unsigned_integer (class_str.methods +
1800b725ae77Skettenis 						(4 * mlistnum), 4);
1801b725ae77Skettenis 	  if (mlist == 0)
1802b725ae77Skettenis 	    break;
1803b725ae77Skettenis 
1804b725ae77Skettenis 	  nmethods = read_objc_methlist_nmethods (mlist);
1805b725ae77Skettenis 
1806b725ae77Skettenis 	  for (i = 0; i < nmethods; i++)
1807b725ae77Skettenis 	    {
1808b725ae77Skettenis 	      struct objc_method meth_str;
1809b725ae77Skettenis 	      read_objc_methlist_method (mlist, i, &meth_str);
1810b725ae77Skettenis 
1811b725ae77Skettenis #if 0
1812b725ae77Skettenis 	      fprintf (stderr,
1813b725ae77Skettenis 		       "checking method 0x%lx against selector 0x%lx\n",
1814b725ae77Skettenis 		       meth_str.name, sel);
1815b725ae77Skettenis #endif
1816b725ae77Skettenis 
1817b725ae77Skettenis 	      if (meth_str.name == sel)
1818b725ae77Skettenis 		/* FIXME: hppa arch was doing a pointer dereference
1819b725ae77Skettenis 		   here. There needs to be a better way to do that.  */
1820b725ae77Skettenis 		return meth_str.imp;
1821b725ae77Skettenis 	    }
1822b725ae77Skettenis 	  mlistnum++;
1823b725ae77Skettenis 	}
1824b725ae77Skettenis       subclass = class_str.super_class;
1825b725ae77Skettenis     }
1826b725ae77Skettenis 
1827b725ae77Skettenis   return 0;
1828b725ae77Skettenis }
1829b725ae77Skettenis 
1830b725ae77Skettenis static CORE_ADDR
find_implementation(CORE_ADDR object,CORE_ADDR sel)1831b725ae77Skettenis find_implementation (CORE_ADDR object, CORE_ADDR sel)
1832b725ae77Skettenis {
1833b725ae77Skettenis   struct objc_object ostr;
1834b725ae77Skettenis 
1835b725ae77Skettenis   if (object == 0)
1836b725ae77Skettenis     return 0;
1837b725ae77Skettenis   read_objc_object (object, &ostr);
1838b725ae77Skettenis   if (ostr.isa == 0)
1839b725ae77Skettenis     return 0;
1840b725ae77Skettenis 
1841b725ae77Skettenis   return find_implementation_from_class (ostr.isa, sel);
1842b725ae77Skettenis }
1843b725ae77Skettenis 
1844b725ae77Skettenis #define OBJC_FETCH_POINTER_ARGUMENT(argi) \
1845b725ae77Skettenis   FETCH_POINTER_ARGUMENT (get_current_frame (), argi, builtin_type_void_func_ptr)
1846b725ae77Skettenis 
1847b725ae77Skettenis static int
resolve_msgsend(CORE_ADDR pc,CORE_ADDR * new_pc)1848b725ae77Skettenis resolve_msgsend (CORE_ADDR pc, CORE_ADDR *new_pc)
1849b725ae77Skettenis {
1850b725ae77Skettenis   CORE_ADDR object;
1851b725ae77Skettenis   CORE_ADDR sel;
1852b725ae77Skettenis   CORE_ADDR res;
1853b725ae77Skettenis 
1854b725ae77Skettenis   object = OBJC_FETCH_POINTER_ARGUMENT (0);
1855b725ae77Skettenis   sel = OBJC_FETCH_POINTER_ARGUMENT (1);
1856b725ae77Skettenis 
1857b725ae77Skettenis   res = find_implementation (object, sel);
1858b725ae77Skettenis   if (new_pc != 0)
1859b725ae77Skettenis     *new_pc = res;
1860b725ae77Skettenis   if (res == 0)
1861b725ae77Skettenis     return 1;
1862b725ae77Skettenis   return 0;
1863b725ae77Skettenis }
1864b725ae77Skettenis 
1865b725ae77Skettenis static int
resolve_msgsend_stret(CORE_ADDR pc,CORE_ADDR * new_pc)1866b725ae77Skettenis resolve_msgsend_stret (CORE_ADDR pc, CORE_ADDR *new_pc)
1867b725ae77Skettenis {
1868b725ae77Skettenis   CORE_ADDR object;
1869b725ae77Skettenis   CORE_ADDR sel;
1870b725ae77Skettenis   CORE_ADDR res;
1871b725ae77Skettenis 
1872b725ae77Skettenis   object = OBJC_FETCH_POINTER_ARGUMENT (1);
1873b725ae77Skettenis   sel = OBJC_FETCH_POINTER_ARGUMENT (2);
1874b725ae77Skettenis 
1875b725ae77Skettenis   res = find_implementation (object, sel);
1876b725ae77Skettenis   if (new_pc != 0)
1877b725ae77Skettenis     *new_pc = res;
1878b725ae77Skettenis   if (res == 0)
1879b725ae77Skettenis     return 1;
1880b725ae77Skettenis   return 0;
1881b725ae77Skettenis }
1882b725ae77Skettenis 
1883b725ae77Skettenis static int
resolve_msgsend_super(CORE_ADDR pc,CORE_ADDR * new_pc)1884b725ae77Skettenis resolve_msgsend_super (CORE_ADDR pc, CORE_ADDR *new_pc)
1885b725ae77Skettenis {
1886b725ae77Skettenis   struct objc_super sstr;
1887b725ae77Skettenis 
1888b725ae77Skettenis   CORE_ADDR super;
1889b725ae77Skettenis   CORE_ADDR sel;
1890b725ae77Skettenis   CORE_ADDR res;
1891b725ae77Skettenis 
1892b725ae77Skettenis   super = OBJC_FETCH_POINTER_ARGUMENT (0);
1893b725ae77Skettenis   sel = OBJC_FETCH_POINTER_ARGUMENT (1);
1894b725ae77Skettenis 
1895b725ae77Skettenis   read_objc_super (super, &sstr);
1896b725ae77Skettenis   if (sstr.class == 0)
1897b725ae77Skettenis     return 0;
1898b725ae77Skettenis 
1899b725ae77Skettenis   res = find_implementation_from_class (sstr.class, sel);
1900b725ae77Skettenis   if (new_pc != 0)
1901b725ae77Skettenis     *new_pc = res;
1902b725ae77Skettenis   if (res == 0)
1903b725ae77Skettenis     return 1;
1904b725ae77Skettenis   return 0;
1905b725ae77Skettenis }
1906b725ae77Skettenis 
1907b725ae77Skettenis static int
resolve_msgsend_super_stret(CORE_ADDR pc,CORE_ADDR * new_pc)1908b725ae77Skettenis resolve_msgsend_super_stret (CORE_ADDR pc, CORE_ADDR *new_pc)
1909b725ae77Skettenis {
1910b725ae77Skettenis   struct objc_super sstr;
1911b725ae77Skettenis 
1912b725ae77Skettenis   CORE_ADDR super;
1913b725ae77Skettenis   CORE_ADDR sel;
1914b725ae77Skettenis   CORE_ADDR res;
1915b725ae77Skettenis 
1916b725ae77Skettenis   super = OBJC_FETCH_POINTER_ARGUMENT (1);
1917b725ae77Skettenis   sel = OBJC_FETCH_POINTER_ARGUMENT (2);
1918b725ae77Skettenis 
1919b725ae77Skettenis   read_objc_super (super, &sstr);
1920b725ae77Skettenis   if (sstr.class == 0)
1921b725ae77Skettenis     return 0;
1922b725ae77Skettenis 
1923b725ae77Skettenis   res = find_implementation_from_class (sstr.class, sel);
1924b725ae77Skettenis   if (new_pc != 0)
1925b725ae77Skettenis     *new_pc = res;
1926b725ae77Skettenis   if (res == 0)
1927b725ae77Skettenis     return 1;
1928b725ae77Skettenis   return 0;
1929b725ae77Skettenis }
1930