fetch.c revision df59c75ee9fa70343c9af929403cd3d371443714
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 <asm/ptrace.h>
22#include <sys/ptrace.h>
23#include <sys/ucontext.h>
24#include <assert.h>
25#include <errno.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include "backend.h"
31#include "fetch.h"
32#include "type.h"
33#include "proc.h"
34#include "value.h"
35
36struct fetch_context {
37	struct user_regs_struct regs;
38	arch_addr_t stack_pointer;
39	int greg;
40	int freg;
41};
42
43static int
44s390x(struct fetch_context *ctx)
45{
46	/* +--------+--------+--------+
47	 * | PSW.31 | PSW.32 | mode   |
48	 * +--------+--------+--------+
49	 * | 0      | 0      | 24-bit | Not supported in Linux
50	 * | 0      | 1      | 31-bit | s390 compatible mode
51	 * | 1      | 1      | 64-bit | z/Architecture, "s390x"
52	 * +--------+--------+--------+
53	 * (Note: The leftmost bit is PSW.0, rightmost PSW.63.)
54	 */
55
56#ifdef __s390x__
57	if ((ctx->regs.psw.mask & 0x180000000UL) == 0x180000000UL)
58		return 1;
59#endif
60	return 0;
61}
62
63static int
64fp_equivalent(struct arg_type_info *info)
65{
66	switch (info->type) {
67	case ARGTYPE_VOID:
68	case ARGTYPE_INT:
69	case ARGTYPE_UINT:
70	case ARGTYPE_LONG:
71	case ARGTYPE_ULONG:
72	case ARGTYPE_CHAR:
73	case ARGTYPE_SHORT:
74	case ARGTYPE_USHORT:
75	case ARGTYPE_ARRAY:
76	case ARGTYPE_POINTER:
77		return 0;
78
79	case ARGTYPE_FLOAT:
80	case ARGTYPE_DOUBLE:
81		return 1;
82
83	case ARGTYPE_STRUCT:
84		if (type_struct_size(info) != 1)
85			return 0;
86		return fp_equivalent(type_element(info, 0));
87	}
88	assert(info->type != info->type);
89	abort();
90}
91
92static int
93fetch_register_banks(struct Process *proc, struct fetch_context *ctx)
94{
95	ptrace_area parea;
96	parea.len = sizeof(ctx->regs);
97	parea.process_addr = (uintptr_t)&ctx->regs;
98	parea.kernel_addr = 0;
99	if (ptrace(PTRACE_PEEKUSR_AREA, proc->pid, &parea, NULL) < 0) {
100		fprintf(stderr, "fetch_register_banks GPR: %s\n",
101			strerror(errno));
102		return -1;
103	}
104	return 0;
105}
106
107static int
108fetch_context_init(struct Process *proc, struct fetch_context *context)
109{
110	context->greg = 2;
111	context->freg = 0;
112	return fetch_register_banks(proc, context);
113}
114
115struct fetch_context *
116arch_fetch_arg_init(enum tof type, struct Process *proc,
117		    struct arg_type_info *ret_info)
118{
119	struct fetch_context *context = malloc(sizeof(*context));
120	if (context == NULL
121	    || fetch_context_init(proc, context) < 0) {
122		fprintf(stderr, "arch_fetch_arg_init: %s\n",
123			strerror(errno));
124		free(context);
125		return NULL;
126	}
127
128	context->stack_pointer = get_stack_pointer(proc)
129		+ (s390x(context) ? 160 : 96);
130	if (ret_info->type == ARGTYPE_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		    size_t sz)
151{
152	/* Note: here we shouldn't see large composite types, those
153	 * are passed by reference, which is handled below.  Here we
154	 * only deal with integers, floats, small structs, etc.  */
155
156	size_t a;
157	if (s390x(ctx)) {
158		assert(sz <= 8);
159		a = 8;
160	} else {
161		/* Note: double is 8 bytes.  */
162		assert(sz <= 8);
163		a = 4;
164	}
165
166	size_t off = sz < a ? a - sz : 0;
167
168	valuep->where = VAL_LOC_INFERIOR;
169	valuep->u.address = ctx->stack_pointer + off;
170
171	ctx->stack_pointer += sz > a ? sz : a;
172	return 0;
173}
174
175static void
176copy_gpr(struct fetch_context *ctx, struct value *valuep, int regno)
177{
178	value_set_word(valuep, ctx->regs.gprs[regno]);
179}
180
181static int
182allocate_gpr(struct fetch_context *ctx, struct Process *proc,
183	     struct arg_type_info *info, struct value *valuep,
184	     size_t sz)
185{
186	if (ctx->greg > 6)
187		return allocate_stack_slot(ctx, proc, info, valuep, sz);
188
189	copy_gpr(ctx, valuep, ctx->greg++);
190	return 0;
191}
192
193static int
194allocate_gpr_pair(struct fetch_context *ctx, struct Process *proc,
195		  struct arg_type_info *info, struct value *valuep,
196		  size_t sz)
197{
198	assert(!s390x(ctx));
199	assert(sz <= 8);
200
201	if (ctx->greg > 5) {
202		ctx->greg = 7;
203		return allocate_stack_slot(ctx, proc, info, valuep, sz);
204	}
205
206	if (value_reserve(valuep, sz) == NULL)
207		return -1;
208
209	unsigned char *ptr = value_get_raw_data(valuep);
210	union {
211		struct {
212			uint32_t a;
213			uint32_t b;
214		};
215		unsigned char buf[8];
216	} u;
217	u.a = ctx->regs.gprs[ctx->greg++];
218	u.b = ctx->regs.gprs[ctx->greg++];
219	memcpy(ptr, u.buf, sz);
220
221	return 0;
222}
223
224static int
225allocate_fpr(struct fetch_context *ctx, struct Process *proc,
226	     struct arg_type_info *info, struct value *valuep,
227	     size_t sz)
228{
229	int pool = s390x(ctx) ? 6 : 2;
230
231	if (ctx->freg > pool)
232		return allocate_stack_slot(ctx, proc, info, valuep, sz);
233
234	if (value_reserve(valuep, sz) == NULL)
235		return -1;
236
237	memcpy(value_get_raw_data(valuep),
238	       &ctx->regs.fp_regs.fprs[ctx->freg], sz);
239	ctx->freg += 2;
240
241	return 0;
242}
243
244int
245arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
246		    struct Process *proc,
247		    struct arg_type_info *info, struct value *valuep)
248{
249	size_t sz = type_sizeof(proc, info);
250	if (sz == (size_t)-1)
251		return -1;
252
253	/* XXX structures<4 bytes on s390 and structures<8 bytes on
254	 * s390x are passed in register.  On s390, long long and
255	 * structures<8 bytes are passed in two consecutive
256	 * registers (if two are available).  */
257
258	switch (info->type) {
259	case ARGTYPE_VOID:
260		value_set_word(valuep, 0);
261		return 0;
262
263	case ARGTYPE_STRUCT:
264		if (fp_equivalent(info))
265			/* fall through */
266	case ARGTYPE_FLOAT:
267	case ARGTYPE_DOUBLE:
268			return allocate_fpr(ctx, proc, info, valuep, sz);
269
270		/* Small structures are passed in registers.  */
271		if (sz <= (s390x(ctx) ? 8 : 4))
272			return allocate_gpr(ctx, proc, info, valuep, sz);
273		else if (sz <= 8)
274			return allocate_gpr_pair(ctx, proc, info, valuep, sz);
275		/* fall through */
276
277	case ARGTYPE_ARRAY:
278		if (value_pass_by_reference(valuep) < 0)
279			return -1;
280		/* fall through */
281
282	case ARGTYPE_INT:
283	case ARGTYPE_UINT:
284	case ARGTYPE_LONG:
285	case ARGTYPE_ULONG:
286	case ARGTYPE_CHAR:
287	case ARGTYPE_SHORT:
288	case ARGTYPE_USHORT:
289	case ARGTYPE_POINTER:
290		return allocate_gpr(ctx, proc, info, valuep, sz);
291	}
292	return -1;
293}
294
295int
296arch_fetch_retval(struct fetch_context *ctx, enum tof type,
297		  struct Process *proc, struct arg_type_info *info,
298		  struct value *valuep)
299{
300	if (info->type == ARGTYPE_STRUCT) {
301		if (value_pass_by_reference(valuep) < 0)
302			return -1;
303		copy_gpr(ctx, valuep, 2);
304		return 0;
305	}
306
307	if (fetch_context_init(proc, ctx) < 0)
308		return -1;
309	return arch_fetch_arg_next(ctx, type, proc, info, valuep);
310}
311
312void
313arch_fetch_arg_done(struct fetch_context *context)
314{
315	free(context);
316}
317