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