1 /* 2 * This file is part of ltrace. 3 * Copyright (C) 2011 Petr Machata, Red Hat Inc. 4 * Copyright (C) 2006 Ian Wienand 5 * Copyright (C) 2002,2008,2009 Juan Cespedes 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 <sys/ptrace.h> 26 #include <errno.h> 27 #include <string.h> 28 #include <stdio.h> 29 30 #include "common.h" 31 #include "backend.h" 32 #include "sysdep.h" 33 #include "breakpoint.h" 34 #include "proc.h" 35 #include "library.h" 36 37 #ifdef ARCH_HAVE_ENABLE_BREAKPOINT 38 extern void arch_enable_breakpoint(pid_t, struct breakpoint *); 39 #else /* ARCH_HAVE_ENABLE_BREAKPOINT */ 40 void 41 arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp) 42 { 43 static unsigned char break_insn[] = BREAKPOINT_VALUE; 44 unsigned int i, j; 45 46 debug(DEBUG_PROCESS, 47 "arch_enable_breakpoint: pid=%d, addr=%p, symbol=%s", 48 pid, sbp->addr, breakpoint_name(sbp)); 49 50 for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) { 51 long a = ptrace(PTRACE_PEEKTEXT, pid, 52 sbp->addr + i * sizeof(long), 0); 53 if (a == -1 && errno) { 54 fprintf(stderr, "enable_breakpoint" 55 " pid=%d, addr=%p, symbol=%s: %s\n", 56 pid, sbp->addr, breakpoint_name(sbp), 57 strerror(errno)); 58 return; 59 } 60 for (j = 0; 61 j < sizeof(long) 62 && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) { 63 unsigned char *bytes = (unsigned char *)&a; 64 65 sbp->orig_value[i * sizeof(long) + j] = bytes[j]; 66 bytes[j] = break_insn[i * sizeof(long) + j]; 67 } 68 a = ptrace(PTRACE_POKETEXT, pid, 69 sbp->addr + i * sizeof(long), a); 70 if (a == -1) { 71 fprintf(stderr, "enable_breakpoint" 72 " pid=%d, addr=%p, symbol=%s: %s\n", 73 pid, sbp->addr, breakpoint_name(sbp), 74 strerror(errno)); 75 return; 76 } 77 } 78 } 79 #endif /* ARCH_HAVE_ENABLE_BREAKPOINT */ 80 81 void 82 enable_breakpoint(struct process *proc, struct breakpoint *sbp) 83 { 84 debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s", 85 proc->pid, sbp->addr, breakpoint_name(sbp)); 86 arch_enable_breakpoint(proc->pid, sbp); 87 } 88 89 #ifdef ARCH_HAVE_DISABLE_BREAKPOINT 90 extern void arch_disable_breakpoint(pid_t, const struct breakpoint *sbp); 91 #else /* ARCH_HAVE_DISABLE_BREAKPOINT */ 92 void 93 arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp) 94 { 95 unsigned int i, j; 96 97 debug(DEBUG_PROCESS, 98 "arch_disable_breakpoint: pid=%d, addr=%p, symbol=%s", 99 pid, sbp->addr, breakpoint_name(sbp)); 100 101 for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) { 102 long a = ptrace(PTRACE_PEEKTEXT, pid, 103 sbp->addr + i * sizeof(long), 0); 104 if (a == -1 && errno) { 105 fprintf(stderr, 106 "disable_breakpoint pid=%d, addr=%p: %s\n", 107 pid, sbp->addr, strerror(errno)); 108 return; 109 } 110 for (j = 0; 111 j < sizeof(long) 112 && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) { 113 unsigned char *bytes = (unsigned char *)&a; 114 115 bytes[j] = sbp->orig_value[i * sizeof(long) + j]; 116 } 117 a = ptrace(PTRACE_POKETEXT, pid, 118 sbp->addr + i * sizeof(long), a); 119 if (a == -1 && errno) { 120 fprintf(stderr, 121 "disable_breakpoint pid=%d, addr=%p: %s\n", 122 pid, sbp->addr, strerror(errno)); 123 return; 124 } 125 } 126 } 127 #endif /* ARCH_HAVE_DISABLE_BREAKPOINT */ 128 129 void 130 disable_breakpoint(struct process *proc, struct breakpoint *sbp) 131 { 132 debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s", 133 proc->pid, sbp->addr, breakpoint_name(sbp)); 134 arch_disable_breakpoint(proc->pid, sbp); 135 } 136