From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31784 invoked by alias); 13 Jan 2011 22:57:55 -0000 Received: (qmail 31775 invoked by uid 22791); 13 Jan 2011 22:57:54 -0000 X-SWARE-Spam-Status: No, hits=-2.3 required=5.0 tests=AWL,BAYES_00,SPF_FAIL,TW_EG X-Spam-Check-By: sourceware.org Received: from gate.lvk.cs.msu.su (HELO mail.lvk.cs.msu.su) (158.250.17.1) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 13 Jan 2011 22:57:48 +0000 Received: from mail.lvk.cs.msu.su (localhost [127.0.0.1]) by mail.lvk.cs.msu.su (Postfix) with ESMTP id 3204F13EE; Fri, 14 Jan 2011 01:57:40 +0300 (MSK) X-Spam-ASN: Received: from thunder.localnet (h86-62-88-129.ln.rinet.ru [86.62.88.129]) by mail.lvk.cs.msu.su (Postfix) with ESMTPSA id 2052D12E0; Fri, 14 Jan 2011 01:57:40 +0300 (MSK) From: Vladimir Prus To: gdb-patches@sources.redhat.com Subject: m68k-elf return value registers Date: Thu, 13 Jan 2011 23:04:00 -0000 User-Agent: KMail/1.13.5 (Linux/2.6.35-24-generic-pae; KDE/4.5.1; i686; ; ) MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_iN4LNbuI33OSenv" Message-Id: <201101140157.38487.vladimir@codesourcery.com> X-AV-Checked: ClamAV using ClamSMTP Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-01/txt/msg00309.txt.bz2 --Boundary-00=_iN4LNbuI33OSenv Content-Type: Text/Plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-length: 1331 This patch, originally written by Nathan Sidwel, makes m68k-tdep.c use right registrers for returning values from functions on bare metal. There are actually 3 parts: 1. Right now, it's assumed that pointer values are returned in %a0. However, for m68k-elf, they are returned in %d0. So, this patch makes %a0 the default, and then makes OSABI sniffers set %a0 again. 2. Structures can be returned in either %a0 or %a1. This was discussed previously at: http://thread.gmane.org/gmane.comp.gdb.devel/20117 I have now put together a table listing what register gcc uses, and how gdb does the same with this patch. See: http://tinyurl.com/5r2j5x6 As you see, in the end we have only uclinuxoldeabi using wrong register (just as now). I am not sure whether (i) this can be fixed, and (ii) anybody care, given that this target was proposed for deprecation in gcc 4.6. Anyway, if somebody cares, it can be done with a separate patch. 3. This patch also updates the logic that decides whether structure is returned in memory or registers. This is a black magic written by Nathan that I don't pretend to understand. Is this OK? I have tests still running, but they will only cover elf and linux, so it would be great to have somebody check behaviour for other targets. -- Vladimir Prus Mentor Graphics +7 (812) 677-68-40 --Boundary-00=_iN4LNbuI33OSenv Content-Type: text/x-patch; charset="UTF-8"; name="m68k-return.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="m68k-return.diff" Content-length: 8507 commit 45c4637b3cf602268bb69b9e7fc045d5cbb70d71 Author: Vladimir Prus Date: Fri Jan 14 00:10:12 2011 +0300 Use the right structure and pointer return registers on m68k-elf. * m68k-tdep.h (struct gdbarch_tdep): Add ptr_value_regnum field. * m68k-tdep.c (m68k_gdbarch_init): Use A0 for structure returns on ELF targets, A1 otherwise. Use %d0 for ptr_value_regnum. (m68k_svr4_extract_return_value): Use tdep->ptr_value_regnum for pointer returns. (m68k_svr4_store_return_value): Likewise. (m68k_reg_struct_return_r): New, broken out of ... (m68k_reg_struct_return_p): ... here. Implement gcc's structure mode algorithm. (m68k_svr4_init_abi): No need to specify %a0 for structure returns here. Set ptr_value_regnum, though. * m68kbsd-tdep.c (m68kbsd_aout_init_abi): Set ptr_value_regnum to A0. (m68kbsd_elf_init_abi): Use A1 for struct return on OpenBSD. diff --git a/gdb/m68k-tdep.c b/gdb/m68k-tdep.c index 082cb84..194ecf3 100644 --- a/gdb/m68k-tdep.c +++ b/gdb/m68k-tdep.c @@ -320,7 +320,7 @@ m68k_svr4_extract_return_value (struct type *type, struct regcache *regcache, convert_typed_floating (buf, fpreg_type, valbuf, type); } else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4) - regcache_raw_read (regcache, M68K_A0_REGNUM, valbuf); + regcache_raw_read (regcache, tdep->ptr_value_regnum, valbuf); else m68k_extract_return_value (type, regcache, valbuf); } @@ -362,16 +362,77 @@ m68k_svr4_store_return_value (struct type *type, struct regcache *regcache, regcache_raw_write (regcache, M68K_FP0_REGNUM, buf); } else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4) - { - regcache_raw_write (regcache, M68K_A0_REGNUM, valbuf); - regcache_raw_write (regcache, M68K_D0_REGNUM, valbuf); - } + regcache_raw_write (regcache, tdep->ptr_value_regnum, valbuf); else m68k_store_return_value (type, regcache, valbuf); } /* Return non-zero if TYPE, which is assumed to be a structure or union type, should be returned in registers for architecture + GDBARCH. + + Unfortunately GCC incorrectly implements this optimization. Rather + than simply return all small structs, or even just those of size + 2^N, it uses the mode of the structure to determine this. BLKmode + structs will be returned by memory and QI,HI,SI,DI,SF&DF mode + structs will be returned by register. For m68k a struct is BLKmode + unless it's size is 2^N and the mode for that size does not need a + greater alignment than the structure itself. This is horrible. */ + + +static int +m68k_reg_struct_return_r (struct type *type, int *align_p) +{ + enum type_code code = TYPE_CODE (type); + int len = TYPE_LENGTH (type); + int field_align = 1; + int my_align = len > 2 ? 2 : len; + int ix; + + if (code != TYPE_CODE_STRUCT && code != TYPE_CODE_UNION) + { + if (align_p && my_align > *align_p) + *align_p = my_align; + return 1; + } + + if ((len & -len) != len) + /* Length is not 2^n. */ + return 0; + + for (ix = 0; ix != TYPE_NFIELDS (type); ix++) + { + struct type *field_type; + int field_len; + + if (field_is_static (&TYPE_FIELD (type, ix))) + /* Skip static fields. */ + continue; + + field_type = TYPE_FIELD_TYPE (type, ix); + field_type = check_typedef (field_type); + field_len = TYPE_LENGTH (field_type); + + /* Look through arrays. */ + while (TYPE_CODE (field_type) == TYPE_CODE_ARRAY) + { + field_type = TYPE_TARGET_TYPE (field_type); + field_type = check_typedef (field_type); + field_len = TYPE_LENGTH (field_type); + } + + if (!m68k_reg_struct_return_r (field_type, &field_align)) + return 0; + } + + if (align_p && field_align > *align_p) + *align_p = field_align; + + return align_p || my_align <= field_align; +} + +/* Return non-zero if TYPE, which is assumed to be a structure or + union type, should be returned in registers for architecture GDBARCH. */ static int @@ -386,7 +447,11 @@ m68k_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type) if (tdep->struct_return == pcc_struct_return) return 0; - return (len == 1 || len == 2 || len == 4 || len == 8); + if (len > 8) + /* Length is too big. */ + return 0; + + return m68k_reg_struct_return_r (type, NULL); } /* Determine, for architecture GDBARCH, how a return value of TYPE @@ -440,25 +505,11 @@ m68k_svr4_return_value (struct gdbarch *gdbarch, struct type *func_type, if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION) && !m68k_reg_struct_return_p (gdbarch, type)) { - /* The System V ABI says that: - - "A function returning a structure or union also sets %a0 to - the value it finds in %a0. Thus when the caller receives - control again, the address of the returned object resides in - register %a0." - - So the ABI guarantees that we can always find the return - value just after the function has returned. */ - - if (readbuf) - { - ULONGEST addr; - - regcache_raw_read_unsigned (regcache, M68K_A0_REGNUM, &addr); - read_memory (addr, readbuf, TYPE_LENGTH (type)); - } - - return RETURN_VALUE_ABI_RETURNS_ADDRESS; + /* Although they SYSV ABI specifies that a function returning a + structure this way should preserve %a0, GCC doesn't do that. + Furthermore there's no point changeing GCC to make it do it, + as that would just be bloat. */ + return RETURN_VALUE_STRUCT_CONVENTION; } /* This special case is for structures consisting of a single @@ -1053,8 +1104,7 @@ m68k_svr4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* SVR4 uses a different calling convention. */ set_gdbarch_return_value (gdbarch, m68k_svr4_return_value); - /* SVR4 uses %a0 instead of %a1. */ - tdep->struct_value_regnum = M68K_A0_REGNUM; + tdep->ptr_value_regnum = M68K_A0_REGNUM; } @@ -1228,7 +1278,17 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Function call & return. */ set_gdbarch_push_dummy_call (gdbarch, m68k_push_dummy_call); set_gdbarch_return_value (gdbarch, m68k_return_value); + tdep->struct_return = reg_struct_return; + /* These register numbers may be overridden by an OSABI + sniffer. */ + if (info.abfd == NULL) + tdep->struct_value_regnum = M68K_A0_REGNUM; + else if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour) + tdep->struct_value_regnum = M68K_A0_REGNUM; + else + tdep->struct_value_regnum = M68K_A1_REGNUM; + tdep->ptr_value_regnum = M68K_D0_REGNUM; /* Disassembler. */ set_gdbarch_print_insn (gdbarch, print_insn_m68k); @@ -1239,8 +1299,6 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) #else tdep->jb_pc = -1; #endif - tdep->struct_value_regnum = M68K_A1_REGNUM; - tdep->struct_return = reg_struct_return; /* Frame unwinder. */ set_gdbarch_dummy_id (gdbarch, m68k_dummy_id); diff --git a/gdb/m68k-tdep.h b/gdb/m68k-tdep.h index 596a8cb..3ea7f24 100644 --- a/gdb/m68k-tdep.h +++ b/gdb/m68k-tdep.h @@ -83,6 +83,9 @@ struct gdbarch_tdep /* Convention for returning structures. */ enum struct_return struct_return; + /* Register in which pointers are returned. */ + int ptr_value_regnum; + /* Convention for returning floats. zero in int regs, non-zero in float. */ int float_return; diff --git a/gdb/m68kbsd-tdep.c b/gdb/m68kbsd-tdep.c index 81e34e9..f5bfa1a 100644 --- a/gdb/m68kbsd-tdep.c +++ b/gdb/m68kbsd-tdep.c @@ -213,11 +213,12 @@ m68kbsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) m68kbsd_init_abi (info, gdbarch); tdep->struct_return = reg_struct_return; + tdep->ptr_value_regnum = M68K_A0_REGNUM; tramp_frame_prepend_unwinder (gdbarch, &m68kobsd_sigtramp); } -/* NetBSD ELF. */ +/* OpenBSD and NetBSD ELF. */ static void m68kbsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) @@ -233,6 +234,15 @@ m68kbsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* NetBSD ELF uses SVR4-style shared libraries. */ set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_ilp32_fetch_link_map_offsets); + + /* OpenBSD uses %a1to return structures. */ + if (info.abfd) + { + enum gdb_osabi osabi = gdbarch_lookup_osabi (info.abfd); + + if (osabi == GDB_OSABI_OPENBSD_ELF) + tdep->struct_value_regnum = M68K_A1_REGNUM; + } } --Boundary-00=_iN4LNbuI33OSenv--