trace.c revision e99af270a60891e68d465c4cd97dbe29cd1a05e4
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(Process *proc) { 52 proc_archdep *a; 53 54 if (!proc->arch_ptr) 55 proc->arch_ptr = (void *)malloc(sizeof(proc_archdep)); 56 a = (proc_archdep *) (proc->arch_ptr); 57 a->valid = (ptrace(PTRACE_GETREGS, proc->pid, 0, &a->regs) >= 0); 58} 59 60/* Returns 0 if not a syscall, 61 * 1 if syscall entry, 2 if syscall exit, 62 * 3 if arch-specific syscall entry, 4 if arch-specific syscall exit, 63 * -1 on error. 64 */ 65int 66syscall_p(Process *proc, int status, int *sysnum) { 67 if (WIFSTOPPED(status) 68 && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { 69 /* get the user's pc (plus 8) */ 70 unsigned pc = ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0); 71 pc = pc - 4; 72 /* fetch the SWI instruction */ 73 unsigned insn = ptrace(PTRACE_PEEKTEXT, proc->pid, 74 (void *)pc, 0); 75 int ip = ptrace(PTRACE_PEEKUSER, proc->pid, off_ip, 0); 76 77 if (insn == 0xef000000 || insn == 0x0f000000 78 || (insn & 0xffff0000) == 0xdf000000) { 79 /* EABI syscall */ 80 *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, off_r7, 0); 81 } else if ((insn & 0xfff00000) == 0xef900000) { 82 /* old ABI syscall */ 83 *sysnum = insn & 0xfffff; 84 } else { 85 /* TODO: handle swi<cond> variations */ 86 /* one possible reason for getting in here is that we 87 * are coming from a signal handler, so the current 88 * PC does not point to the instruction just after the 89 * "swi" one. */ 90 output_line(proc, "unexpected instruction 0x%x at %p", 91 insn, pc); 92 return 0; 93 } 94 if ((*sysnum & 0xf0000) == 0xf0000) { 95 /* arch-specific syscall */ 96 *sysnum &= ~0xf0000; 97 return ip ? 4 : 3; 98 } 99 /* ARM syscall convention: on syscall entry, ip is zero; 100 * on syscall exit, ip is non-zero */ 101 return ip ? 2 : 1; 102 } 103 return 0; 104} 105 106long 107gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info) 108{ 109 proc_archdep *a = (proc_archdep *) proc->arch_ptr; 110 111 if (arg_num == -1) { /* return value */ 112 return ptrace(PTRACE_PEEKUSER, proc->pid, off_r0, 0); 113 } 114 115 /* deal with the ARM calling conventions */ 116 if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { 117 if (arg_num < 4) { 118 if (a->valid && type == LT_TOF_FUNCTION) 119 return a->regs.uregs[arg_num]; 120 if (a->valid && type == LT_TOF_FUNCTIONR) 121 return a->func_arg[arg_num]; 122 return ptrace(PTRACE_PEEKUSER, proc->pid, 123 (void *)(4 * arg_num), 0); 124 } else { 125 return ptrace(PTRACE_PEEKDATA, proc->pid, 126 proc->stack_pointer + 4 * (arg_num - 4), 127 0); 128 } 129 } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) { 130 if (arg_num < 5) { 131 if (a->valid && type == LT_TOF_SYSCALL) 132 return a->regs.uregs[arg_num]; 133 if (a->valid && type == LT_TOF_SYSCALLR) 134 return a->sysc_arg[arg_num]; 135 return ptrace(PTRACE_PEEKUSER, proc->pid, 136 (void *)(4 * arg_num), 0); 137 } else { 138 return ptrace(PTRACE_PEEKDATA, proc->pid, 139 proc->stack_pointer + 4 * (arg_num - 5), 140 0); 141 } 142 } else { 143 fprintf(stderr, "gimme_arg called with wrong arguments\n"); 144 exit(1); 145 } 146 147 return 0; 148} 149