trace.c revision 929bd57ca202fd2f2e8485ebf65d683e664f67b5
1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2012 Petr Machata, Red Hat Inc. 4 * Copyright (C) 1998,2004,2008,2009 Juan Cespedes 5 * Copyright (C) 2006 Ian Wienand 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of the 10 * License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA 21 */ 22 23#include "config.h" 24 25#include <string.h> 26#include <sys/types.h> 27#include <sys/wait.h> 28#include <signal.h> 29#include <sys/ptrace.h> 30#include <asm/ptrace.h> 31 32#include "proc.h" 33#include "common.h" 34#include "output.h" 35#include "ptrace.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 45#define off_r0 ((void *)0) 46#define off_r7 ((void *)28) 47#define off_ip ((void *)48) 48#define off_pc ((void *)60) 49 50void 51get_arch_dep(struct process *proc) 52{ 53 proc_archdep *a; 54 55 if (!proc->arch_ptr) 56 proc->arch_ptr = (void *)malloc(sizeof(proc_archdep)); 57 a = (proc_archdep *) (proc->arch_ptr); 58 a->valid = (ptrace(PTRACE_GETREGS, proc->pid, 0, &a->regs) >= 0); 59} 60 61/* Returns 0 if not a syscall, 62 * 1 if syscall entry, 2 if syscall exit, 63 * 3 if arch-specific syscall entry, 4 if arch-specific syscall exit, 64 * -1 on error. 65 */ 66int 67syscall_p(struct process *proc, int status, int *sysnum) 68{ 69 if (WIFSTOPPED(status) 70 && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { 71 /* get the user's pc (plus 8) */ 72 unsigned pc = ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0); 73 pc = pc - 4; 74 /* fetch the SWI instruction */ 75 unsigned insn = ptrace(PTRACE_PEEKTEXT, proc->pid, 76 (void *)pc, 0); 77 int ip = ptrace(PTRACE_PEEKUSER, proc->pid, off_ip, 0); 78 79 if (insn == 0xef000000 || insn == 0x0f000000 80 || (insn & 0xffff0000) == 0xdf000000) { 81 /* EABI syscall */ 82 *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, off_r7, 0); 83 } else if ((insn & 0xfff00000) == 0xef900000) { 84 /* old ABI syscall */ 85 *sysnum = insn & 0xfffff; 86 } else { 87 /* TODO: handle swi<cond> variations */ 88 /* one possible reason for getting in here is that we 89 * are coming from a signal handler, so the current 90 * PC does not point to the instruction just after the 91 * "swi" one. */ 92 output_line(proc, "unexpected instruction 0x%x at %p", 93 insn, pc); 94 return 0; 95 } 96 if ((*sysnum & 0xf0000) == 0xf0000) { 97 /* arch-specific syscall */ 98 *sysnum &= ~0xf0000; 99 return ip ? 4 : 3; 100 } 101 /* ARM syscall convention: on syscall entry, ip is zero; 102 * on syscall exit, ip is non-zero */ 103 return ip ? 2 : 1; 104 } 105 return 0; 106} 107 108long 109gimme_arg(enum tof type, struct process *proc, int arg_num, 110 struct arg_type_info *info) 111{ 112 proc_archdep *a = (proc_archdep *) proc->arch_ptr; 113 114 if (arg_num == -1) { /* return value */ 115 return ptrace(PTRACE_PEEKUSER, proc->pid, off_r0, 0); 116 } 117 118 /* deal with the ARM calling conventions */ 119 if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { 120 if (arg_num < 4) { 121 if (a->valid && type == LT_TOF_FUNCTION) 122 return a->regs.uregs[arg_num]; 123 if (a->valid && type == LT_TOF_FUNCTIONR) 124 return a->func_arg[arg_num]; 125 return ptrace(PTRACE_PEEKUSER, proc->pid, 126 (void *)(4 * arg_num), 0); 127 } else { 128 return ptrace(PTRACE_PEEKDATA, proc->pid, 129 proc->stack_pointer + 4 * (arg_num - 4), 130 0); 131 } 132 } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) { 133 if (arg_num < 5) { 134 if (a->valid && type == LT_TOF_SYSCALL) 135 return a->regs.uregs[arg_num]; 136 if (a->valid && type == LT_TOF_SYSCALLR) 137 return a->sysc_arg[arg_num]; 138 return ptrace(PTRACE_PEEKUSER, proc->pid, 139 (void *)(4 * arg_num), 0); 140 } else { 141 return ptrace(PTRACE_PEEKDATA, proc->pid, 142 proc->stack_pointer + 4 * (arg_num - 5), 143 0); 144 } 145 } else { 146 fprintf(stderr, "gimme_arg called with wrong arguments\n"); 147 exit(1); 148 } 149 150 return 0; 151} 152