trace.c revision 917ef246757d89b74eac58e0664b3fe2146a6fdb
1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2012 Petr Machata, Red Hat Inc.
4 * Copyright (C) 2001,2005 IBM Corp.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 */
21
22#include "config.h"
23
24#include <asm/ptrace.h>
25#include <sys/ptrace.h>
26#include <sys/types.h>
27#include <sys/wait.h>
28#include <assert.h>
29#include <errno.h>
30#include <signal.h>
31#include <stdlib.h>
32
33#include "common.h"
34#include "proc.h"
35#include "type.h"
36
37#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
38# define PTRACE_PEEKUSER PTRACE_PEEKUSR
39#endif
40
41#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR))
42# define PTRACE_POKEUSER PTRACE_POKEUSR
43#endif
44
45void
46get_arch_dep(Process *proc) {
47#ifdef __s390x__
48	unsigned long psw;
49
50	if (proc->arch_ptr)
51		return;
52
53	psw = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWMASK, 0);
54
55	if ((psw & 0x000000180000000) == 0x000000080000000) {
56		proc->mask_32bit = 1;
57		proc->personality = 1;
58	}
59
60	proc->arch_ptr = (void *)1;
61#endif
62}
63
64/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
65 */
66int
67syscall_p(Process *proc, int status, int *sysnum) {
68	long pc, opcode, offset_reg, scno, tmp;
69	void *svc_addr;
70	int gpr_offset[16] = { PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
71		PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
72		PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
73		PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
74	};
75
76	if (WIFSTOPPED(status)
77	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
78
79		/*
80		 * If we have PTRACE_O_TRACESYSGOOD and we have the new style
81		 * of passing the system call number to user space via PT_GPR2
82		 * then the task is quite easy.
83		 */
84
85		*sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR2, 0);
86
87		if (proc->tracesysgood) {
88			/* System call was encountered... */
89			if (proc->callstack_depth > 0 &&
90			    proc->callstack[proc->callstack_depth -
91					    1].is_syscall) {
92				/* syscall exit */
93				*sysnum =
94				    proc->callstack[proc->callstack_depth -
95						    1].c_un.syscall;
96				return 2;
97			} else {
98				/* syscall enter */
99				if (*sysnum != -ENOSYS)
100					return 1;
101			}
102		}
103
104		/*
105		 * At least one of the two requirements mentioned above is not
106		 * met. Therefore the fun part starts here:
107		 * We try to do some instruction decoding without even knowing
108		 * the instruction code length of the last instruction executed.
109		 * Needs to be done to get the system call number or to decide
110		 * if we reached a breakpoint or even checking for a completely
111		 * unrelated instruction.
112		 * Just a heuristic that most of the time appears to work...
113		 */
114
115		pc = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWADDR, 0);
116		opcode = ptrace(PTRACE_PEEKTEXT, proc->pid,
117				(char *)(pc - sizeof(long)), 0);
118
119		if ((opcode & 0xffff) == 0x0001) {
120			/* Breakpoint */
121			return 0;
122		} else if ((opcode & 0xff00) == 0x0a00) {
123			/* SVC opcode */
124			scno = opcode & 0xff;
125		} else if ((opcode & 0xff000000) == 0x44000000) {
126			/* Instruction decoding of EXECUTE... */
127			svc_addr = (void *)(opcode & 0xfff);
128
129			offset_reg = (opcode & 0x000f0000) >> 16;
130			if (offset_reg)
131				svc_addr += ptrace(PTRACE_PEEKUSER, proc->pid,
132						   gpr_offset[offset_reg], 0);
133
134			offset_reg = (opcode & 0x0000f000) >> 12;
135			if (offset_reg)
136				svc_addr += ptrace(PTRACE_PEEKUSER, proc->pid,
137						   gpr_offset[offset_reg], 0);
138
139			scno = ptrace(PTRACE_PEEKTEXT, proc->pid, svc_addr, 0);
140#ifdef __s390x__
141			scno >>= 48;
142#else
143			scno >>= 16;
144#endif
145			if ((scno & 0xff00) != 0x0a000)
146				return 0;
147
148			tmp = 0;
149			offset_reg = (opcode & 0x00f00000) >> 20;
150			if (offset_reg)
151				tmp = ptrace(PTRACE_PEEKUSER, proc->pid,
152					     gpr_offset[offset_reg], 0);
153
154			scno = (scno | tmp) & 0xff;
155		} else {
156			/* No opcode related to syscall handling */
157			return 0;
158		}
159
160		if (scno == 0)
161			scno = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR1, 0);
162
163		*sysnum = scno;
164
165		/* System call was encountered... */
166		if (proc->callstack_depth > 0 &&
167		    proc->callstack[proc->callstack_depth - 1].is_syscall) {
168			return 2;
169		} else {
170			return 1;
171		}
172	}
173	/* Unknown status... */
174	return 0;
175}
176
177long
178gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info)
179{
180	long ret;
181
182	switch (arg_num) {
183	case -1:		/* return value */
184		ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR2, 0);
185		break;
186	case 0:
187		ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_ORIGGPR2, 0);
188		break;
189	case 1:
190		ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR3, 0);
191		break;
192	case 2:
193		ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR4, 0);
194		break;
195	case 3:
196		ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR5, 0);
197		break;
198	case 4:
199		ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR6, 0);
200		break;
201	default:
202		/*Rest of the params saved in stack */
203		if (arg_num >= 5) {
204			ret = ptrace(PTRACE_PEEKUSER, proc->pid,
205				     proc->stack_pointer + 96 +
206				     4 * (arg_num - 5), 0);
207		} else {
208			fprintf(stderr, "gimme_arg called with wrong arguments\n");
209			exit(2);
210		}
211	}
212#ifdef __s390x__
213	if (proc->mask_32bit)
214		ret &= 0xffffffff;
215#endif
216	return ret;
217}
218
219size_t
220arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
221{
222	if (proc == NULL)
223		return (size_t)-2;
224
225	switch (info->type) {
226	case ARGTYPE_VOID:
227		return 0;
228
229	case ARGTYPE_CHAR:
230		return 1;
231
232	case ARGTYPE_SHORT:
233	case ARGTYPE_USHORT:
234		return 2;
235
236	case ARGTYPE_INT:
237	case ARGTYPE_UINT:
238		return 4;
239
240	case ARGTYPE_LONG:
241	case ARGTYPE_ULONG:
242	case ARGTYPE_POINTER:
243		return proc->e_class == ELFCLASS64 ? 8 : 4;
244
245	case ARGTYPE_FLOAT:
246		return 4;
247	case ARGTYPE_DOUBLE:
248		return 8;
249
250	case ARGTYPE_ARRAY:
251	case ARGTYPE_STRUCT:
252		/* Use default value.  */
253		return (size_t)-2;
254	}
255	assert(info->type != info->type);
256	abort();
257}
258
259size_t
260arch_type_alignof(struct Process *proc, struct arg_type_info *info)
261{
262	if (proc == NULL)
263		return (size_t)-2;
264
265	switch (info->type) {
266	case ARGTYPE_VOID:
267		assert(info->type != ARGTYPE_VOID);
268		break;
269
270	case ARGTYPE_CHAR:
271		return 1;
272
273	case ARGTYPE_SHORT:
274	case ARGTYPE_USHORT:
275		return 2;
276
277	case ARGTYPE_INT:
278	case ARGTYPE_UINT:
279		return 4;
280
281	case ARGTYPE_LONG:
282	case ARGTYPE_ULONG:
283	case ARGTYPE_POINTER:
284		return proc->e_class == ELFCLASS64 ? 8 : 4;
285
286	case ARGTYPE_FLOAT:
287		return 4;
288	case ARGTYPE_DOUBLE:
289		return 8;
290
291	case ARGTYPE_ARRAY:
292	case ARGTYPE_STRUCT:
293		/* Use default value.  */
294		return (size_t)-2;
295	}
296	abort();
297}
298