1/* Memory breakpoint operations for the remote server for GDB. 2 Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc. 3 4 Contributed by MontaVista Software. 5 6 This file is part of GDB. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20 21#include "server.h" 22 23const unsigned char *breakpoint_data; 24int breakpoint_len; 25 26#define MAX_BREAKPOINT_LEN 8 27 28struct breakpoint 29{ 30 struct breakpoint *next; 31 CORE_ADDR pc; 32 unsigned char old_data[MAX_BREAKPOINT_LEN]; 33 34 /* Non-zero iff we are stepping over this breakpoint. */ 35 int reinserting; 36 37 /* Non-NULL iff this breakpoint was inserted to step over 38 another one. Points to the other breakpoint (which is also 39 in the *next chain somewhere). */ 40 struct breakpoint *breakpoint_to_reinsert; 41 42 /* Function to call when we hit this breakpoint. */ 43 void (*handler) (CORE_ADDR); 44}; 45 46struct breakpoint *breakpoints; 47 48void 49set_breakpoint_at (CORE_ADDR where, void (*handler) (CORE_ADDR)) 50{ 51 struct breakpoint *bp; 52 53 if (breakpoint_data == NULL) 54 error ("Target does not support breakpoints."); 55 56 bp = malloc (sizeof (struct breakpoint)); 57 memset (bp, 0, sizeof (struct breakpoint)); 58 59 (*the_target->read_memory) (where, bp->old_data, 60 breakpoint_len); 61 (*the_target->write_memory) (where, breakpoint_data, 62 breakpoint_len); 63 64 bp->pc = where; 65 bp->handler = handler; 66 67 bp->next = breakpoints; 68 breakpoints = bp; 69} 70 71static void 72delete_breakpoint (struct breakpoint *bp) 73{ 74 struct breakpoint *cur; 75 76 if (breakpoints == bp) 77 { 78 breakpoints = bp->next; 79 (*the_target->write_memory) (bp->pc, bp->old_data, 80 breakpoint_len); 81 free (bp); 82 return; 83 } 84 cur = breakpoints; 85 while (cur->next) 86 { 87 if (cur->next == bp) 88 { 89 cur->next = bp->next; 90 (*the_target->write_memory) (bp->pc, bp->old_data, 91 breakpoint_len); 92 free (bp); 93 return; 94 } 95 } 96 warning ("Could not find breakpoint in list."); 97} 98 99static struct breakpoint * 100find_breakpoint_at (CORE_ADDR where) 101{ 102 struct breakpoint *bp = breakpoints; 103 104 while (bp != NULL) 105 { 106 if (bp->pc == where) 107 return bp; 108 bp = bp->next; 109 } 110 111 return NULL; 112} 113 114void 115delete_breakpoint_at (CORE_ADDR addr) 116{ 117 struct breakpoint *bp = find_breakpoint_at (addr); 118 if (bp != NULL) 119 delete_breakpoint (bp); 120} 121 122static void 123reinsert_breakpoint_handler (CORE_ADDR stop_pc) 124{ 125 struct breakpoint *stop_bp, *orig_bp; 126 127 stop_bp = find_breakpoint_at (stop_pc); 128 if (stop_bp == NULL) 129 error ("lost the stopping breakpoint."); 130 131 orig_bp = stop_bp->breakpoint_to_reinsert; 132 if (orig_bp == NULL) 133 error ("no breakpoint to reinsert"); 134 135 (*the_target->write_memory) (orig_bp->pc, breakpoint_data, 136 breakpoint_len); 137 orig_bp->reinserting = 0; 138 delete_breakpoint (stop_bp); 139} 140 141void 142reinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at) 143{ 144 struct breakpoint *bp, *orig_bp; 145 146 set_breakpoint_at (stop_at, reinsert_breakpoint_handler); 147 148 orig_bp = find_breakpoint_at (stop_pc); 149 if (orig_bp == NULL) 150 error ("Could not find original breakpoint in list."); 151 152 bp = find_breakpoint_at (stop_at); 153 if (bp == NULL) 154 error ("Could not find breakpoint in list (reinserting by breakpoint)."); 155 bp->breakpoint_to_reinsert = orig_bp; 156 157 (*the_target->write_memory) (orig_bp->pc, orig_bp->old_data, 158 breakpoint_len); 159 orig_bp->reinserting = 1; 160} 161 162void 163uninsert_breakpoint (CORE_ADDR stopped_at) 164{ 165 struct breakpoint *bp; 166 167 bp = find_breakpoint_at (stopped_at); 168 if (bp == NULL) 169 error ("Could not find breakpoint in list (uninserting)."); 170 171 (*the_target->write_memory) (bp->pc, bp->old_data, 172 breakpoint_len); 173 bp->reinserting = 1; 174} 175 176void 177reinsert_breakpoint (CORE_ADDR stopped_at) 178{ 179 struct breakpoint *bp; 180 181 bp = find_breakpoint_at (stopped_at); 182 if (bp == NULL) 183 error ("Could not find breakpoint in list (uninserting)."); 184 if (! bp->reinserting) 185 error ("Breakpoint already inserted at reinsert time."); 186 187 (*the_target->write_memory) (bp->pc, breakpoint_data, 188 breakpoint_len); 189 bp->reinserting = 0; 190} 191 192int 193check_breakpoints (CORE_ADDR stop_pc) 194{ 195 struct breakpoint *bp; 196 197 bp = find_breakpoint_at (stop_pc); 198 if (bp == NULL) 199 return 0; 200 if (bp->reinserting) 201 { 202 warning ("Hit a removed breakpoint?"); 203 return 0; 204 } 205 206 (*bp->handler) (bp->pc); 207 return 1; 208} 209 210void 211set_breakpoint_data (const unsigned char *bp_data, int bp_len) 212{ 213 breakpoint_data = bp_data; 214 breakpoint_len = bp_len; 215} 216 217void 218check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) 219{ 220 struct breakpoint *bp = breakpoints; 221 CORE_ADDR mem_end = mem_addr + mem_len; 222 223 for (; bp != NULL; bp = bp->next) 224 { 225 CORE_ADDR bp_end = bp->pc + breakpoint_len; 226 CORE_ADDR start, end; 227 int copy_offset, copy_len, buf_offset; 228 229 if (mem_addr >= bp_end) 230 continue; 231 if (bp->pc >= mem_end) 232 continue; 233 234 start = bp->pc; 235 if (mem_addr > start) 236 start = mem_addr; 237 238 end = bp_end; 239 if (end > mem_end) 240 end = mem_end; 241 242 copy_len = end - start; 243 copy_offset = start - bp->pc; 244 buf_offset = start - mem_addr; 245 246 memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len); 247 } 248} 249 250void 251check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) 252{ 253 struct breakpoint *bp = breakpoints; 254 CORE_ADDR mem_end = mem_addr + mem_len; 255 256 for (; bp != NULL; bp = bp->next) 257 { 258 CORE_ADDR bp_end = bp->pc + breakpoint_len; 259 CORE_ADDR start, end; 260 int copy_offset, copy_len, buf_offset; 261 262 if (mem_addr >= bp_end) 263 continue; 264 if (bp->pc >= mem_end) 265 continue; 266 267 start = bp->pc; 268 if (mem_addr > start) 269 start = mem_addr; 270 271 end = bp_end; 272 if (end > mem_end) 273 end = mem_end; 274 275 copy_len = end - start; 276 copy_offset = start - bp->pc; 277 buf_offset = start - mem_addr; 278 279 memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len); 280 if (bp->reinserting == 0) 281 memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len); 282 } 283} 284 285/* Delete all breakpoints. */ 286 287void 288delete_all_breakpoints (void) 289{ 290 while (breakpoints) 291 delete_breakpoint (breakpoints); 292} 293