breakpoint.c revision e99af270a60891e68d465c4cd97dbe29cd1a05e4
1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2008,2009 Juan Cespedes 4 * Copyright (C) 2005,2006 Ian Wienand 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/* IA64 breakpoint support. Much of this clagged from gdb 23 * -Ian Wienand <ianw@gelato.unsw.edu.au> 10/3/2005 24 */ 25 26#include <sys/ptrace.h> 27#include <string.h> 28#include <assert.h> 29 30#include "breakpoint.h" 31#include "debug.h" 32 33static long long 34extract_bit_field(char *bundle, int from, int len) { 35 long long result = 0LL; 36 int to = from + len; 37 int from_byte = from / 8; 38 int to_byte = to / 8; 39 unsigned char *b = (unsigned char *)bundle; 40 unsigned char c; 41 int lshift; 42 int i; 43 44 c = b[from_byte]; 45 if (from_byte == to_byte) 46 c = ((unsigned char)(c << (8 - to % 8))) >> (8 - to % 8); 47 result = c >> (from % 8); 48 lshift = 8 - (from % 8); 49 50 for (i = from_byte + 1; i < to_byte; i++) { 51 result |= ((long long)b[i]) << lshift; 52 lshift += 8; 53 } 54 55 if (from_byte < to_byte && (to % 8 != 0)) { 56 c = b[to_byte]; 57 c = ((unsigned char)(c << (8 - to % 8))) >> (8 - to % 8); 58 result |= ((long long)c) << lshift; 59 } 60 61 return result; 62} 63 64/* Replace the specified bits in an instruction bundle */ 65static void 66replace_bit_field(char *bundle, long long val, int from, int len) { 67 int to = from + len; 68 int from_byte = from / 8; 69 int to_byte = to / 8; 70 unsigned char *b = (unsigned char *)bundle; 71 unsigned char c; 72 73 if (from_byte == to_byte) { 74 unsigned char left, right; 75 c = b[from_byte]; 76 left = (c >> (to % 8)) << (to % 8); 77 right = 78 ((unsigned char)(c << (8 - from % 8))) >> (8 - from % 8); 79 c = (unsigned char)(val & 0xff); 80 c = (unsigned char)(c << (from % 8 + 8 - to % 8)) >> (8 - 81 to % 8); 82 c |= right | left; 83 b[from_byte] = c; 84 } else { 85 int i; 86 c = b[from_byte]; 87 c = ((unsigned char)(c << (8 - from % 8))) >> (8 - from % 8); 88 c = c | (val << (from % 8)); 89 b[from_byte] = c; 90 val >>= 8 - from % 8; 91 92 for (i = from_byte + 1; i < to_byte; i++) { 93 c = val & 0xff; 94 val >>= 8; 95 b[i] = c; 96 } 97 98 if (to % 8 != 0) { 99 unsigned char cv = (unsigned char)val; 100 c = b[to_byte]; 101 c = c >> (to % 8) << (to % 8); 102 c |= ((unsigned char)(cv << (8 - to % 8))) >> (8 - 103 to % 8); 104 b[to_byte] = c; 105 } 106 } 107} 108 109/* Return the contents of slot N (for N = 0, 1, or 2) in 110 and instruction bundle */ 111static long long 112slotN_contents(char *bundle, int slotnum) { 113 return extract_bit_field(bundle, 5 + 41 * slotnum, 41); 114} 115 116/* Store an instruction in an instruction bundle */ 117 118static void 119replace_slotN_contents(char *bundle, long long instr, int slotnum) { 120 replace_bit_field(bundle, instr, 5 + 41 * slotnum, 41); 121} 122 123typedef enum instruction_type { 124 A, /* Integer ALU ; I-unit or M-unit */ 125 I, /* Non-ALU integer; I-unit */ 126 M, /* Memory ; M-unit */ 127 F, /* Floating-point ; F-unit */ 128 B, /* Branch ; B-unit */ 129 L, /* Extended (L+X) ; I-unit */ 130 X, /* Extended (L+X) ; I-unit */ 131 undefined /* undefined or reserved */ 132} instruction_type; 133 134static enum instruction_type template_encoding_table[32][3] = { 135 {M, I, I}, /* 00 */ 136 {M, I, I}, /* 01 */ 137 {M, I, I}, /* 02 */ 138 {M, I, I}, /* 03 */ 139 {M, L, X}, /* 04 */ 140 {M, L, X}, /* 05 */ 141 {undefined, undefined, undefined}, /* 06 */ 142 {undefined, undefined, undefined}, /* 07 */ 143 {M, M, I}, /* 08 */ 144 {M, M, I}, /* 09 */ 145 {M, M, I}, /* 0A */ 146 {M, M, I}, /* 0B */ 147 {M, F, I}, /* 0C */ 148 {M, F, I}, /* 0D */ 149 {M, M, F}, /* 0E */ 150 {M, M, F}, /* 0F */ 151 {M, I, B}, /* 10 */ 152 {M, I, B}, /* 11 */ 153 {M, B, B}, /* 12 */ 154 {M, B, B}, /* 13 */ 155 {undefined, undefined, undefined}, /* 14 */ 156 {undefined, undefined, undefined}, /* 15 */ 157 {B, B, B}, /* 16 */ 158 {B, B, B}, /* 17 */ 159 {M, M, B}, /* 18 */ 160 {M, M, B}, /* 19 */ 161 {undefined, undefined, undefined}, /* 1A */ 162 {undefined, undefined, undefined}, /* 1B */ 163 {M, F, B}, /* 1C */ 164 {M, F, B}, /* 1D */ 165 {undefined, undefined, undefined}, /* 1E */ 166 {undefined, undefined, undefined}, /* 1F */ 167}; 168 169union bundle_t { 170 char cbundle[16]; 171 unsigned long ubundle[2]; 172}; 173 174void 175arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp) 176{ 177 178 unsigned long addr = (unsigned long)sbp->addr; 179 union bundle_t bundle; 180 int slotnum = (int)(addr & 0x0f) & 0x3; 181 long long instr; 182 int template; 183 184 debug(1, "Enable Breakpoint at %p)", sbp->addr); 185 186 assert(slotnum <= 2); 187 188 addr &= ~0x0f; 189 bundle.ubundle[0] = ptrace(PTRACE_PEEKTEXT, pid, addr, 0); 190 bundle.ubundle[1] = ptrace(PTRACE_PEEKTEXT, pid, addr + 8, 0); 191 192 /* Check for L type instruction in 2nd slot, if present then 193 bump up the slot number to the 3rd slot */ 194 template = extract_bit_field(bundle.cbundle, 0, 5); 195 if (slotnum == 1 && template_encoding_table[template][1] == L) { 196 slotnum = 2; 197 } 198 199 instr = slotN_contents(bundle.cbundle, slotnum); 200 201 memcpy(sbp->orig_value, &instr, sizeof(instr)); 202 203 replace_slotN_contents(bundle.cbundle, 0x00002000040LL, slotnum); 204 205 ptrace(PTRACE_POKETEXT, pid, addr, bundle.ubundle[0]); 206 ptrace(PTRACE_POKETEXT, pid, addr + 8, bundle.ubundle[1]); 207 208} 209 210void 211arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp) 212{ 213 214 unsigned long addr = (unsigned long)sbp->addr; 215 int slotnum = (int)(addr & 0x0f) & 0x3; 216 union bundle_t bundle; 217 unsigned long instr; 218 219 debug(1, "Disable Breakpoint at %p", sbp->addr); 220 221 addr &= ~0x0f; 222 223 bundle.ubundle[0] = ptrace(PTRACE_PEEKTEXT, pid, addr, 0); 224 bundle.ubundle[1] = ptrace(PTRACE_PEEKTEXT, pid, addr + 8, 0); 225 226 memcpy(&instr, sbp->orig_value, sizeof(instr)); 227 228 replace_slotN_contents(bundle.cbundle, instr, slotnum); 229 ptrace(PTRACE_POKETEXT, pid, addr, bundle.ubundle[0]); 230 ptrace(PTRACE_POKETEXT, pid, addr + 8, bundle.ubundle[1]); 231} 232