This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Handle ObjC OPS in eval.c


Adam Fedor writes:
 > 
 > 
 > Michael Snyder wrote:
 > > Adam Fedor wrote:
 > > 
 > >>2003-01-02  Adam Fedor  <fedor at gnu dot org>
 > >>
 > >>        * Makefile.in (eval.o): Add $(objc_lang_h)
 > >>        * eval.c (evaluate_subexp_standard): Handle ObjC ops.
 > >>        * valops.c (find_function_addr): Make non-static.
 > >>        * value.h (find_function_addr): Declare.
 > > 
 > > 
 > > Adam, this is OK in principal, assuming that the objc code
 > > such as value_nsstring is being unconditionally built now.
 > > A few remarks:
 > > 
 > 
 > I havne't been able to resolve the problem you had with the last part of 
 > the patch, but here is an updated patch with the other changes.
 > 

a few comments below, from a Objc-naive person.


 > 2003-02-12  Adam Fedor  <fedor at gnu dot org>
 > 
 > 	* Makefile.in (eval.o): Add $(objc_lang_h)
 > 	* eval.c (evaluate_subexp_standard): Handle ObjC ops.
 > 	* valops.c (find_function_addr): Make non-static.
 > 	* value.h (find_function_addr): Declare.
 > 
 > Index: Makefile.in
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/Makefile.in,v
 > retrieving revision 1.329
 > diff -u -p -r1.329 Makefile.in
 > --- Makefile.in	11 Feb 2003 16:11:16 -0000	1.329
 > +++ Makefile.in	13 Feb 2003 02:46:43 -0000
 > @@ -1641,7 +1642,7 @@ elfread.o: elfread.c $(defs_h) $(bfd_h) 
 >  environ.o: environ.c $(defs_h) $(environ_h) $(gdb_string_h)
 >  eval.o: eval.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
 >  	$(value_h) $(expression_h) $(target_h) $(frame_h) $(language_h) \
 > -	$(f_lang_h) $(cp_abi_h)
 > +	$(f_lang_h) $(cp_abi_h) $(objc_lang_h)
 >  event-loop.o: event-loop.c $(defs_h) $(event_loop_h) $(event_top_h) \
 >  	$(gdb_string_h)
 >  event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \
 > Index: eval.c
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/eval.c,v
 > retrieving revision 1.27
 > diff -u -p -r1.27 eval.c
 > --- eval.c	14 Jan 2003 00:49:03 -0000	1.27
 > +++ eval.c	13 Feb 2003 02:46:44 -0000
 > @@ -31,6 +31,7 @@
 >  #include "frame.h"
 >  #include "language.h"		/* For CAST_IS_CONVERSION */
 >  #include "f-lang.h"		/* for array bound stuff */
 > +#include "objc-lang.h"
 >  #include "cp-abi.h"
 >  
 >  /* Defined in symtab.c */
 > @@ -471,6 +472,15 @@ evaluate_subexp_standard (struct type *e
 >  	goto nosideret;
 >        return value_string (&exp->elts[pc + 2].string, tem);
 >  
 > +    case OP_OBJC_NSSTRING:		/* Objective C Foundation Class NSString constant.  */
 > +      tem = longest_to_int (exp->elts[pc + 1].longconst);
 > +      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
 > +      if (noside == EVAL_SKIP)
 > +	{
 > +	  goto nosideret;
 > +	}
 > +      return (struct value *) value_nsstring (&exp->elts[pc + 2].string, tem + 1);
 > +
 >      case OP_BITSTRING:
 >        tem = longest_to_int (exp->elts[pc + 1].longconst);
 >        (*pos)
 > @@ -667,6 +677,295 @@ evaluate_subexp_standard (struct type *e
 >  	  return arg2;
 >  	}
 >  
 > +    case OP_OBJC_SELECTOR:
 > +      {				/* Objective C @selector operator.  */
 > +	char *sel = &exp->elts[pc + 2].string;
 > +	int len = longest_to_int (exp->elts[pc + 1].longconst);
 > +
 > +	(*pos) += 3 + BYTES_TO_EXP_ELEM (len + 1);
 > +	if (noside == EVAL_SKIP)
 > +	  goto nosideret;
 > +
 > +	if (sel[len] != 0)
 > +	  sel[len] = 0;		/* Make sure it's terminated.  */
 > +	return value_from_longest (lookup_pointer_type (builtin_type_void),
 > +				   lookup_child_selector (sel));
 > +      }
 > +
 > +    case OP_OBJC_MSGCALL:
 > +      {				/* Objective C message (method) call.  */
 > +
 > +	static unsigned long responds_selector = 0;
 > +	static unsigned long method_selector = 0;
 > +	static unsigned int selector_generation = 0;
 > +
 > +	unsigned long selector = 0;
 > +
 > +	int using_gcc = 0;
 > +	int struct_return = 0;
 > +	int sub_no_side = 0;
 > +
 > +	static struct value *msg_send = NULL;
 > +	static struct value *msg_send_stret = NULL;
 > +	static struct value *msg_send_typed = NULL;
 > +	static int gnu_runtime = 0;
 > +
 > +	struct value *target = NULL;
 > +	struct value *method = NULL;
 > +	struct value *called_method = NULL; 
 > +
 > +	struct type *selector_type = NULL;
 > +
 > +	struct value *ret = NULL;
 > +	struct symbol *sym = NULL;
 > +	CORE_ADDR addr = 0;
 > +
 > +	selector = exp->elts[pc + 1].longconst;
 > +	nargs = exp->elts[pc + 2].longconst;
 > +	argvec = (struct value **) alloca (sizeof (struct value *) 
 > +					   * (nargs + 5));
 > +
 > +	(*pos) += 3;
 > +
 > +	selector_type = lookup_pointer_type (builtin_type_void);
 > +	sub_no_side = (noside == EVAL_AVOID_SIDE_EFFECTS) 
 > +	  ? EVAL_NORMAL : noside;
 > +

can you get rid of the conditional expression?

 > +	target = evaluate_subexp (selector_type, exp, pos, sub_no_side);
 > +
 > +	if (value_as_long (target) == 0)
 > + 	  return value_from_longest (builtin_type_long, 0);
 > +	
 > +	if (lookup_minimal_symbol ("objc_msg_lookup", 0, 0))
 > +	  gnu_runtime = 1;
 > +	
 > +	if (gnu_runtime)
 > +	  {
 > +	    msg_send = find_function_in_inferior ("objc_msg_lookup");
 > +	    msg_send_stret = find_function_in_inferior ("objc_msg_lookup");
 > +	    msg_send_typed = find_function_in_inferior ("objc_msg_lookup");
 > +	  }
 > +	else
 > +	  {
 > +	    msg_send = find_function_in_inferior ("objc_msgSend");
 > +	    msg_send_stret = find_function_in_inferior ("objc_msgSend_stret");
 > +	    msg_send_typed = find_function_in_inferior ("objc_msgSend");
 > +	  }
 > +

I think we need more comments, I guess stret means structure return?
What are these methods used for? Also can you add a high level
description of how these dispatchers get into the picture?

 > +	/* Verify target responds to method selector.  Must also
 > +	   account for new (NSObject) and old (Object) worlds. */
 > +
 > +	responds_selector = lookup_child_selector ("respondsToSelector:");
 > +	if (responds_selector == 0)
 > +	  responds_selector = lookup_child_selector ("respondsTo:");
 > +	
 > +	if (responds_selector == 0)
 > +	  error ("no 'respondsTo:' or 'respondsToSelector:' method");
 > +	
 > +	if (gnu_runtime)
 > +	  {
 > +	    method_selector = lookup_child_selector ("methodFor:");
 > +	    if (method_selector == 0)
 > +	      method_selector = lookup_child_selector ("methodForSelector:");
 > +	  }
 > +	else
 > +	  {
 > +	    method_selector = lookup_child_selector ("methodForSelector:");
 > +	    if (method_selector == 0)
 > +	      method_selector = lookup_child_selector ("methodFor:");
 > +	  }
 > +	
 > +	if (method_selector == 0)
 > +	  error ("no 'methodFor:' or 'methodForSelector:' method");
 > +
 > +	/* Call "respondsToSelector:" method, to make sure that the
 > +	 target class implements the user's desired method
 > +	 selector. */
 > +
 > +	argvec[0] = msg_send_typed;
 > +	argvec[1] = target;
 > +	argvec[2] = value_from_longest (builtin_type_long, responds_selector);
 > +	argvec[3] = value_from_longest (builtin_type_long, selector);
 > +	argvec[4] = 0;
 > +
 > +	ret = call_function_by_hand (argvec[0], 3, argvec + 1);
 > +	if (gnu_runtime)
 > +	  {
 > +	    /* Function objc_msg_lookup returns a pointer.  */
 > +	    argvec[0] = ret;
 > +	    ret = call_function_by_hand (argvec[0], 3, argvec + 1);
 > +	  }
 > +	if (value_as_long (ret) == 0)
 > +	  error ("Target does not respond to this message selector.");
 > +
 > +	/* Call "methodForSelector:" method, to get the address of a
 > +	   function method that implements this selector for this
 > +	   class.  If we can find a symbol at that address, then we
 > +	   know the return type, parameter types etc.  (that's a good
 > +	   thing). */
 > +
 > +	argvec[0] = msg_send_typed;
 > +	argvec[1] = target;
 > +	argvec[2] = value_from_longest (builtin_type_long, method_selector);
 > +	argvec[3] = value_from_longest (builtin_type_long, selector);
 > +	argvec[4] = 0;
 > +
 > +	ret = call_function_by_hand (argvec[0], 3, argvec + 1);
 > +	if (gnu_runtime)
 > +	  {
 > +	    argvec[0] = ret;
 > +	    ret = call_function_by_hand (argvec[0], 3, argvec + 1);
 > +	  }
 > +
 > +	/* ret should now be the selector.  */
 > +
 > +	addr = value_as_long (ret);
 > +	if (addr)
 > +	  {
 > +	    /* Is it a high_level symbol?  */
 > +
 > +#if 0
 > +	    /* Was defined only for HPPA architectures. Commented out
 > +	       since we cannot verify that this works anymore.  Anyone
 > +	       experiencing problems on HPPA machines can check this
 > +	       for validity.  */
 > +	    CORE_ADDR tmp;
 > +	    /* Code and comment lifted from hppa-tdep.c.
 > +	       Unfortunately there is no builtin function to do
 > +	       this.  */
 > +	    /* If bit 30 (counting from the left) is on, then addr
 > +	       is the address of the PLT entry for this function,
 > +	       not the address of the function itself.  Bit 31 has
 > +	       meaning too, but only for MPE.  */
 > +	    if (addr & 0x2)
 > +	      addr = (CORE_ADDR) read_memory_unsigned_integer (addr & ~0x3, 4);
 > +	    if (tmp = skip_trampoline_code (addr, 0))
 > +	      addr = tmp;
 > +#endif
 > +
 > +	    sym = find_pc_function (addr);
 > +	    if (sym != NULL) 
 > +	      method = value_of_variable (sym, 0);
 > +	  }
 > +
 > +	/* If we found a method with symbol information, check to see
 > +           if it returns a struct.  Otherwise assume it doesn't.  */
 > +
 > +	if (method)
 > +	  {
 > +	    struct block *b;
 > +	    CORE_ADDR funaddr;
 > +	    struct type *value_type;
 > +
 > +	    funaddr = find_function_addr (method, &value_type);
 > +
 > +	    b = block_for_pc (funaddr);
 > +
 > +	    /* If compiled without -g, assume GCC 2.  */
 > +	    using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b));
 > +
 > +	    CHECK_TYPEDEF (value_type);
 > +	  
 > +	    if ((value_type == NULL) 
 > +		|| (TYPE_CODE(value_type) == TYPE_CODE_ERROR))
 > +	      {
 > +		if (expect_type != NULL)
 > +		  value_type = expect_type;
 > +	      }
 > +
 > +	    struct_return = using_struct_return (method, funaddr, value_type, using_gcc);
 > +	  }
 > +	else if (expect_type != NULL)
 > +	  {
 > +	    struct_return = using_struct_return (NULL, addr, check_typedef (expect_type), using_gcc);
 > +	  }
 > +	
 > +	/* Found a function symbol.  Now we will substitute its
 > +	   value in place of the message dispatcher (obj_msgSend),
 > +	   so that we call the method directly instead of thru
 > +	   the dispatcher.  The main reason for doing this is that
 > +	   we can now evaluate the return value and parameter values
 > +	   according to their known data types, in case we need to
 > +	   do things like promotion, dereferencing, special handling
 > +	   of structs and doubles, etc.
 > +	  
 > +	   We want to use the type signature of 'method', but still
 > +	   jump to objc_msgSend() or objc_msgSend_stret() to better
 > +	   mimic the behavior of the runtime.  */
 > +	
 > +	if (method)
 > +	  {
 > +	    if (TYPE_CODE (VALUE_TYPE (method)) != TYPE_CODE_FUNC)
 > +	      error ("method address has symbol information with non-function type; skipping");
 > +	    if (struct_return)
 > +	      VALUE_ADDRESS (method) = value_as_address (msg_send_stret);
 > +	    else
 > +	      VALUE_ADDRESS (method) = value_as_address (msg_send);
 > +	    called_method = method;
 > +	  }
 > +	else
 > +	  {
 > +	    if (struct_return)
 > +	      called_method = msg_send_stret;
 > +	    else
 > +	      called_method = msg_send;
 > +	  }
 > +
 > +	if (noside == EVAL_SKIP)
 > +	  goto nosideret;
 > +
 > +	if (noside == EVAL_AVOID_SIDE_EFFECTS)
 > +	  {
 > +	    /* If the return type doesn't look like a function type,
 > +	       call an error.  This can happen if somebody tries to
 > +	       turn a variable into a function call. This is here
 > +	       because people often want to call, eg, strcmp, which
 > +	       gdb doesn't know is a function.  If gdb isn't asked for
 > +	       it's opinion (ie. through "whatis"), it won't offer
 > +	       it. */
 > +
 > +	    struct type *type = VALUE_TYPE (called_method);
 > +	    if (type && TYPE_CODE (type) == TYPE_CODE_PTR)
 > +	      type = TYPE_TARGET_TYPE (type);
 > +	    type = TYPE_TARGET_TYPE (type);
 > +
 > +	    if (type)
 > +	    {
 > +	      if ((TYPE_CODE (type) == TYPE_CODE_ERROR) && expect_type)
 > +		return allocate_value (expect_type);
 > +	      else
 > +		return allocate_value (type);
 > +	    }
 > +	    else
 > +	      error ("Expression of type other than \"method returning ...\" used as a method");
 > +	  }
 > +
 > +	/* Now depending on whether we found a symbol for the method,
 > +	   we will either call the runtime dispatcher or the method
 > +	   directly.  */
 > +
 > +	argvec[0] = called_method;
 > +	argvec[1] = target;
 > +	argvec[2] = value_from_longest (builtin_type_long, selector);
 > +	/* User-supplied arguments.  */
 > +	for (tem = 0; tem < nargs; tem++)
 > +	  argvec[tem + 3] = evaluate_subexp_with_coercion (exp, pos, noside);
 > +	argvec[tem + 3] = 0;
 > +
 > +	if (gnu_runtime && (method != NULL))
 > +	  {
 > +	    ret = call_function_by_hand (argvec[0], nargs + 2, argvec + 1);
 > +	    /* Function objc_msg_lookup returns a pointer.  */
 > +	    argvec[0] = ret;
 > +	    ret = call_function_by_hand (argvec[0], nargs + 2, argvec + 1);
 > +	  }
 > +	else
 > +	  ret = call_function_by_hand (argvec[0], nargs + 2, argvec + 1);
 > +
 > +	return ret;
 > +      }
 > +      break;
 > +
 >      case OP_FUNCALL:
 >        (*pos) += 2;
 >        op = exp->elts[*pos].opcode;
 > @@ -1748,6 +2047,10 @@ evaluate_subexp_standard (struct type *e
 >      case OP_THIS:
 >        (*pos) += 1;
 >        return value_of_this (1);
 > +
 > +    case OP_OBJC_SELF:
 > +      (*pos) += 1;
 > +      return value_of_local ("self", 1);
 >  
 >      case OP_TYPE:
 >        error ("Attempt to use a type name as an expression");
 > Index: valops.c
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/valops.c,v
 > retrieving revision 1.89
 > diff -u -p -r1.89 valops.c
 > --- valops.c	30 Jan 2003 16:44:20 -0000	1.89
 > +++ valops.c	13 Feb 2003 02:46:52 -0000
 > @@ -48,7 +48,6 @@ extern int overload_debug;
 >  static int typecmp (int staticp, int varargs, int nargs,
 >  		    struct field t1[], struct value *t2[]);
 >  
 > -static CORE_ADDR find_function_addr (struct value *, struct type **);
 >  static struct value *value_arg_coerce (struct value *, struct type *, int);
 >  
 >  
 > @@ -1172,7 +1171,7 @@ value_arg_coerce (struct value *arg, str
 >  /* Determine a function's address and its return type from its value.
 >     Calls error() if the function is not valid for calling.  */
 >  
 > -static CORE_ADDR
 > +CORE_ADDR
 >  find_function_addr (struct value *function, struct type **retval_type)
 >  {
 >    register struct type *ftype = check_typedef (VALUE_TYPE (function));
 > Index: value.h
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/value.h,v
 > retrieving revision 1.41
 > diff -u -p -r1.41 value.h
 > --- value.h	19 Jan 2003 04:06:46 -0000	1.41
 > +++ value.h	13 Feb 2003 02:46:52 -0000
 > @@ -563,6 +563,8 @@ extern CORE_ADDR default_push_arguments 
 >  					 CORE_ADDR sp, int struct_return,
 >  					 CORE_ADDR struct_addr);
 >  
 > +extern CORE_ADDR find_function_addr (struct value *, struct type **);
 > +
 >  extern struct value *value_of_local (const char *name, int complain);
 >  
 >  #endif /* !defined (VALUE_H) */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]