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