• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /* Function return value location for Linux/PPC ABI.
2     Copyright (C) 2005, 2006, 2007, 2010, 2014 Red Hat, Inc.
3     This file is part of elfutils.
4  
5     This file is free software; you can redistribute it and/or modify
6     it under the terms of either
7  
8       * the GNU Lesser General Public License as published by the Free
9         Software Foundation; either version 3 of the License, or (at
10         your option) any later version
11  
12     or
13  
14       * the GNU General Public License as published by the Free
15         Software Foundation; either version 2 of the License, or (at
16         your option) any later version
17  
18     or both in parallel, as here.
19  
20     elfutils is distributed in the hope that it will be useful, but
21     WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23     General Public License for more details.
24  
25     You should have received copies of the GNU General Public License and
26     the GNU Lesser General Public License along with this program.  If
27     not, see <http://www.gnu.org/licenses/>.  */
28  
29  #ifdef HAVE_CONFIG_H
30  # include <config.h>
31  #endif
32  
33  #include <assert.h>
34  #include <dwarf.h>
35  
36  #define BACKEND ppc_
37  #include "libebl_CPU.h"
38  
39  
40  /* This is the SVR4 ELF ABI convention, but AIX and Linux do not use it.  */
41  #define SVR4_STRUCT_RETURN 0
42  
43  
44  /* r3, or pair r3, r4, or quad r3-r6.  */
45  static const Dwarf_Op loc_intreg[] =
46    {
47      { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 4 },
48      { .atom = DW_OP_reg4 }, { .atom = DW_OP_piece, .number = 4 },
49      { .atom = DW_OP_reg5 }, { .atom = DW_OP_piece, .number = 4 },
50      { .atom = DW_OP_reg6 }, { .atom = DW_OP_piece, .number = 4 },
51    };
52  #define nloc_intreg	1
53  #define nloc_intregpair	4
54  #define nloc_intregquad	8
55  
56  /* f1.  */
57  static const Dwarf_Op loc_fpreg[] =
58    {
59      { .atom = DW_OP_regx, .number = 33 }
60    };
61  #define nloc_fpreg	1
62  
63  /* vr2.  */
64  static const Dwarf_Op loc_vmxreg[] =
65    {
66      { .atom = DW_OP_regx, .number = 1124 + 2 }
67    };
68  #define nloc_vmxreg	1
69  
70  /* The return value is a structure and is actually stored in stack space
71     passed in a hidden argument by the caller.  But, the compiler
72     helpfully returns the address of that space in r3.  */
73  static const Dwarf_Op loc_aggregate[] =
74    {
75      { .atom = DW_OP_breg3, .number = 0 }
76    };
77  #define nloc_aggregate 1
78  
79  
80  /* XXX We should check the SHT_GNU_ATTRIBUTES bits here (or in ppc_init).  */
81  static bool
ppc_altivec_abi(void)82  ppc_altivec_abi (void)
83  {
84    return true;
85  }
86  
87  int
ppc_return_value_location(Dwarf_Die * functypedie,const Dwarf_Op ** locp)88  ppc_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
89  {
90    /* Start with the function's type, and get the DW_AT_type attribute,
91       which is the type of the return value.  */
92    Dwarf_Die die_mem, *typedie = &die_mem;
93    int tag = dwarf_peeled_die_type (functypedie, typedie);
94    if (tag <= 0)
95      return tag;
96  
97    Dwarf_Word size;
98    switch (tag)
99      {
100      case -1:
101        return -1;
102  
103      case DW_TAG_subrange_type:
104        if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
105  	{
106  	  Dwarf_Attribute attr_mem, *attr;
107  	  attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
108  	  typedie = dwarf_formref_die (attr, &die_mem);
109  	  tag = DWARF_TAG_OR_RETURN (typedie);
110  	}
111        FALLTHROUGH;
112  
113      case DW_TAG_base_type:
114      case DW_TAG_enumeration_type:
115      case DW_TAG_pointer_type:
116      case DW_TAG_ptr_to_member_type:
117        {
118  	Dwarf_Attribute attr_mem;
119  	if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
120  						   &attr_mem), &size) != 0)
121  	  {
122  	    if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
123  	      size = 4;
124  	    else
125  	      return -1;
126  	  }
127        }
128  
129        if (size <= 8)
130  	{
131  	  if (tag == DW_TAG_base_type)
132  	    {
133  	      Dwarf_Attribute attr_mem;
134  	      Dwarf_Word encoding;
135  	      if (dwarf_formudata (dwarf_attr_integrate (typedie,
136  							 DW_AT_encoding,
137  							 &attr_mem),
138  				   &encoding) != 0)
139  		return -1;
140  	      if (encoding == DW_ATE_float)
141  		{
142  		  *locp = loc_fpreg;
143  		  return nloc_fpreg;
144  		}
145  	    }
146  	intreg:
147  	  *locp = loc_intreg;
148  	  return size <= 4 ? nloc_intreg : nloc_intregpair;
149  	}
150  
151      aggregate:
152        *locp = loc_aggregate;
153        return nloc_aggregate;
154  
155      case DW_TAG_array_type:
156        {
157  	Dwarf_Attribute attr_mem;
158  	bool is_vector;
159  	if (dwarf_formflag (dwarf_attr_integrate (typedie, DW_AT_GNU_vector,
160  						  &attr_mem), &is_vector) == 0
161  	    && is_vector
162  	    && dwarf_aggregate_size (typedie, &size) == 0)
163  	  switch (size)
164  	    {
165  	    case 16:
166  	      if (ppc_altivec_abi ())
167  		{
168  		  *locp = loc_vmxreg;
169  		  return nloc_vmxreg;
170  		}
171  	      *locp = loc_intreg;
172  	      return nloc_intregquad;
173  	    }
174        }
175        FALLTHROUGH;
176  
177      case DW_TAG_structure_type:
178      case DW_TAG_class_type:
179      case DW_TAG_union_type:
180        if (SVR4_STRUCT_RETURN
181  	  && dwarf_aggregate_size (typedie, &size) == 0
182  	  && size > 0 && size <= 8)
183  	goto intreg;
184        goto aggregate;
185      }
186  
187    /* XXX We don't have a good way to return specific errors from ebl calls.
188       This value means we do not understand the type, but it is well-formed
189       DWARF and might be valid.  */
190    return -2;
191  }
192