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