Line data Source code
1 : /* Function return value location for Linux/x86-64 ABI.
2 : Copyright (C) 2005-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 x86_64_
37 : #include "libebl_CPU.h"
38 :
39 :
40 : /* %rax, or pair %rax, %rdx. */
41 : static const Dwarf_Op loc_intreg[] =
42 : {
43 : { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 8 },
44 : { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 8 },
45 : };
46 : #define nloc_intreg 1
47 : #define nloc_intregpair 4
48 :
49 : /* %st(0), or pair %st(0), %st(1). */
50 : static const Dwarf_Op loc_x87reg[] =
51 : {
52 : { .atom = DW_OP_regx, .number = 33 },
53 : { .atom = DW_OP_piece, .number = 10 },
54 : { .atom = DW_OP_regx, .number = 34 },
55 : { .atom = DW_OP_piece, .number = 10 },
56 : };
57 : #define nloc_x87reg 1
58 : #define nloc_x87regpair 4
59 :
60 : /* %xmm0, or pair %xmm0, %xmm1. */
61 : static const Dwarf_Op loc_ssereg[] =
62 : {
63 : { .atom = DW_OP_reg17 }, { .atom = DW_OP_piece, .number = 16 },
64 : { .atom = DW_OP_reg18 }, { .atom = DW_OP_piece, .number = 16 },
65 : };
66 : #define nloc_ssereg 1
67 : #define nloc_sseregpair 4
68 :
69 : /* The return value is a structure and is actually stored in stack space
70 : passed in a hidden argument by the caller. But, the compiler
71 : helpfully returns the address of that space in %rax. */
72 : static const Dwarf_Op loc_aggregate[] =
73 : {
74 : { .atom = DW_OP_breg0, .number = 0 }
75 : };
76 : #define nloc_aggregate 1
77 :
78 :
79 : int
80 10417 : x86_64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
81 : {
82 : /* Start with the function's type, and get the DW_AT_type attribute,
83 : which is the type of the return value. */
84 10417 : Dwarf_Die die_mem, *typedie = &die_mem;
85 10417 : int tag = dwarf_peeled_die_type (functypedie, typedie);
86 10417 : if (tag <= 0)
87 : return tag;
88 :
89 8324 : Dwarf_Word size;
90 8324 : switch (tag)
91 : {
92 : case -1:
93 : return -1;
94 :
95 0 : case DW_TAG_subrange_type:
96 0 : if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
97 : {
98 0 : Dwarf_Attribute attr_mem, *attr;
99 0 : attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
100 0 : typedie = dwarf_formref_die (attr, &die_mem);
101 0 : tag = DWARF_TAG_OR_RETURN (typedie);
102 : }
103 8256 : FALLTHROUGH;
104 :
105 : case DW_TAG_base_type:
106 : case DW_TAG_enumeration_type:
107 : case DW_TAG_pointer_type:
108 : case DW_TAG_ptr_to_member_type:
109 8256 : {
110 8256 : Dwarf_Attribute attr_mem;
111 8256 : if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
112 : &attr_mem), &size) != 0)
113 : {
114 0 : if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
115 0 : size = 8;
116 : else
117 0 : return -1;
118 : }
119 : }
120 :
121 8256 : if (tag == DW_TAG_base_type)
122 : {
123 5960 : Dwarf_Attribute attr_mem;
124 5960 : Dwarf_Word encoding;
125 5960 : if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
126 : &attr_mem),
127 : &encoding) != 0)
128 190 : return -1;
129 :
130 5960 : switch (encoding)
131 : {
132 0 : case DW_ATE_complex_float:
133 0 : switch (size)
134 : {
135 0 : case 4 * 2: /* complex float */
136 : case 8 * 2: /* complex double */
137 0 : *locp = loc_ssereg;
138 0 : return nloc_sseregpair;
139 0 : case 16 * 2: /* complex long double */
140 0 : *locp = loc_x87reg;
141 0 : return nloc_x87regpair;
142 : }
143 : return -2;
144 :
145 190 : case DW_ATE_float:
146 190 : switch (size)
147 : {
148 100 : case 4: /* float */
149 : case 8: /* double */
150 100 : *locp = loc_ssereg;
151 100 : return nloc_ssereg;
152 90 : case 16: /* long double */
153 : /* XXX distinguish __float128, which is sseregpair?? */
154 90 : *locp = loc_x87reg;
155 90 : return nloc_x87reg;
156 : }
157 : return -2;
158 : }
159 : }
160 :
161 2296 : intreg:
162 8132 : *locp = loc_intreg;
163 8132 : if (size <= 8)
164 : return nloc_intreg;
165 62 : if (size <= 16)
166 : return nloc_intregpair;
167 :
168 0 : large:
169 2 : *locp = loc_aggregate;
170 2 : return nloc_aggregate;
171 :
172 68 : case DW_TAG_structure_type:
173 : case DW_TAG_class_type:
174 : case DW_TAG_union_type:
175 : case DW_TAG_array_type:
176 68 : if (dwarf_aggregate_size (typedie, &size) != 0)
177 : goto large;
178 68 : if (size > 16)
179 : goto large;
180 :
181 : /* XXX
182 : Must examine the fields in picayune ways to determine the
183 : actual answer. This will be right for small C structs
184 : containing integer types and similarly simple cases.
185 : */
186 :
187 : goto intreg;
188 : }
189 :
190 : /* XXX We don't have a good way to return specific errors from ebl calls.
191 : This value means we do not understand the type, but it is well-formed
192 : DWARF and might be valid. */
193 0 : return -2;
194 : }
|