This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [PATCH] Handle ObjC OPS in eval.c
- From: Elena Zannoni <ezannoni at redhat dot com>
- To: Adam Fedor <fedor at doc dot com>
- Cc: Michael Snyder <msnyder at redhat dot com>, GDB Patches <gdb-patches at sources dot redhat dot com>
- Date: Wed, 19 Feb 2003 15:09:41 -0500
- Subject: Re: [PATCH] Handle ObjC OPS in eval.c
- References: <3E15F21B.6010101@doc.com><3E39E887.AB98ECA4@redhat.com><3E4B195D.2000200@doc.com>
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) */