trace.c revision 000e31195ad4ad30a0c80c93ab57a424e7d8d918
1/*
2** S390 specific part of trace.c
3**
4** Other routines are in ../trace.c and need to be combined
5** at link time with this code.
6**
7** Copyright (C) 2001,2005 IBM Corp.
8*/
9
10#include "config.h"
11
12#include <errno.h>
13#include <stdlib.h>
14#include <sys/types.h>
15#include <sys/wait.h>
16#include <signal.h>
17#include <sys/ptrace.h>
18#include <asm/ptrace.h>
19
20#include "proc.h"
21#include "common.h"
22
23#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
24# define PTRACE_PEEKUSER PTRACE_PEEKUSR
25#endif
26
27#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR))
28# define PTRACE_POKEUSER PTRACE_POKEUSR
29#endif
30
31void
32get_arch_dep(Process *proc) {
33#ifdef __s390x__
34	unsigned long psw;
35
36	if (proc->arch_ptr)
37		return;
38
39	psw = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWMASK, 0);
40
41	if ((psw & 0x000000180000000) == 0x000000080000000) {
42		proc->mask_32bit = 1;
43		proc->personality = 1;
44	}
45
46	proc->arch_ptr = (void *)1;
47#endif
48}
49
50/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
51 */
52int
53syscall_p(Process *proc, int status, int *sysnum) {
54	long pc, opcode, offset_reg, scno, tmp;
55	void *svc_addr;
56	int gpr_offset[16] = { PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
57		PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
58		PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
59		PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
60	};
61
62	if (WIFSTOPPED(status)
63	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
64
65		/*
66		 * If we have PTRACE_O_TRACESYSGOOD and we have the new style
67		 * of passing the system call number to user space via PT_GPR2
68		 * then the task is quite easy.
69		 */
70
71		*sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR2, 0);
72
73		if (proc->tracesysgood) {
74			/* System call was encountered... */
75			if (proc->callstack_depth > 0 &&
76			    proc->callstack[proc->callstack_depth -
77					    1].is_syscall) {
78				/* syscall exit */
79				*sysnum =
80				    proc->callstack[proc->callstack_depth -
81						    1].c_un.syscall;
82				return 2;
83			} else {
84				/* syscall enter */
85				if (*sysnum != -ENOSYS)
86					return 1;
87			}
88		}
89
90		/*
91		 * At least one of the two requirements mentioned above is not
92		 * met. Therefore the fun part starts here:
93		 * We try to do some instruction decoding without even knowing
94		 * the instruction code length of the last instruction executed.
95		 * Needs to be done to get the system call number or to decide
96		 * if we reached a breakpoint or even checking for a completely
97		 * unrelated instruction.
98		 * Just a heuristic that most of the time appears to work...
99		 */
100
101		pc = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWADDR, 0);
102		opcode = ptrace(PTRACE_PEEKTEXT, proc->pid,
103				(char *)(pc - sizeof(long)), 0);
104
105		if ((opcode & 0xffff) == 0x0001) {
106			/* Breakpoint */
107			return 0;
108		} else if ((opcode & 0xff00) == 0x0a00) {
109			/* SVC opcode */
110			scno = opcode & 0xff;
111		} else if ((opcode & 0xff000000) == 0x44000000) {
112			/* Instruction decoding of EXECUTE... */
113			svc_addr = (void *)(opcode & 0xfff);
114
115			offset_reg = (opcode & 0x000f0000) >> 16;
116			if (offset_reg)
117				svc_addr += ptrace(PTRACE_PEEKUSER, proc->pid,
118						   gpr_offset[offset_reg], 0);
119
120			offset_reg = (opcode & 0x0000f000) >> 12;
121			if (offset_reg)
122				svc_addr += ptrace(PTRACE_PEEKUSER, proc->pid,
123						   gpr_offset[offset_reg], 0);
124
125			scno = ptrace(PTRACE_PEEKTEXT, proc->pid, svc_addr, 0);
126#ifdef __s390x__
127			scno >>= 48;
128#else
129			scno >>= 16;
130#endif
131			if ((scno & 0xff00) != 0x0a000)
132				return 0;
133
134			tmp = 0;
135			offset_reg = (opcode & 0x00f00000) >> 20;
136			if (offset_reg)
137				tmp = ptrace(PTRACE_PEEKUSER, proc->pid,
138					     gpr_offset[offset_reg], 0);
139
140			scno = (scno | tmp) & 0xff;
141		} else {
142			/* No opcode related to syscall handling */
143			return 0;
144		}
145
146		if (scno == 0)
147			scno = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR1, 0);
148
149		*sysnum = scno;
150
151		/* System call was encountered... */
152		if (proc->callstack_depth > 0 &&
153		    proc->callstack[proc->callstack_depth - 1].is_syscall) {
154			return 2;
155		} else {
156			return 1;
157		}
158	}
159	/* Unknown status... */
160	return 0;
161}
162
163long
164gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info)
165{
166	long ret;
167
168	switch (arg_num) {
169	case -1:		/* return value */
170		ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR2, 0);
171		break;
172	case 0:
173		ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_ORIGGPR2, 0);
174		break;
175	case 1:
176		ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR3, 0);
177		break;
178	case 2:
179		ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR4, 0);
180		break;
181	case 3:
182		ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR5, 0);
183		break;
184	case 4:
185		ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR6, 0);
186		break;
187	default:
188		/*Rest of the params saved in stack */
189		if (arg_num >= 5) {
190			ret = ptrace(PTRACE_PEEKUSER, proc->pid,
191				     proc->stack_pointer + 96 +
192				     4 * (arg_num - 5), 0);
193		} else {
194			fprintf(stderr, "gimme_arg called with wrong arguments\n");
195			exit(2);
196		}
197	}
198#ifdef __s390x__
199	if (proc->mask_32bit)
200		ret &= 0xffffffff;
201#endif
202	return ret;
203}
204
205void
206save_register_args(enum tof type, Process *proc) {
207}
208