This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[PATCH] Handle ObjC OPS in eval.c
- From: Adam Fedor <fedor at doc dot com>
- To: GDB Patches <gdb-patches at sources dot redhat dot com>
- Date: Fri, 03 Jan 2003 13:27:07 -0700
- Subject: [PATCH] Handle ObjC OPS in eval.c
<<< text/plain; charset=us-ascii; format=flowed: Unrecognized >>>
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) */