Admin Panel

/*
Copyright (C) 2018-2019 by Stefan "Bebbo" Franke <stefan@franke.ms> 

This file is part of bgdbserver.

bgdbserver is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

bgdbserver is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with bgdbserver.  If not, see <http://www.gnu.org/licenses/>.
*/  

#include "common.h"
#include "breakpoint.h"


struct Breakpoint {
	UWORD * address;
	USHORT value;
	short tmp; // temporary breakpoint
	UWORD * restore; //address where the bp should be.
};


struct Breakpoint * bps;
short numBps;
short maxBps;
short bpEnabled;

void clearBreakpoints() {
	numBps = 0;
}

/**
 * find a breakpoint.
 */
static short findBp(UWORD * addr) {
	for (short i = 0; i < numBps; ++i) {
		if (bps[i].address == addr)
			return i;
	}
	return -1;
}

/**
 * add a new breakpoint.
 */
void addBreakpoint(UWORD * addr, short isTmp, UWORD * restore) {
	if (findBp(addr) >= 0)
		return;

	if (numBps == maxBps) {
		maxBps = maxBps + maxBps + 4;
		bps = (struct Breakpoint *)realloc(bps, maxBps * sizeof(struct Breakpoint));
	}
	struct Breakpoint * b = & bps[numBps++];
	b->address = addr;
	b->tmp = isTmp;
	b->restore = restore;
}

/**
 * delete a breakpoint.
 */
void delBreakpoint(UWORD * addr) {
	short index = findBp(addr);
	if (index < 0)
		return;

	--numBps;
	if (index != numBps) {
		bps[index] = bps[numBps];
	}
}

/**
 * Enable the breakpoints.
 */
void enableBreakpoints() {
	bpEnabled = 1;
	for (int i = 0; i < numBps; ++i) {
		bps[i].value = *bps[i].address;
		*bps[i].address = trapInsn;

//		printf("set bp %08x %04x -> %04x\n", bps[i].address, bps[i].value, *bps[i].address);
	}
	CacheClearU();
}

/**
 * Disable all breakpoints.
 */
void disableBreakpoints() {
	if (!bpEnabled)
		return;

	bpEnabled = 0;
	// restore the code
	for (int i = 0; i < numBps; ++i) {
		*bps[i].address = bps[i].value;

//		printf("clear bp %08x %04x -> %04x\n", bps[i].address, bps[i].value, *bps[i].address);

		// fixup pc to original insn.
		if (reginfo.pc == bps[i].address + 1) {
			--reginfo.pc;
		}

		if (bps[i].tmp) {
			delBreakpoint(bps[i].address);
			--i;
		}
	}
	CacheClearU();
}