1 /*
2 * This file is part of ltrace.
3 * Copyright (C) 2014 Petr Machata, Red Hat, Inc.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 */
20
21 #include <sys/ptrace.h>
22 #include <asm/ptrace.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdint.h>
26
27 #include "fetch.h"
28 #include "proc.h"
29 #include "type.h"
30 #include "value.h"
31
32 int aarch64_read_gregs(struct process *proc, struct user_pt_regs *regs);
33 int aarch64_read_fregs(struct process *proc, struct user_fpsimd_state *regs);
34
35
36 struct fetch_context
37 {
38 struct user_pt_regs gregs;
39 struct user_fpsimd_state fpregs;
40 arch_addr_t nsaa;
41 unsigned ngrn;
42 unsigned nsrn;
43 arch_addr_t x8;
44 };
45
46 static int
context_init(struct fetch_context * context,struct process * proc)47 context_init(struct fetch_context *context, struct process *proc)
48 {
49 if (aarch64_read_gregs(proc, &context->gregs) < 0
50 || aarch64_read_fregs(proc, &context->fpregs) < 0)
51 return -1;
52
53 context->ngrn = 0;
54 context->nsrn = 0;
55 /* XXX double cast */
56 context->nsaa = (arch_addr_t) (uintptr_t) context->gregs.sp;
57 context->x8 = 0;
58
59 return 0;
60 }
61
62 struct fetch_context *
arch_fetch_arg_clone(struct process * proc,struct fetch_context * context)63 arch_fetch_arg_clone(struct process *proc, struct fetch_context *context)
64 {
65 struct fetch_context *ret = malloc(sizeof(*ret));
66 if (ret == NULL)
67 return NULL;
68 return memcpy(ret, context, sizeof(*ret));
69 }
70
71 static void
fetch_next_gpr(struct fetch_context * context,unsigned char * buf)72 fetch_next_gpr(struct fetch_context *context, unsigned char *buf)
73 {
74 uint64_t u = context->gregs.regs[context->ngrn++];
75 memcpy(buf, &u, 8);
76 }
77
78 static int
fetch_gpr(struct fetch_context * context,struct value * value,size_t sz)79 fetch_gpr(struct fetch_context *context, struct value *value, size_t sz)
80 {
81 if (sz < 8)
82 sz = 8;
83
84 unsigned char *buf = value_reserve(value, sz);
85 if (buf == NULL)
86 return -1;
87
88 size_t i;
89 for (i = 0; i < sz; i += 8)
90 fetch_next_gpr(context, buf + i);
91
92 return 0;
93 }
94
95 static void
fetch_next_sse(struct fetch_context * context,unsigned char * buf,size_t sz)96 fetch_next_sse(struct fetch_context *context, unsigned char *buf, size_t sz)
97 {
98 __int128 u = context->fpregs.vregs[context->nsrn++];
99 memcpy(buf, &u, sz);
100 }
101
102 static int
fetch_sse(struct fetch_context * context,struct value * value,size_t sz)103 fetch_sse(struct fetch_context *context, struct value *value, size_t sz)
104 {
105 unsigned char *buf = value_reserve(value, sz);
106 if (buf == NULL)
107 return -1;
108
109 fetch_next_sse(context, buf, sz);
110 return 0;
111 }
112
113 static int
fetch_hfa(struct fetch_context * context,struct value * value,struct arg_type_info * hfa_t,size_t count)114 fetch_hfa(struct fetch_context *context,
115 struct value *value, struct arg_type_info *hfa_t, size_t count)
116 {
117 size_t sz = type_sizeof(value->inferior, hfa_t);
118 unsigned char *buf = value_reserve(value, sz * count);
119 if (buf == NULL)
120 return -1;
121
122 size_t i;
123 for (i = 0; i < count; ++i) {
124 fetch_next_sse(context, buf, sz);
125 buf += sz;
126 }
127 return 0;
128 }
129
130 static int
fetch_stack(struct fetch_context * context,struct value * value,size_t align,size_t sz)131 fetch_stack(struct fetch_context *context, struct value *value,
132 size_t align, size_t sz)
133 {
134 if (align < 8)
135 align = 8;
136 size_t amount = ((sz + align - 1) / align) * align;
137
138 /* XXX double casts */
139 uintptr_t sp = (uintptr_t) context->nsaa;
140 sp = ((sp + align - 1) / align) * align;
141
142 value_in_inferior(value, (arch_addr_t) sp);
143
144 sp += amount;
145 context->nsaa = (arch_addr_t) sp;
146
147 return 0;
148 }
149
150 enum convert_method {
151 CVT_ERR = -1,
152 CVT_NOP = 0,
153 CVT_BYREF,
154 };
155
156 enum fetch_method {
157 FETCH_NOP,
158 FETCH_STACK,
159 FETCH_GPR,
160 FETCH_SSE,
161 FETCH_HFA,
162 };
163
164 struct fetch_script {
165 enum convert_method c;
166 enum fetch_method f;
167 size_t sz;
168 struct arg_type_info *hfa_t;
169 size_t count;
170 };
171
172 static struct fetch_script
pass_arg(struct fetch_context const * context,struct process * proc,struct arg_type_info * info)173 pass_arg(struct fetch_context const *context,
174 struct process *proc, struct arg_type_info *info)
175 {
176 enum fetch_method cvt = CVT_NOP;
177
178 size_t sz = type_sizeof(proc, info);
179 if (sz == (size_t) -1)
180 return (struct fetch_script) { CVT_ERR, FETCH_NOP, sz };
181
182 switch (info->type) {
183 case ARGTYPE_VOID:
184 return (struct fetch_script) { cvt, FETCH_NOP, sz };
185
186 case ARGTYPE_STRUCT:
187 case ARGTYPE_ARRAY:;
188 size_t count;
189 struct arg_type_info *hfa_t = type_get_hfa_type(info, &count);
190 if (hfa_t != NULL && count <= 4) {
191 if (context->nsrn + count <= 8)
192 return (struct fetch_script)
193 { cvt, FETCH_HFA, sz, hfa_t, count };
194 return (struct fetch_script)
195 { cvt, FETCH_STACK, sz, hfa_t, count };
196 }
197
198 if (sz <= 16) {
199 size_t count = sz / 8;
200 if (context->ngrn + count <= 8)
201 return (struct fetch_script)
202 { cvt, FETCH_GPR, sz };
203 }
204
205 cvt = CVT_BYREF;
206 sz = 8;
207 /* Fall through. */
208
209 case ARGTYPE_POINTER:
210 case ARGTYPE_INT:
211 case ARGTYPE_UINT:
212 case ARGTYPE_LONG:
213 case ARGTYPE_ULONG:
214 case ARGTYPE_CHAR:
215 case ARGTYPE_SHORT:
216 case ARGTYPE_USHORT:
217 if (context->ngrn < 8 && sz <= 8)
218 return (struct fetch_script) { cvt, FETCH_GPR, sz };
219 /* We don't support types wider than 8 bytes as of
220 * now. */
221 assert(sz <= 8);
222
223 return (struct fetch_script) { cvt, FETCH_STACK, sz };
224
225 case ARGTYPE_FLOAT:
226 case ARGTYPE_DOUBLE:
227 if (context->nsrn < 8) {
228 /* ltrace doesn't support float128. */
229 assert(sz <= 8);
230 return (struct fetch_script) { cvt, FETCH_SSE, sz };
231 }
232
233 return (struct fetch_script) { cvt, FETCH_STACK, sz };
234 }
235
236 assert(! "Failed to allocate argument.");
237 abort();
238 }
239
240 static int
convert_arg(struct value * value,struct fetch_script how)241 convert_arg(struct value *value, struct fetch_script how)
242 {
243 switch (how.c) {
244 case CVT_NOP:
245 return 0;
246 case CVT_BYREF:
247 return value_pass_by_reference(value);
248 case CVT_ERR:
249 return -1;
250 }
251
252 assert(! "Don't know how to convert argument.");
253 abort();
254 }
255
256 static int
fetch_arg(struct fetch_context * context,struct process * proc,struct arg_type_info * info,struct value * value,struct fetch_script how)257 fetch_arg(struct fetch_context *context,
258 struct process *proc, struct arg_type_info *info,
259 struct value *value, struct fetch_script how)
260 {
261 if (convert_arg(value, how) < 0)
262 return -1;
263
264 switch (how.f) {
265 case FETCH_NOP:
266 return 0;
267
268 case FETCH_STACK:
269 if (how.hfa_t != NULL && how.count != 0 && how.count <= 8)
270 context->nsrn = 8;
271 return fetch_stack(context, value,
272 type_alignof(proc, info), how.sz);
273
274 case FETCH_GPR:
275 return fetch_gpr(context, value, how.sz);
276
277 case FETCH_SSE:
278 return fetch_sse(context, value, how.sz);
279
280 case FETCH_HFA:
281 return fetch_hfa(context, value, how.hfa_t, how.count);
282 }
283
284 assert(! "Don't know how to fetch argument.");
285 abort();
286 }
287
288 struct fetch_context *
arch_fetch_arg_init(enum tof type,struct process * proc,struct arg_type_info * ret_info)289 arch_fetch_arg_init(enum tof type, struct process *proc,
290 struct arg_type_info *ret_info)
291 {
292 struct fetch_context *context = malloc(sizeof *context);
293 if (context == NULL || context_init(context, proc) < 0) {
294 fail:
295 free(context);
296 return NULL;
297 }
298
299 /* There's a provision in ARMv8 parameter passing convention
300 * for returning types that, if passed as first argument to a
301 * function, would be passed on stack. For those types, x8
302 * contains an address where the return argument should be
303 * placed. The callee doesn't need to preserve the value of
304 * x8, so we need to fetch it now.
305 *
306 * To my knowledge, there are currently no types where this
307 * holds, but the code is here, utterly untested. */
308
309 struct fetch_script how = pass_arg(context, proc, ret_info);
310 if (how.c == CVT_ERR)
311 goto fail;
312 if (how.c == CVT_NOP && how.f == FETCH_STACK) {
313 /* XXX double cast. */
314 context->x8 = (arch_addr_t) (uintptr_t) context->gregs.regs[8];
315 /* See the comment above about the assert. */
316 assert(! "Unexpected: first argument passed on stack.");
317 abort();
318 }
319
320 return context;
321 }
322
323 int
arch_fetch_arg_next(struct fetch_context * context,enum tof type,struct process * proc,struct arg_type_info * info,struct value * value)324 arch_fetch_arg_next(struct fetch_context *context, enum tof type,
325 struct process *proc, struct arg_type_info *info,
326 struct value *value)
327 {
328 return fetch_arg(context, proc, info, value,
329 pass_arg(context, proc, info));
330 }
331
332 int
arch_fetch_retval(struct fetch_context * context,enum tof type,struct process * proc,struct arg_type_info * info,struct value * value)333 arch_fetch_retval(struct fetch_context *context, enum tof type,
334 struct process *proc, struct arg_type_info *info,
335 struct value *value)
336 {
337 if (context->x8 != 0) {
338 value_in_inferior(value, context->x8);
339 return 0;
340 }
341
342 if (context_init(context, proc) < 0)
343 return -1;
344
345 return fetch_arg(context, proc, info, value,
346 pass_arg(context, proc, info));
347 }
348
349 void
arch_fetch_arg_done(struct fetch_context * context)350 arch_fetch_arg_done(struct fetch_context *context)
351 {
352 if (context != NULL)
353 free(context);
354 }
355
356 size_t
arch_type_sizeof(struct process * proc,struct arg_type_info * arg)357 arch_type_sizeof(struct process *proc, struct arg_type_info *arg)
358 {
359 return (size_t) -2;
360 }
361
362 size_t
arch_type_alignof(struct process * proc,struct arg_type_info * arg)363 arch_type_alignof(struct process *proc, struct arg_type_info *arg)
364 {
365 return (size_t) -2;
366 }
367