This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[rfc] Fix Obj-C method calls on 64-bit PowerPC
- From: "Ulrich Weigand" <uweigand at de dot ibm dot com>
- To: gdb-patches at sourceware dot org
- Date: Sun, 27 Sep 2009 23:49:27 +0200 (CEST)
- Subject: [rfc] Fix Obj-C method calls on 64-bit PowerPC
Hello,
on ppc64-linux, most Obj-C test cases now fail with a timeout due to
segmentation faults, causing very long testsuite run times.
The fundamental problem is that calling an Obj-C method does not
properly support platforms where a function pointer actually points
to a function descriptor instead of the target address. This showed
up in a number of places:
- linespec.c:decode_objc did not convert minimal symbol addresses to
function addresses (in addition, it did not fully initialize the SAL
it returned in that case, resulting in an uninitialized "section"
pointer that sometimes caused GDB to crash).
- objc-lang.c:find_methods required minimal symbols to reside in the
text section (which is not valid if the symbol points to a descriptor
in the data section) and likewise did not convert the minsym address
to the function address.
- eval.c:evaluate_subexp_standard did some quite interesting hand-crafted
"type casts" between *function pointer* and *function* types, which
fail if function pointers actually refer to descriptors. This code
needs to use real function pointers as long as possible (to avoid
losing descriptor information that is needed later on).
- and finally, ppc-sysv-tdep.c:ppc64_sysv_abi_push_dummy_call is sometimes
unable to re-construct a function descriptor for a function called via
function pointer (if the target is in a library without debug info).
But this is silly, as the function pointer actually contains all the
descriptor information needed, we just have to look at it ...
With the patch below, the Obj-C test cases now work as well as on
32-bit ppc-linux (and other Linux platforms). There is still the
one failure in objcdecode.exp (like on other platforms).
Tested on s390(x)-linux and ppc(64)-linux with no regressions.
Does this look OK?
Bye,
Ulrich
ChangeLog:
* eval.c (evaluate_subexp_standard) [OP_OBJC_MSGCALL]: Support
platforms that use function descriptors. Prefer to use function
pointer types instead of function types.
* linespec.c (decode_objc): Support function descriptors. Fully
initialize SAL result.
* objc-lang.c (find_methods): Support function descriptors.
Do not require function symbol to point to text section.
* ppc-sysv-tdep.c (ppc64_sysv_abi_push_dummy_call): When calling
via a function pointer, use the descriptor it point to.
Index: gdb/eval.c
===================================================================
RCS file: /cvs/src/src/gdb/eval.c,v
retrieving revision 1.120
diff -c -p -r1.120 eval.c
*** gdb/eval.c 22 Sep 2009 17:39:53 -0000 1.120
--- gdb/eval.c 25 Sep 2009 17:54:25 -0000
*************** evaluate_subexp_standard (struct type *e
*** 1161,1168 ****
if (addr)
{
struct symbol *sym = NULL;
- /* Is it a high_level symbol? */
sym = find_pc_function (addr);
if (sym != NULL)
method = value_of_variable (sym, 0);
--- 1161,1173 ----
if (addr)
{
struct symbol *sym = NULL;
+ /* The address might point to a function descriptor;
+ resolve it to the actual code address instead. */
+ addr = gdbarch_convert_from_func_ptr_addr (exp->gdbarch, addr,
+ ¤t_target);
+
+ /* Is it a high_level symbol? */
sym = find_pc_function (addr);
if (sym != NULL)
method = value_of_variable (sym, 0);
*************** evaluate_subexp_standard (struct type *e
*** 1216,1226 ****
{
if (TYPE_CODE (value_type (method)) != TYPE_CODE_FUNC)
error (_("method address has symbol information with non-function type; skipping"));
if (struct_return)
! set_value_address (method, value_as_address (msg_send_stret));
else
! set_value_address (method, value_as_address (msg_send));
! called_method = method;
}
else
{
--- 1221,1240 ----
{
if (TYPE_CODE (value_type (method)) != TYPE_CODE_FUNC)
error (_("method address has symbol information with non-function type; skipping"));
+
+ /* Create a function pointer of the appropriate type, and replace
+ its value with the value of msg_send or msg_send_stret. We must
+ use a pointer here, as msg_send and msg_send_stret are of pointer
+ type, and the representation may be different on systems that use
+ function descriptors. */
if (struct_return)
! called_method
! = value_from_pointer (lookup_pointer_type (value_type (method)),
! value_as_address (msg_send_stret));
else
! called_method
! = value_from_pointer (lookup_pointer_type (value_type (method)),
! value_as_address (msg_send));
}
else
{
*************** evaluate_subexp_standard (struct type *e
*** 1275,1281 ****
{
/* Function objc_msg_lookup returns a pointer. */
deprecated_set_value_type (argvec[0],
! lookup_function_type (lookup_pointer_type (value_type (argvec[0]))));
argvec[0] = call_function_by_hand (argvec[0], nargs + 2, argvec + 1);
}
--- 1289,1295 ----
{
/* Function objc_msg_lookup returns a pointer. */
deprecated_set_value_type (argvec[0],
! lookup_pointer_type (lookup_function_type (value_type (argvec[0]))));
argvec[0] = call_function_by_hand (argvec[0], nargs + 2, argvec + 1);
}
Index: gdb/linespec.c
===================================================================
RCS file: /cvs/src/src/gdb/linespec.c,v
retrieving revision 1.90
diff -c -p -r1.90 linespec.c
*** gdb/linespec.c 21 Sep 2009 19:46:43 -0000 1.90
--- gdb/linespec.c 25 Sep 2009 17:54:26 -0000
*************** decode_objc (char **argptr, int funfirst
*** 1172,1182 ****
}
else
{
! /* The only match was a non-debuggable symbol. */
! values.sals[0].symtab = NULL;
! values.sals[0].line = 0;
! values.sals[0].end = 0;
! values.sals[0].pc = SYMBOL_VALUE_ADDRESS (sym_arr[0]);
}
return values;
}
--- 1172,1190 ----
}
else
{
! /* The only match was a non-debuggable symbol, which might point
! to a function descriptor; resolve it to the actual code address
! instead. */
! struct minimal_symbol *msymbol = (struct minimal_symbol *)sym_arr[0];
! struct objfile *objfile = msymbol_objfile (msymbol);
! struct gdbarch *gdbarch = get_objfile_arch (objfile);
! CORE_ADDR pc = SYMBOL_VALUE_ADDRESS (msymbol);
!
! pc = gdbarch_convert_from_func_ptr_addr (gdbarch, pc,
! ¤t_target);
!
! init_sal (&values.sals[0]);
! values.sals[0].pc = pc;
}
return values;
}
Index: gdb/objc-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/objc-lang.c,v
retrieving revision 1.83
diff -c -p -r1.83 objc-lang.c
*** gdb/objc-lang.c 2 Jul 2009 17:25:57 -0000 1.83
--- gdb/objc-lang.c 25 Sep 2009 17:54:27 -0000
*************** find_methods (struct symtab *symtab, cha
*** 1173,1188 ****
ALL_OBJFILE_MSYMBOLS (objfile, msymbol)
{
QUIT;
! if ((MSYMBOL_TYPE (msymbol) != mst_text)
! && (MSYMBOL_TYPE (msymbol) != mst_file_text))
! /* Not a function or method. */
! continue;
if (symtab)
! if ((SYMBOL_VALUE_ADDRESS (msymbol) < BLOCK_START (block)) ||
! (SYMBOL_VALUE_ADDRESS (msymbol) >= BLOCK_END (block)))
/* Not in the specified symtab. */
continue;
--- 1173,1190 ----
ALL_OBJFILE_MSYMBOLS (objfile, msymbol)
{
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ CORE_ADDR pc = SYMBOL_VALUE_ADDRESS (msymbol);
+
QUIT;
! /* The minimal symbol might point to a function descriptor;
! resolve it to the actual code address instead. */
! pc = gdbarch_convert_from_func_ptr_addr (gdbarch, pc,
! ¤t_target);
if (symtab)
! if (pc < BLOCK_START (block) || pc >= BLOCK_END (block))
/* Not in the specified symtab. */
continue;
*************** find_methods (struct symtab *symtab, cha
*** 1221,1227 ****
((nselector == NULL) || (strcmp (selector, nselector) != 0)))
continue;
! sym = find_pc_function (SYMBOL_VALUE_ADDRESS (msymbol));
if (sym != NULL)
{
const char *newsymname = SYMBOL_NATURAL_NAME (sym);
--- 1223,1229 ----
((nselector == NULL) || (strcmp (selector, nselector) != 0)))
continue;
! sym = find_pc_function (pc);
if (sym != NULL)
{
const char *newsymname = SYMBOL_NATURAL_NAME (sym);
Index: gdb/ppc-sysv-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-sysv-tdep.c,v
retrieving revision 1.55
diff -c -p -r1.55 ppc-sysv-tdep.c
*** gdb/ppc-sysv-tdep.c 2 Jul 2009 17:25:58 -0000 1.55
--- gdb/ppc-sysv-tdep.c 25 Sep 2009 17:54:27 -0000
*************** ppc64_sysv_abi_push_dummy_call (struct g
*** 1326,1335 ****
regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
/* Use the func_addr to find the descriptor, and use that to find
! the TOC. */
{
! CORE_ADDR desc_addr;
! if (convert_code_addr_to_desc_addr (func_addr, &desc_addr))
{
/* The TOC is the second double word in the descriptor. */
CORE_ADDR toc =
--- 1326,1339 ----
regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
/* Use the func_addr to find the descriptor, and use that to find
! the TOC. If we're calling via a function pointer, the pointer
! itself identifies the descriptor. */
{
! struct type *ftype = check_typedef (value_type (function));
! CORE_ADDR desc_addr = value_as_address (function);
!
! if (TYPE_CODE (ftype) == TYPE_CODE_PTR
! || convert_code_addr_to_desc_addr (func_addr, &desc_addr))
{
/* The TOC is the second double word in the descriptor. */
CORE_ADDR toc =
--
Dr. Ulrich Weigand
GNU Toolchain for Linux on System z and Cell BE
Ulrich.Weigand@de.ibm.com