trace.c revision bac2da505ee174b7fb984b975c5938f88f0dbab2
1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2010,2012 Petr Machata, Red Hat Inc. 4 * Copyright (C) 2011 Andreas Schwab 5 * Copyright (C) 2002,2004,2008,2009 Juan Cespedes 6 * Copyright (C) 2008 Luis Machado, IBM Corporation 7 * Copyright (C) 2006 Ian Wienand 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation; either version 2 of the 12 * License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 22 * 02110-1301 USA 23 */ 24 25#include "config.h" 26 27#include <assert.h> 28#include <elf.h> 29#include <errno.h> 30#include <signal.h> 31#include <string.h> 32 33#include "backend.h" 34#include "breakpoint.h" 35#include "common.h" 36#include "proc.h" 37#include "ptrace.h" 38#include "type.h" 39 40#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) 41# define PTRACE_PEEKUSER PTRACE_PEEKUSR 42#endif 43 44#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) 45# define PTRACE_POKEUSER PTRACE_POKEUSR 46#endif 47 48void 49get_arch_dep(Process *proc) { 50#ifdef __powerpc64__ 51 proc->mask_32bit = (proc->e_machine == EM_PPC); 52#endif 53} 54 55#define SYSCALL_INSN 0x44000002 56 57/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */ 58int 59syscall_p(Process *proc, int status, int *sysnum) { 60 if (WIFSTOPPED(status) 61 && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { 62 long pc = (long)get_instruction_pointer(proc); 63 int insn = 64 (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long), 65 0); 66 67 if (insn == SYSCALL_INSN) { 68 *sysnum = 69 (int)ptrace(PTRACE_PEEKUSER, proc->pid, 70 sizeof(long) * PT_R0, 0); 71 if (proc->callstack_depth > 0 && 72 proc->callstack[proc->callstack_depth - 1].is_syscall && 73 proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) { 74 return 2; 75 } 76 return 1; 77 } 78 } 79 return 0; 80} 81 82/* The atomic skip code is mostly taken from GDB. */ 83 84/* Instruction masks used during single-stepping of atomic 85 * sequences. This was lifted from GDB. */ 86#define LWARX_MASK 0xfc0007fe 87#define LWARX_INSTRUCTION 0x7c000028 88#define LDARX_INSTRUCTION 0x7c0000A8 89#define STWCX_MASK 0xfc0007ff 90#define STWCX_INSTRUCTION 0x7c00012d 91#define STDCX_INSTRUCTION 0x7c0001ad 92#define BC_MASK 0xfc000000 93#define BC_INSN 0x40000000 94#define BRANCH_MASK 0xfc000000 95 96/* In plt.h. XXX make this official interface. */ 97int read_target_4(struct Process *proc, arch_addr_t addr, uint32_t *lp); 98 99int 100arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp, 101 int (*add_cb)(void *addr, void *data), 102 void *add_cb_data) 103{ 104 arch_addr_t ip = get_instruction_pointer(proc); 105 struct breakpoint *other = address2bpstruct(proc->leader, ip); 106 107 debug(1, "arch_atomic_singlestep pid=%d addr=%p %s(%p)", 108 proc->pid, ip, breakpoint_name(sbp), sbp->addr); 109 110 /* If the original instruction was lwarx/ldarx, we can't 111 * single-step over it, instead we have to execute the whole 112 * atomic block at once. */ 113 union { 114 uint32_t insn; 115 char buf[BREAKPOINT_LENGTH]; 116 } u; 117 if (other != NULL) { 118 memcpy(u.buf, sbp->orig_value, BREAKPOINT_LENGTH); 119 } else if (read_target_4(proc, ip, &u.insn) < 0) { 120 fprintf(stderr, "couldn't read instruction at IP %p\n", ip); 121 /* Do the normal singlestep. */ 122 return 1; 123 } 124 125 if ((u.insn & LWARX_MASK) != LWARX_INSTRUCTION 126 && (u.insn & LWARX_MASK) != LDARX_INSTRUCTION) 127 return 1; 128 129 debug(1, "singlestep over atomic block at %p", ip); 130 131 int insn_count; 132 arch_addr_t addr = ip; 133 for (insn_count = 0; ; ++insn_count) { 134 addr += 4; 135 unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); 136 if (l == (unsigned long)-1 && errno) 137 return -1; 138 uint32_t insn; 139#ifdef __powerpc64__ 140 insn = l >> 32; 141#else 142 insn = l; 143#endif 144 145 /* If a conditional branch is found, put a breakpoint 146 * in its destination address. */ 147 if ((insn & BRANCH_MASK) == BC_INSN) { 148 int immediate = ((insn & 0xfffc) ^ 0x8000) - 0x8000; 149 int absolute = insn & 2; 150 151 /* XXX drop the following casts. */ 152 arch_addr_t branch_addr; 153 if (absolute) 154 branch_addr = (void *)(uintptr_t)immediate; 155 else 156 branch_addr = addr + (uintptr_t)immediate; 157 158 debug(1, "pid=%d, branch in atomic block from %p to %p", 159 proc->pid, addr, branch_addr); 160 if (add_cb(branch_addr, add_cb_data) < 0) 161 return -1; 162 } 163 164 /* Assume that the atomic sequence ends with a 165 * stwcx/stdcx instruction. */ 166 if ((insn & STWCX_MASK) == STWCX_INSTRUCTION 167 || (insn & STWCX_MASK) == STDCX_INSTRUCTION) { 168 debug(1, "pid=%d, found end of atomic block %p at %p", 169 proc->pid, ip, addr); 170 break; 171 } 172 173 /* Arbitrary cut-off. If we didn't find the 174 * terminating instruction by now, just give up. */ 175 if (insn_count > 16) { 176 fprintf(stderr, "[%d] couldn't find end of atomic block" 177 " at %p\n", proc->pid, ip); 178 return -1; 179 } 180 } 181 182 /* Put the breakpoint to the next instruction. */ 183 addr += 4; 184 if (add_cb(addr, add_cb_data) < 0) 185 return -1; 186 187 debug(1, "PTRACE_CONT"); 188 ptrace(PTRACE_CONT, proc->pid, 0, 0); 189 return 0; 190} 191 192size_t 193arch_type_sizeof(struct Process *proc, struct arg_type_info *info) 194{ 195 if (proc == NULL) 196 return (size_t)-2; 197 198 switch (info->type) { 199 case ARGTYPE_VOID: 200 return 0; 201 202 case ARGTYPE_CHAR: 203 return 1; 204 205 case ARGTYPE_SHORT: 206 case ARGTYPE_USHORT: 207 return 2; 208 209 case ARGTYPE_INT: 210 case ARGTYPE_UINT: 211 return 4; 212 213 case ARGTYPE_LONG: 214 case ARGTYPE_ULONG: 215 case ARGTYPE_POINTER: 216 return proc->e_machine == EM_PPC64 ? 8 : 4; 217 218 case ARGTYPE_FLOAT: 219 return 4; 220 case ARGTYPE_DOUBLE: 221 return 8; 222 223 case ARGTYPE_ARRAY: 224 case ARGTYPE_STRUCT: 225 /* Use default value. */ 226 return (size_t)-2; 227 } 228 assert(info->type != info->type); 229 abort(); 230} 231 232size_t 233arch_type_alignof(struct Process *proc, struct arg_type_info *info) 234{ 235 if (proc == NULL) 236 return (size_t)-2; 237 238 switch (info->type) { 239 case ARGTYPE_VOID: 240 assert(info->type != ARGTYPE_VOID); 241 break; 242 243 case ARGTYPE_CHAR: 244 case ARGTYPE_SHORT: 245 case ARGTYPE_USHORT: 246 case ARGTYPE_INT: 247 case ARGTYPE_UINT: 248 case ARGTYPE_LONG: 249 case ARGTYPE_ULONG: 250 case ARGTYPE_POINTER: 251 case ARGTYPE_FLOAT: 252 case ARGTYPE_DOUBLE: 253 /* On both PPC and PPC64, fundamental types have the 254 * same alignment as size. */ 255 return arch_type_sizeof(proc, info); 256 257 case ARGTYPE_ARRAY: 258 case ARGTYPE_STRUCT: 259 /* Use default value. */ 260 return (size_t)-2; 261 } 262 assert(info->type != info->type); 263 abort(); 264} 265