From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29144 invoked by alias); 13 Feb 2003 04:05:01 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 29131 invoked from network); 13 Feb 2003 04:05:00 -0000 Received: from unknown (HELO external1.doc.com) (63.119.183.65) by 172.16.49.205 with SMTP; 13 Feb 2003 04:05:00 -0000 Received: (qmail 13244 invoked from network); 13 Feb 2003 04:04:45 -0000 Received: from cpe-24-221-209-215.co.sprintbbd.net (HELO doc.com) (24.221.209.215) by external1 with SMTP; 13 Feb 2003 04:04:45 -0000 Message-ID: <3E4B195D.2000200@doc.com> Date: Thu, 13 Feb 2003 04:05:00 -0000 From: Adam Fedor User-Agent: Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.1) Gecko/20020905 X-Accept-Language: en-us, en MIME-Version: 1.0 To: Michael Snyder CC: GDB Patches Subject: Re: [PATCH] Handle ObjC OPS in eval.c References: <3E15F21B.6010101@doc.com> <3E39E887.AB98ECA4@redhat.com> Content-Type: multipart/mixed; boundary="------------090301010300090106020305" X-SW-Source: 2003-02/txt/msg00304.txt.bz2 This is a multi-part message in MIME format. --------------090301010300090106020305 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Content-length: 608 Michael Snyder wrote: > Adam Fedor wrote: > >>2003-01-02 Adam Fedor >> >> * 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. --------------090301010300090106020305 Content-Type: text/plain; name="objc21.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="objc21.patch" Content-length: 13233 2003-02-12 Adam Fedor * 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; + + 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. 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) */ --------------090301010300090106020305--