trace.c revision 2d45b1a8e26a36a9f85dc49e721c4390ca93dc40
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) 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