Branch data Line data Source code
1 : : /* Function return value location for Linux/mips ABI.
2 : : Copyright (C) 2005 Red Hat, Inc.
3 : : Copyright (C) 2024 CIP United Inc.
4 : : This file is part of elfutils.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of either
8 : :
9 : : * the GNU Lesser General Public License as published by the Free
10 : : Software Foundation; either version 3 of the License, or (at
11 : : your option) any later version
12 : :
13 : : or
14 : :
15 : : * the GNU General Public License as published by the Free
16 : : Software Foundation; either version 2 of the License, or (at
17 : : your option) any later version
18 : :
19 : : or both in parallel, as here.
20 : :
21 : : elfutils is distributed in the hope that it will be useful, but
22 : : WITHOUT ANY WARRANTY; without even the implied warranty of
23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : : General Public License for more details.
25 : :
26 : : You should have received copies of the GNU General Public License and
27 : : the GNU Lesser General Public License along with this program. If
28 : : not, see <http://www.gnu.org/licenses/>. */
29 : :
30 : : #ifdef HAVE_CONFIG_H
31 : : # include <config.h>
32 : : #endif
33 : :
34 : : #include <assert.h>
35 : : #include <dwarf.h>
36 : : #include <string.h>
37 : : #include <elf.h>
38 : : #include <stdio.h>
39 : :
40 : : #define BACKEND mips_
41 : : #include "libebl_CPU.h"
42 : : #include "libdwP.h"
43 : : #include <stdio.h>
44 : :
45 : : /* $v0 or pair $v0, $v1 */
46 : : static const Dwarf_Op loc_intreg_o32[] =
47 : : {
48 : : { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 4 },
49 : : { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 4 },
50 : : };
51 : :
52 : : static const Dwarf_Op loc_intreg[] =
53 : : {
54 : : { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 8 },
55 : : { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 8 },
56 : : };
57 : : #define nloc_intreg 1
58 : : #define nloc_intregpair 4
59 : :
60 : : /* $f0 (float), or pair $f0, $f1 (double).
61 : : * f2/f3 are used for COMPLEX (= 2 doubles) returns in Fortran */
62 : : static const Dwarf_Op loc_fpreg_o32[] =
63 : : {
64 : : { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 4 },
65 : : { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 4 },
66 : : { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 4 },
67 : : { .atom = DW_OP_regx, .number = 35 }, { .atom = DW_OP_piece, .number = 4 },
68 : : };
69 : :
70 : : /* $f0, or pair $f0, $f2. */
71 : : static const Dwarf_Op loc_fpreg[] =
72 : : {
73 : : { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 8 },
74 : : { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 8 },
75 : : };
76 : : #define nloc_fpreg 1
77 : : #define nloc_fpregpair 4
78 : : #define nloc_fpregquad 8
79 : :
80 : : /* The return value is a structure and is actually stored in stack space
81 : : passed in a hidden argument by the caller. But, the compiler
82 : : helpfully returns the address of that space in $v0. */
83 : : static const Dwarf_Op loc_aggregate[] =
84 : : {
85 : : { .atom = DW_OP_breg2, .number = 0 }
86 : : };
87 : : #define nloc_aggregate 1
88 : :
89 : : int
90 : 0 : mips_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
91 : : {
92 [ # # ]: 0 : unsigned int regsize = (gelf_getclass (functypedie->cu->dbg->elf) == ELFCLASS32 ) ? 4 : 8;
93 : 0 : if (!regsize)
94 : : return -2;
95 : :
96 : : /* Start with the function's type, and get the DW_AT_type attribute,
97 : : which is the type of the return value. */
98 : :
99 : 0 : Dwarf_Attribute attr_mem;
100 : 0 : Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type, &attr_mem);
101 [ # # ]: 0 : if (attr == NULL)
102 : : /* The function has no return value, like a `void' function in C. */
103 : : return 0;
104 : :
105 : 0 : Dwarf_Die die_mem;
106 : 0 : Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem);
107 : 0 : int tag = dwarf_tag (typedie);
108 : :
109 : : /* Follow typedefs and qualifiers to get to the actual type. */
110 : 0 : while (tag == DW_TAG_typedef
111 : 0 : || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type
112 [ # # # # ]: 0 : || tag == DW_TAG_restrict_type)
113 : : {
114 : 0 : attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
115 : 0 : typedie = dwarf_formref_die (attr, &die_mem);
116 : 0 : tag = dwarf_tag (typedie);
117 : : }
118 : :
119 [ # # # # : 0 : switch (tag)
# # ]
120 : : {
121 : : case -1:
122 : : return -1;
123 : :
124 : 0 : case DW_TAG_subrange_type:
125 [ # # ]: 0 : if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
126 : : {
127 : 0 : attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
128 : 0 : typedie = dwarf_formref_die (attr, &die_mem);
129 : 0 : tag = dwarf_tag (typedie);
130 : : }
131 : : /* Fall through. */
132 : 0 : FALLTHROUGH;
133 : :
134 : : case DW_TAG_base_type:
135 : : case DW_TAG_enumeration_type:
136 : : CASE_POINTER:
137 : : {
138 : 0 : Dwarf_Word size;
139 [ # # ]: 0 : if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
140 : : &attr_mem), &size) != 0)
141 : : {
142 [ # # ]: 0 : if (dwarf_is_pointer (tag))
143 : 0 : size = regsize;
144 : : else
145 : 0 : return -1;
146 : : }
147 [ # # ]: 0 : if (tag == DW_TAG_base_type)
148 : : {
149 : 0 : Dwarf_Word encoding;
150 [ # # ]: 0 : if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
151 : : &attr_mem), &encoding) != 0)
152 : 0 : return -1;
153 : :
154 : : #define ARCH_LOC(loc, regsize) ((regsize) == 4 ? (loc ## _o32) : (loc))
155 : :
156 [ # # ]: 0 : if (encoding == DW_ATE_float)
157 : : {
158 [ # # ]: 0 : *locp = ARCH_LOC(loc_fpreg, regsize);
159 [ # # ]: 0 : if (size <= regsize)
160 : : return nloc_fpreg;
161 : :
162 [ # # ]: 0 : if (size <= 2*regsize)
163 : : return nloc_fpregpair;
164 : :
165 [ # # ]: 0 : if (size <= 4*regsize)
166 : : return nloc_fpregquad;
167 : :
168 : 0 : goto aggregate;
169 : : }
170 : : }
171 [ # # ]: 0 : *locp = ARCH_LOC(loc_intreg, regsize);
172 [ # # ]: 0 : if (size <= regsize)
173 : : return nloc_intreg;
174 [ # # ]: 0 : if (size <= 2*regsize)
175 : : return nloc_intregpair;
176 : :
177 : : /* Else fall through. Shouldn't happen though (at least with gcc) */
178 : : }
179 : 0 : FALLTHROUGH;
180 : :
181 : : case DW_TAG_structure_type:
182 : : case DW_TAG_class_type:
183 : : case DW_TAG_union_type:
184 : : case DW_TAG_array_type:
185 : 0 : aggregate:
186 : 0 : *locp = loc_aggregate;
187 : 0 : return nloc_aggregate;
188 : : case DW_TAG_unspecified_type:
189 : : return 0;
190 : : }
191 : :
192 : : /* XXX We don't have a good way to return specific errors from ebl calls.
193 : : This value means we do not understand the type, but it is well-formed
194 : : DWARF and might be valid. */
195 : 0 : return -2;
196 : : }
|