From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30751 invoked by alias); 10 Apr 2003 21:56:25 -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 30744 invoked from network); 10 Apr 2003 21:56:25 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sources.redhat.com with SMTP; 10 Apr 2003 21:56:25 -0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.11.6/8.11.6) with ESMTP id h3ALuPe26601 for ; Thu, 10 Apr 2003 17:56:25 -0400 Received: from pobox.corp.redhat.com (pobox.corp.redhat.com [172.16.52.156]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id h3ALuPJ15573; Thu, 10 Apr 2003 17:56:25 -0400 Received: from localhost.redhat.com (romulus-int.sfbay.redhat.com [172.16.27.46]) by pobox.corp.redhat.com (8.11.6/8.11.6) with ESMTP id h3ALuJ621883; Thu, 10 Apr 2003 17:56:20 -0400 Received: by localhost.redhat.com (Postfix, from userid 469) id 5B6452C43E; Thu, 10 Apr 2003 18:00:41 -0400 (EDT) From: Elena Zannoni MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <16021.59784.477170.598470@localhost.redhat.com> Date: Thu, 10 Apr 2003 21:56:00 -0000 To: Adam Fedor Cc: Elena Zannoni , Michael Snyder , GDB Patches Subject: Re: [PATCH] Handle ObjC OPS in eval.c In-Reply-To: <3E6585AA.7040602@doc.com> References: <3E15F21B.6010101@doc.com> <3E39E887.AB98ECA4@redhat.com> <3E4B195D.2000200@doc.com> <15955.58501.106665.997721@localhost.redhat.com> <3E6585AA.7040602@doc.com> X-SW-Source: 2003-04/txt/msg00219.txt.bz2 Adam Fedor writes: > > > Elena Zannoni wrote: > [...] > > > > 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? > > > > Here's a better documented and slightly cleaned-up patch. > 2003-03-04 Adam Fedor I think it's ok. Except I don't like to introduce more #if0 code with new code. Do we really need that part? elena > > * Makefile.in (eval.o): Add $(objc_lang_h) (block_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) $(block_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 5 Mar 2003 04:59:34 -0000 > @@ -31,7 +31,9 @@ > #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" > +#include "block.h" > > /* Defined in symtab.c */ > extern int hp_som_som_object_present; > @@ -471,6 +473,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 +678,296 @@ 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; > + > + 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 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; > + 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); > + if (noside == EVAL_AVOID_SIDE_EFFECTS) > + sub_no_side = EVAL_NORMAL; > + else > + sub_no_side = 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; > + > + /* Find the method dispatch (Apple runtime) or method lookup > + (GNU runtime) function for Objective-C. These will be used > + to lookup the symbol information for the method. If we > + can't find any symbol information, then we'll use these to > + call the method, otherwise we can call the method > + directly. The msg_send_stret function is used in the special > + case of a method that returns a structure (Apple runtime > + only). */ > + if (gnu_runtime) > + { > + msg_send = find_function_in_inferior ("objc_msg_lookup"); > + msg_send_stret = find_function_in_inferior ("objc_msg_lookup"); > + } > + else > + { > + msg_send = find_function_in_inferior ("objc_msgSend"); > + /* Special dispatcher for methods returning structs */ > + msg_send_stret = find_function_in_inferior ("objc_msgSend_stret"); > + } > + > + /* Verify the target object responds to this method. The > + standard top-level 'Object' class uses a different name for > + the verification method than the non-standard, but more > + often used, 'NSObject' class. Make sure we check for both. */ > + > + 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"); > + > + 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 the verification method, to make sure that the target > + class implements the desired method. */ > + > + argvec[0] = msg_send; > + 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; > + 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) > + { > + struct symbol *sym = NULL; > + /* 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 +2054,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) */