fetch.c revision bac2da505ee174b7fb984b975c5938f88f0dbab2
1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2012 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 <assert.h>
22#include <ptrace.h>
23#include <stdint.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/ucontext.h>
27
28#include <stdio.h>
29
30#include "backend.h"
31#include "fetch.h"
32#include "type.h"
33#include "proc.h"
34#include "value.h"
35
36static int allocate_gpr(struct fetch_context *ctx, struct Process *proc,
37			struct arg_type_info *info, struct value *valuep);
38
39/* Floating point registers have the same width on 32-bit as well as
40 * 64-bit PPC, but <ucontext.h> presents a different API depending on
41 * whether ltrace is PPC32 or PPC64.
42 *
43 * This is PPC64 definition.  The PPC32 is simply an array of 33
44 * doubles, and doesn't contain the terminating pad.  Both seem
45 * compatible enough.  */
46struct fpregs_t
47{
48	double fpregs[32];
49	double fpscr;
50	unsigned int _pad[2];
51};
52
53typedef uint32_t gregs32_t[48];
54typedef uint64_t gregs64_t[48];
55
56struct fetch_context {
57	arch_addr_t stack_pointer;
58	int greg;
59	int freg;
60	int ret_struct;
61
62	union {
63		gregs32_t r32;
64		gregs64_t r64;
65	} regs;
66	struct fpregs_t fpregs;
67
68};
69
70static int
71fetch_context_init(struct Process *proc, struct fetch_context *context)
72{
73	context->greg = 3;
74	context->freg = 1;
75
76	if (proc->e_machine == EM_PPC)
77		context->stack_pointer = proc->stack_pointer + 8;
78	else
79		context->stack_pointer = proc->stack_pointer + 112;
80
81	/* When ltrace is 64-bit, we might use PTRACE_GETREGS to
82	 * obtain 64-bit as well as 32-bit registers.  But if we do it
83	 * this way, 32-bit ltrace can obtain 64-bit registers.
84	 *
85	 * XXX this direction is not supported as of this writing, but
86	 * should be eventually.  */
87	if (proc->e_machine == EM_PPC64) {
88		if (ptrace(PTRACE_GETREGS64, proc->pid, 0,
89			   &context->regs.r64) < 0)
90			return -1;
91	} else {
92#ifdef __powerpc64__
93		if (ptrace(PTRACE_GETREGS, proc->pid, 0,
94			  &context->regs.r64) < 0)
95			return -1;
96		unsigned i;
97		for (i = 0; i < sizeof(context->regs.r64)/8; ++i)
98			context->regs.r32[i] = context->regs.r64[i];
99#else
100		if (ptrace(PTRACE_GETREGS, proc->pid, 0,
101			  &context->regs.r32) < 0)
102			return -1;
103#endif
104	}
105
106	if (ptrace(PTRACE_GETFPREGS, proc->pid, 0, &context->fpregs) < 0)
107		return -1;
108
109	return 0;
110}
111
112struct fetch_context *
113arch_fetch_arg_init(enum tof type, struct Process *proc,
114		    struct arg_type_info *ret_info)
115{
116	struct fetch_context *context = malloc(sizeof(*context));
117	if (context == NULL
118	    || fetch_context_init(proc, context) < 0) {
119		free(context);
120		return NULL;
121	}
122
123	/* Aggregates or unions of any length, and character strings
124	 * of length longer than 8 bytes, will be returned in a
125	 * storage buffer allocated by the caller. The caller will
126	 * pass the address of this buffer as a hidden first argument
127	 * in r3, causing the first explicit argument to be passed in
128	 * r4.  */
129	context->ret_struct = ret_info->type == ARGTYPE_STRUCT;
130	if (context->ret_struct)
131		context->greg++;
132
133	return context;
134}
135
136struct fetch_context *
137arch_fetch_arg_clone(struct Process *proc,
138		     struct fetch_context *context)
139{
140	struct fetch_context *clone = malloc(sizeof(*context));
141	if (clone == NULL)
142		return NULL;
143	*clone = *context;
144	return clone;
145}
146
147static int
148allocate_stack_slot(struct fetch_context *ctx, struct Process *proc,
149		    struct arg_type_info *info, struct value *valuep)
150{
151	size_t sz = type_sizeof(proc, info);
152	if (sz == (size_t)-1)
153		return -1;
154
155	size_t a = type_alignof(proc, info);
156	size_t off = 0;
157	if (proc->e_machine == EM_PPC && a < 4)
158		a = 4;
159	else if (proc->e_machine == EM_PPC64 && a < 8)
160		a = 8;
161
162	/* XXX Remove the two double casts when arch_addr_t
163	 * becomes integral type.  */
164	uintptr_t tmp = align((uint64_t)(uintptr_t)ctx->stack_pointer, a);
165	ctx->stack_pointer = (arch_addr_t)tmp;
166
167	if (valuep != NULL) {
168		valuep->where = VAL_LOC_INFERIOR;
169		valuep->u.address = ctx->stack_pointer + off;
170	}
171
172	ctx->stack_pointer += sz;
173
174	return 0;
175}
176
177static uint64_t
178read_gpr(struct fetch_context *ctx, struct Process *proc, int reg_num)
179{
180	if (proc->e_machine == EM_PPC)
181		return ctx->regs.r32[reg_num];
182	else
183		return ctx->regs.r64[reg_num];
184}
185
186/* The support for little endian PowerPC is in upstream Linux and BFD,
187 * and Unix-like Solaris, which we might well support at some point,
188 * runs PowerPC in little endian as well.  This code moves SZ-sized
189 * value to the beginning of W-sized BUF regardless of
190 * endian.  */
191static void
192align_small_int(unsigned char *buf, size_t w, size_t sz)
193{
194	assert(w == 4 || w == 8);
195	union {
196		uint64_t i64;
197		uint32_t i32;
198		uint16_t i16;
199		uint8_t i8;
200		char buf[0];
201	} u;
202	memcpy(u.buf, buf, w);
203	if (w == 4)
204		u.i64 = u.i32;
205
206	switch (sz) {
207	case 1:
208		u.i8 = u.i64;
209		break;
210	case 2:
211		u.i16 = u.i64;
212		break;
213	case 4:
214		u.i32 = u.i64;
215	case 8:
216		break;
217	}
218
219	memcpy(buf, u.buf, sz);
220}
221
222static int
223allocate_gpr(struct fetch_context *ctx, struct Process *proc,
224	     struct arg_type_info *info, struct value *valuep)
225{
226	if (ctx->greg > 10)
227		return allocate_stack_slot(ctx, proc, info, valuep);
228
229	int reg_num = ctx->greg++;
230	if (valuep == NULL)
231		return 0;
232
233	size_t sz = type_sizeof(proc, info);
234	if (sz == (size_t)-1)
235		return -1;
236	assert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
237	if (value_reserve(valuep, sz) == NULL)
238		return -1;
239
240	union {
241		uint64_t i64;
242		unsigned char buf[0];
243	} u;
244
245	u.i64 = read_gpr(ctx, proc, reg_num);
246	if (proc->e_machine == EM_PPC)
247		align_small_int(u.buf, 8, sz);
248	memcpy(value_get_raw_data(valuep), u.buf, sz);
249	return 0;
250}
251
252static int
253allocate_float(struct fetch_context *ctx, struct Process *proc,
254	       struct arg_type_info *info, struct value *valuep)
255{
256	int pool = proc->e_machine == EM_PPC64 ? 13 : 8;
257	if (ctx->freg <= pool) {
258		union {
259			double d;
260			float f;
261			char buf[0];
262		} u = { .d = ctx->fpregs.fpregs[ctx->freg] };
263
264		ctx->freg++;
265		if (proc->e_machine == EM_PPC64)
266			allocate_gpr(ctx, proc, info, NULL);
267
268		size_t sz = sizeof(double);
269		if (info->type == ARGTYPE_FLOAT) {
270			sz = sizeof(float);
271			u.f = (float)u.d;
272		}
273
274		if (value_reserve(valuep, sz) == NULL)
275			return -1;
276
277		memcpy(value_get_raw_data(valuep), u.buf, sz);
278		return 0;
279	}
280	return allocate_stack_slot(ctx, proc, info, valuep);
281}
282
283static int
284allocate_argument(struct fetch_context *ctx, struct Process *proc,
285		  struct arg_type_info *info, struct value *valuep)
286{
287	/* Floating point types and void are handled specially.  */
288	switch (info->type) {
289	case ARGTYPE_VOID:
290		value_set_word(valuep, 0);
291		return 0;
292
293	case ARGTYPE_FLOAT:
294	case ARGTYPE_DOUBLE:
295		return allocate_float(ctx, proc, info, valuep);
296
297	case ARGTYPE_STRUCT:
298		if (proc->e_machine == EM_PPC) {
299			if (value_pass_by_reference(valuep) < 0)
300				return -1;
301		} else {
302			/* PPC64: Fixed size aggregates and unions passed by
303			 * value are mapped to as many doublewords of the
304			 * parameter save area as the value uses in memory.
305			 * [...] The first eight doublewords mapped to the
306			 * parameter save area correspond to the registers r3
307			 * through r10.  */
308		}
309		/* fall through */
310	case ARGTYPE_CHAR:
311	case ARGTYPE_SHORT:
312	case ARGTYPE_USHORT:
313	case ARGTYPE_INT:
314	case ARGTYPE_UINT:
315	case ARGTYPE_LONG:
316	case ARGTYPE_ULONG:
317	case ARGTYPE_POINTER:
318		break;
319
320	case ARGTYPE_ARRAY:
321		/* Arrays decay into pointers.  XXX Fortran?  */
322		assert(info->type != ARGTYPE_ARRAY);
323		abort();
324	}
325
326	unsigned width = proc->e_machine == EM_PPC64 ? 8 : 4;
327
328	/* For other cases (integral types and aggregates), read the
329	 * eightbytes comprising the data.  */
330	size_t sz = type_sizeof(proc, valuep->type);
331	if (sz == (size_t)-1)
332		return -1;
333	size_t slots = (sz + width - 1) / width;  /* Round up.  */
334	unsigned char *buf = value_reserve(valuep, slots * width);
335	if (buf == NULL)
336		return -1;
337	struct arg_type_info *long_info = type_get_simple(ARGTYPE_LONG);
338
339	unsigned char *ptr = buf;
340	while (slots-- > 0) {
341		struct value val;
342		value_init(&val, proc, NULL, long_info, 0);
343		int rc = allocate_gpr(ctx, proc, long_info, &val);
344		if (rc >= 0) {
345			memcpy(ptr, value_get_data(&val, NULL), width);
346			ptr += width;
347		}
348		value_destroy(&val);
349		if (rc < 0)
350			return rc;
351	}
352
353	/* Small values need post-processing.  */
354	if (sz < width) {
355		switch (info->type) {
356		case ARGTYPE_LONG:
357		case ARGTYPE_ULONG:
358		case ARGTYPE_POINTER:
359		case ARGTYPE_DOUBLE:
360		case ARGTYPE_VOID:
361			abort();
362
363		/* Simple integer types (char, short, int, long, enum)
364		 * are mapped to a single doubleword. Values shorter
365		 * than a doubleword are sign or zero extended as
366		 * necessary.  */
367		case ARGTYPE_CHAR:
368		case ARGTYPE_SHORT:
369		case ARGTYPE_INT:
370		case ARGTYPE_USHORT:
371		case ARGTYPE_UINT:
372			align_small_int(buf, width, sz);
373			break;
374
375		/* Single precision floating point values are mapped
376		 * to the second word in a single doubleword.
377		 *
378		 * An aggregate or union smaller than one doubleword
379		 * in size is padded so that it appears in the least
380		 * significant bits of the doubleword.  */
381		case ARGTYPE_FLOAT:
382		case ARGTYPE_ARRAY:
383		case ARGTYPE_STRUCT:
384			memmove(buf, buf + width - sz, sz);
385			break;
386		}
387	}
388
389	return 0;
390}
391
392int
393arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
394		    struct Process *proc,
395		    struct arg_type_info *info, struct value *valuep)
396{
397	return allocate_argument(ctx, proc, info, valuep);
398}
399
400int
401arch_fetch_retval(struct fetch_context *ctx, enum tof type,
402		  struct Process *proc, struct arg_type_info *info,
403		  struct value *valuep)
404{
405	if (ctx->ret_struct) {
406		assert(info->type == ARGTYPE_STRUCT);
407
408		uint64_t addr = read_gpr(ctx, proc, 3);
409		value_init(valuep, proc, NULL, info, 0);
410
411		valuep->where = VAL_LOC_INFERIOR;
412		/* XXX Remove the double cast when arch_addr_t
413		 * becomes integral type. */
414		valuep->u.address = (arch_addr_t)(uintptr_t)addr;
415		return 0;
416	}
417
418	if (fetch_context_init(proc, ctx) < 0)
419		return -1;
420	return allocate_argument(ctx, proc, info, valuep);
421}
422
423void
424arch_fetch_arg_done(struct fetch_context *context)
425{
426	free(context);
427}
428