breakpoint.c revision a7af00db2231e99a4506e4f5587f9dd00b9d1175
124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner/* IA64 breakpoint support. Much of this clagged from gdb 224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * -Ian Wienand <ianw@gelato.unsw.edu.au> 10/3/2005 324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner */ 424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner 524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "config.h" 624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner 724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include <sys/ptrace.h> 824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include <string.h> 924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "common.h" 10d996d0c32b483c2190e1eb288cd3bbbd259c2960Greg Clayton 1124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerstatic long long 1224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerextract_bit_field(char *bundle, int from, int len) { 1324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner long long result = 0LL; 1424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner int to = from + len; 1524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner int from_byte = from / 8; 1624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner int to_byte = to / 8; 1724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner unsigned char *b = (unsigned char *)bundle; 1824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner unsigned char c; 1924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner int lshift; 2024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner int i; 2124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner 2224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner c = b[from_byte]; 2324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner if (from_byte == to_byte) 2424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner c = ((unsigned char)(c << (8 - to % 8))) >> (8 - to % 8); 2524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner result = c >> (from % 8); 2624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner lshift = 8 - (from % 8); 2724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner 2824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner for (i = from_byte + 1; i < to_byte; i++) { 2924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner result |= ((long long)b[i]) << lshift; 3024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner lshift += 8; 3124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner } 3224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner 3324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner if (from_byte < to_byte && (to % 8 != 0)) { 3424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner c = b[to_byte]; 3524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner c = ((unsigned char)(c << (8 - to % 8))) >> (8 - to % 8); 3624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner result |= ((long long)c) << lshift; 3724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner } 3824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner 39 return result; 40} 41 42/* Replace the specified bits in an instruction bundle */ 43static void 44replace_bit_field(char *bundle, long long val, int from, int len) { 45 int to = from + len; 46 int from_byte = from / 8; 47 int to_byte = to / 8; 48 unsigned char *b = (unsigned char *)bundle; 49 unsigned char c; 50 51 if (from_byte == to_byte) { 52 unsigned char left, right; 53 c = b[from_byte]; 54 left = (c >> (to % 8)) << (to % 8); 55 right = 56 ((unsigned char)(c << (8 - from % 8))) >> (8 - from % 8); 57 c = (unsigned char)(val & 0xff); 58 c = (unsigned char)(c << (from % 8 + 8 - to % 8)) >> (8 - 59 to % 8); 60 c |= right | left; 61 b[from_byte] = c; 62 } else { 63 int i; 64 c = b[from_byte]; 65 c = ((unsigned char)(c << (8 - from % 8))) >> (8 - from % 8); 66 c = c | (val << (from % 8)); 67 b[from_byte] = c; 68 val >>= 8 - from % 8; 69 70 for (i = from_byte + 1; i < to_byte; i++) { 71 c = val & 0xff; 72 val >>= 8; 73 b[i] = c; 74 } 75 76 if (to % 8 != 0) { 77 unsigned char cv = (unsigned char)val; 78 c = b[to_byte]; 79 c = c >> (to % 8) << (to % 8); 80 c |= ((unsigned char)(cv << (8 - to % 8))) >> (8 - 81 to % 8); 82 b[to_byte] = c; 83 } 84 } 85} 86 87/* Return the contents of slot N (for N = 0, 1, or 2) in 88 and instruction bundle */ 89static long long 90slotN_contents(char *bundle, int slotnum) { 91 return extract_bit_field(bundle, 5 + 41 * slotnum, 41); 92} 93 94/* Store an instruction in an instruction bundle */ 95 96static void 97replace_slotN_contents(char *bundle, long long instr, int slotnum) { 98 replace_bit_field(bundle, instr, 5 + 41 * slotnum, 41); 99} 100 101typedef enum instruction_type { 102 A, /* Integer ALU ; I-unit or M-unit */ 103 I, /* Non-ALU integer; I-unit */ 104 M, /* Memory ; M-unit */ 105 F, /* Floating-point ; F-unit */ 106 B, /* Branch ; B-unit */ 107 L, /* Extended (L+X) ; I-unit */ 108 X, /* Extended (L+X) ; I-unit */ 109 undefined /* undefined or reserved */ 110} instruction_type; 111 112static enum instruction_type template_encoding_table[32][3] = { 113 {M, I, I}, /* 00 */ 114 {M, I, I}, /* 01 */ 115 {M, I, I}, /* 02 */ 116 {M, I, I}, /* 03 */ 117 {M, L, X}, /* 04 */ 118 {M, L, X}, /* 05 */ 119 {undefined, undefined, undefined}, /* 06 */ 120 {undefined, undefined, undefined}, /* 07 */ 121 {M, M, I}, /* 08 */ 122 {M, M, I}, /* 09 */ 123 {M, M, I}, /* 0A */ 124 {M, M, I}, /* 0B */ 125 {M, F, I}, /* 0C */ 126 {M, F, I}, /* 0D */ 127 {M, M, F}, /* 0E */ 128 {M, M, F}, /* 0F */ 129 {M, I, B}, /* 10 */ 130 {M, I, B}, /* 11 */ 131 {M, B, B}, /* 12 */ 132 {M, B, B}, /* 13 */ 133 {undefined, undefined, undefined}, /* 14 */ 134 {undefined, undefined, undefined}, /* 15 */ 135 {B, B, B}, /* 16 */ 136 {B, B, B}, /* 17 */ 137 {M, M, B}, /* 18 */ 138 {M, M, B}, /* 19 */ 139 {undefined, undefined, undefined}, /* 1A */ 140 {undefined, undefined, undefined}, /* 1B */ 141 {M, F, B}, /* 1C */ 142 {M, F, B}, /* 1D */ 143 {undefined, undefined, undefined}, /* 1E */ 144 {undefined, undefined, undefined}, /* 1F */ 145}; 146 147union bundle_t { 148 char cbundle[16]; 149 unsigned long ubundle[2]; 150}; 151 152void 153arch_enable_breakpoint(pid_t pid, Breakpoint *sbp) { 154 155 unsigned long addr = (unsigned long)sbp->addr; 156 union bundle_t bundle; 157 int slotnum = (int)(addr & 0x0f) & 0x3; 158 long long instr; 159 int template; 160 161 debug(1, "Enable Breakpoint at %p)", sbp->addr); 162 163 if (slotnum > 2) 164 printf 165 ("Can't insert breakpoint for slot numbers greater than 2."); 166 167 addr &= ~0x0f; 168 bundle.ubundle[0] = ptrace(PTRACE_PEEKTEXT, pid, addr, 0); 169 bundle.ubundle[1] = ptrace(PTRACE_PEEKTEXT, pid, addr + 8, 0); 170 171 /* Check for L type instruction in 2nd slot, if present then 172 bump up the slot number to the 3rd slot */ 173 template = extract_bit_field(bundle.cbundle, 0, 5); 174 if (slotnum == 1 && template_encoding_table[template][1] == L) { 175 slotnum = 2; 176 } 177 178 instr = slotN_contents(bundle.cbundle, slotnum); 179 180 memcpy(sbp->orig_value, &instr, sizeof(instr)); 181 182 replace_slotN_contents(bundle.cbundle, 0x00002000040LL, slotnum); 183 184 ptrace(PTRACE_POKETEXT, pid, addr, bundle.ubundle[0]); 185 ptrace(PTRACE_POKETEXT, pid, addr + 8, bundle.ubundle[1]); 186 187} 188 189void 190arch_disable_breakpoint(pid_t pid, const Breakpoint *sbp) { 191 192 unsigned long addr = (unsigned long)sbp->addr; 193 int slotnum = (int)(addr & 0x0f) & 0x3; 194 union bundle_t bundle; 195 unsigned long instr; 196 197 debug(1, "Disable Breakpoint at %p", sbp->addr); 198 199 addr &= ~0x0f; 200 201 bundle.ubundle[0] = ptrace(PTRACE_PEEKTEXT, pid, addr, 0); 202 bundle.ubundle[1] = ptrace(PTRACE_PEEKTEXT, pid, addr + 8, 0); 203 204 memcpy(&instr, sbp->orig_value, sizeof(instr)); 205 206 replace_slotN_contents(bundle.cbundle, instr, slotnum); 207 ptrace(PTRACE_POKETEXT, pid, addr, bundle.ubundle[0]); 208 ptrace(PTRACE_POKETEXT, pid, addr + 8, bundle.ubundle[1]); 209} 210