This is the mail archive of the gdb-prs@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]

pending/996: [PATCH] Handle ObjC OPS in eval.c


>Number:         996
>Category:       pending
>Synopsis:       [PATCH] Handle ObjC OPS in eval.c
>Confidential:   yes
>Severity:       serious
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          change-request
>Submitter-Id:   unknown
>Arrival-Date:   Fri Jan 31 05:38:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator:     
>Release:        
>Organization:
>Environment:
>Description:
 This is a multi-part message in MIME format.
 --------------000805040703010403080309
 Content-Type: text/plain; charset=us-ascii; format=flowed
 Content-Transfer-Encoding: 7bit
 
 
 --------------000805040703010403080309
 Content-Type: text/plain;
  name="objc21.patch"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline;
  filename="objc21.patch"
 
 2003-01-02  Adam Fedor  <fedor@gnu.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.302
 diff -u -p -r1.302 Makefile.in
 --- Makefile.in	2 Jan 2003 20:29:15 -0000	1.302
 +++ Makefile.in	3 Jan 2003 03:51:46 -0000
 @@ -1644,7 +1645,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.26
 diff -u -p -r1.26 eval.c
 --- eval.c	2 Jan 2003 14:27:26 -0000	1.26
 +++ eval.c	3 Jan 2003 20:18:26 -0000
 @@ -30,6 +30,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 */
 @@ -470,6 +471,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)
 @@ -666,6 +676,297 @@ 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 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;
 +
 +	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");
 +	  }
 +
 +	/* Verify target responds to method selector. This logic needs
 +	 * work: not sure of GNU variant's name.  Must also account for
 +	 * new (NSObject) and old (Object) worlds
 +	 */
 +
 +	if (1)
 +	  {
 +	    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)
 +	  {
 +	    /* objc_msg_lookup returns a pointer */
 +	    argvec[0] = ret;	/* prepare to call the method */
 +	    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;	/* prepare to call the method */
 +	    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? */
 +
 +#ifdef GDB_TARGET_IS_HPPA
 +	    CORE_ADDR tmp;
 +	    /* code and comment lifted from hppa-tdep.c -- unfortunately 
 +	       there is no builtin function to do this for me. */
 +	    /* 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;	/* in case of trampoline code */
 +#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);
 +	    /* 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;
 @@ -1747,6 +2048,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.85
 diff -u -p -r1.85 valops.c
 --- valops.c	2 Jan 2003 14:27:27 -0000	1.85
 +++ valops.c	3 Jan 2003 03:52:01 -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);
  
  
 @@ -1185,7 +1184,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.38
 diff -u -p -r1.38 value.h
 --- value.h	2 Jan 2003 14:27:27 -0000	1.38
 +++ value.h	3 Jan 2003 03:52:02 -0000
 @@ -566,6 +566,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) */
 
 --------------000805040703010403080309--
 
 
>How-To-Repeat:
>Fix:
>Release-Note:
>Audit-Trail:
>Unformatted:


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