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