1130803Smarcel/* Memory breakpoint operations for the remote server for GDB. 2130803Smarcel Copyright 2002 3130803Smarcel Free Software Foundation, Inc. 4130803Smarcel 5130803Smarcel Contributed by MontaVista Software. 6130803Smarcel 7130803Smarcel This file is part of GDB. 8130803Smarcel 9130803Smarcel This program is free software; you can redistribute it and/or modify 10130803Smarcel it under the terms of the GNU General Public License as published by 11130803Smarcel the Free Software Foundation; either version 2 of the License, or 12130803Smarcel (at your option) any later version. 13130803Smarcel 14130803Smarcel This program is distributed in the hope that it will be useful, 15130803Smarcel but WITHOUT ANY WARRANTY; without even the implied warranty of 16130803Smarcel MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17130803Smarcel GNU General Public License for more details. 18130803Smarcel 19130803Smarcel You should have received a copy of the GNU General Public License 20130803Smarcel along with this program; if not, write to the Free Software 21130803Smarcel Foundation, Inc., 59 Temple Place - Suite 330, 22130803Smarcel Boston, MA 02111-1307, USA. */ 23130803Smarcel 24130803Smarcel#include "server.h" 25130803Smarcel 26130803Smarcelconst char *breakpoint_data; 27130803Smarcelint breakpoint_len; 28130803Smarcel 29130803Smarcel#define MAX_BREAKPOINT_LEN 8 30130803Smarcel 31130803Smarcelstruct breakpoint 32130803Smarcel{ 33130803Smarcel struct breakpoint *next; 34130803Smarcel CORE_ADDR pc; 35130803Smarcel unsigned char old_data[MAX_BREAKPOINT_LEN]; 36130803Smarcel 37130803Smarcel /* Non-zero iff we are stepping over this breakpoint. */ 38130803Smarcel int reinserting; 39130803Smarcel 40130803Smarcel /* Non-NULL iff this breakpoint was inserted to step over 41130803Smarcel another one. Points to the other breakpoint (which is also 42130803Smarcel in the *next chain somewhere). */ 43130803Smarcel struct breakpoint *breakpoint_to_reinsert; 44130803Smarcel 45130803Smarcel /* Function to call when we hit this breakpoint. */ 46130803Smarcel void (*handler) (CORE_ADDR); 47130803Smarcel}; 48130803Smarcel 49130803Smarcelstruct breakpoint *breakpoints; 50130803Smarcel 51130803Smarcelvoid 52130803Smarcelset_breakpoint_at (CORE_ADDR where, void (*handler) (CORE_ADDR)) 53130803Smarcel{ 54130803Smarcel struct breakpoint *bp; 55130803Smarcel 56130803Smarcel if (breakpoint_data == NULL) 57130803Smarcel error ("Target does not support breakpoints."); 58130803Smarcel 59130803Smarcel bp = malloc (sizeof (struct breakpoint)); 60130803Smarcel memset (bp, 0, sizeof (struct breakpoint)); 61130803Smarcel 62130803Smarcel (*the_target->read_memory) (where, bp->old_data, 63130803Smarcel breakpoint_len); 64130803Smarcel (*the_target->write_memory) (where, breakpoint_data, 65130803Smarcel breakpoint_len); 66130803Smarcel 67130803Smarcel bp->pc = where; 68130803Smarcel bp->handler = handler; 69130803Smarcel 70130803Smarcel bp->next = breakpoints; 71130803Smarcel breakpoints = bp; 72130803Smarcel} 73130803Smarcel 74130803Smarcelstatic void 75130803Smarceldelete_breakpoint (struct breakpoint *bp) 76130803Smarcel{ 77130803Smarcel struct breakpoint *cur; 78130803Smarcel 79130803Smarcel if (breakpoints == bp) 80130803Smarcel { 81130803Smarcel breakpoints = bp->next; 82130803Smarcel (*the_target->write_memory) (bp->pc, bp->old_data, 83130803Smarcel breakpoint_len); 84130803Smarcel free (bp); 85130803Smarcel return; 86130803Smarcel } 87130803Smarcel cur = breakpoints; 88130803Smarcel while (cur->next) 89130803Smarcel { 90130803Smarcel if (cur->next == bp) 91130803Smarcel { 92130803Smarcel cur->next = bp->next; 93130803Smarcel (*the_target->write_memory) (bp->pc, bp->old_data, 94130803Smarcel breakpoint_len); 95130803Smarcel free (bp); 96130803Smarcel return; 97130803Smarcel } 98130803Smarcel } 99130803Smarcel warning ("Could not find breakpoint in list."); 100130803Smarcel} 101130803Smarcel 102130803Smarcelstatic struct breakpoint * 103130803Smarcelfind_breakpoint_at (CORE_ADDR where) 104130803Smarcel{ 105130803Smarcel struct breakpoint *bp = breakpoints; 106130803Smarcel 107130803Smarcel while (bp != NULL) 108130803Smarcel { 109130803Smarcel if (bp->pc == where) 110130803Smarcel return bp; 111130803Smarcel bp = bp->next; 112130803Smarcel } 113130803Smarcel 114130803Smarcel return NULL; 115130803Smarcel} 116130803Smarcel 117130803Smarcelstatic void 118130803Smarcelreinsert_breakpoint_handler (CORE_ADDR stop_pc) 119130803Smarcel{ 120130803Smarcel struct breakpoint *stop_bp, *orig_bp; 121130803Smarcel 122130803Smarcel stop_bp = find_breakpoint_at (stop_pc); 123130803Smarcel if (stop_bp == NULL) 124130803Smarcel error ("lost the stopping breakpoint."); 125130803Smarcel 126130803Smarcel orig_bp = stop_bp->breakpoint_to_reinsert; 127130803Smarcel if (orig_bp == NULL) 128130803Smarcel error ("no breakpoint to reinsert"); 129130803Smarcel 130130803Smarcel (*the_target->write_memory) (orig_bp->pc, breakpoint_data, 131130803Smarcel breakpoint_len); 132130803Smarcel orig_bp->reinserting = 0; 133130803Smarcel delete_breakpoint (stop_bp); 134130803Smarcel} 135130803Smarcel 136130803Smarcelvoid 137130803Smarcelreinsert_breakpoint_by_bp (CORE_ADDR stop_pc, CORE_ADDR stop_at) 138130803Smarcel{ 139130803Smarcel struct breakpoint *bp, *orig_bp; 140130803Smarcel 141130803Smarcel set_breakpoint_at (stop_at, reinsert_breakpoint_handler); 142130803Smarcel 143130803Smarcel orig_bp = find_breakpoint_at (stop_pc); 144130803Smarcel if (orig_bp == NULL) 145130803Smarcel error ("Could not find original breakpoint in list."); 146130803Smarcel 147130803Smarcel bp = find_breakpoint_at (stop_at); 148130803Smarcel if (bp == NULL) 149130803Smarcel error ("Could not find breakpoint in list (reinserting by breakpoint)."); 150130803Smarcel bp->breakpoint_to_reinsert = orig_bp; 151130803Smarcel 152130803Smarcel (*the_target->write_memory) (orig_bp->pc, orig_bp->old_data, 153130803Smarcel breakpoint_len); 154130803Smarcel orig_bp->reinserting = 1; 155130803Smarcel} 156130803Smarcel 157130803Smarcelvoid 158130803Smarceluninsert_breakpoint (CORE_ADDR stopped_at) 159130803Smarcel{ 160130803Smarcel struct breakpoint *bp; 161130803Smarcel 162130803Smarcel bp = find_breakpoint_at (stopped_at); 163130803Smarcel if (bp == NULL) 164130803Smarcel error ("Could not find breakpoint in list (uninserting)."); 165130803Smarcel 166130803Smarcel (*the_target->write_memory) (bp->pc, bp->old_data, 167130803Smarcel breakpoint_len); 168130803Smarcel bp->reinserting = 1; 169130803Smarcel} 170130803Smarcel 171130803Smarcelvoid 172130803Smarcelreinsert_breakpoint (CORE_ADDR stopped_at) 173130803Smarcel{ 174130803Smarcel struct breakpoint *bp; 175130803Smarcel 176130803Smarcel bp = find_breakpoint_at (stopped_at); 177130803Smarcel if (bp == NULL) 178130803Smarcel error ("Could not find breakpoint in list (uninserting)."); 179130803Smarcel if (! bp->reinserting) 180130803Smarcel error ("Breakpoint already inserted at reinsert time."); 181130803Smarcel 182130803Smarcel (*the_target->write_memory) (bp->pc, breakpoint_data, 183130803Smarcel breakpoint_len); 184130803Smarcel bp->reinserting = 0; 185130803Smarcel} 186130803Smarcel 187130803Smarcelint 188130803Smarcelcheck_breakpoints (CORE_ADDR stop_pc) 189130803Smarcel{ 190130803Smarcel struct breakpoint *bp; 191130803Smarcel 192130803Smarcel bp = find_breakpoint_at (stop_pc); 193130803Smarcel if (bp == NULL) 194130803Smarcel return 0; 195130803Smarcel if (bp->reinserting) 196130803Smarcel { 197130803Smarcel warning ("Hit a removed breakpoint?"); 198130803Smarcel return 0; 199130803Smarcel } 200130803Smarcel 201130803Smarcel (*bp->handler) (bp->pc); 202130803Smarcel return 1; 203130803Smarcel} 204130803Smarcel 205130803Smarcelvoid 206130803Smarcelset_breakpoint_data (const char *bp_data, int bp_len) 207130803Smarcel{ 208130803Smarcel breakpoint_data = bp_data; 209130803Smarcel breakpoint_len = bp_len; 210130803Smarcel} 211130803Smarcel 212130803Smarcelvoid 213130803Smarcelcheck_mem_read (CORE_ADDR mem_addr, char *buf, int mem_len) 214130803Smarcel{ 215130803Smarcel struct breakpoint *bp = breakpoints; 216130803Smarcel CORE_ADDR mem_end = mem_addr + mem_len; 217130803Smarcel 218130803Smarcel for (; bp != NULL; bp = bp->next) 219130803Smarcel { 220130803Smarcel CORE_ADDR bp_end = bp->pc + breakpoint_len; 221130803Smarcel CORE_ADDR start, end; 222130803Smarcel int copy_offset, copy_len, buf_offset; 223130803Smarcel 224130803Smarcel if (mem_addr >= bp_end) 225130803Smarcel continue; 226130803Smarcel if (bp->pc >= mem_end) 227130803Smarcel continue; 228130803Smarcel 229130803Smarcel start = bp->pc; 230130803Smarcel if (mem_addr > start) 231130803Smarcel start = mem_addr; 232130803Smarcel 233130803Smarcel end = bp_end; 234130803Smarcel if (end > mem_end) 235130803Smarcel end = mem_end; 236130803Smarcel 237130803Smarcel copy_len = end - start; 238130803Smarcel copy_offset = start - bp->pc; 239130803Smarcel buf_offset = start - mem_addr; 240130803Smarcel 241130803Smarcel memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len); 242130803Smarcel } 243130803Smarcel} 244130803Smarcel 245130803Smarcelvoid 246130803Smarcelcheck_mem_write (CORE_ADDR mem_addr, char *buf, int mem_len) 247130803Smarcel{ 248130803Smarcel struct breakpoint *bp = breakpoints; 249130803Smarcel CORE_ADDR mem_end = mem_addr + mem_len; 250130803Smarcel 251130803Smarcel for (; bp != NULL; bp = bp->next) 252130803Smarcel { 253130803Smarcel CORE_ADDR bp_end = bp->pc + breakpoint_len; 254130803Smarcel CORE_ADDR start, end; 255130803Smarcel int copy_offset, copy_len, buf_offset; 256130803Smarcel 257130803Smarcel if (mem_addr >= bp_end) 258130803Smarcel continue; 259130803Smarcel if (bp->pc >= mem_end) 260130803Smarcel continue; 261130803Smarcel 262130803Smarcel start = bp->pc; 263130803Smarcel if (mem_addr > start) 264130803Smarcel start = mem_addr; 265130803Smarcel 266130803Smarcel end = bp_end; 267130803Smarcel if (end > mem_end) 268130803Smarcel end = mem_end; 269130803Smarcel 270130803Smarcel copy_len = end - start; 271130803Smarcel copy_offset = start - bp->pc; 272130803Smarcel buf_offset = start - mem_addr; 273130803Smarcel 274130803Smarcel memcpy (bp->old_data + copy_offset, buf + buf_offset, copy_len); 275130803Smarcel if (bp->reinserting == 0) 276130803Smarcel memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len); 277130803Smarcel } 278130803Smarcel} 279