From 826e921dac8648df9a4392adfa00fb4741ddcdbe Mon Sep 17 00:00:00 2001 From: Guy Perfect Date: Fri, 16 Oct 2020 19:25:36 -0500 Subject: [PATCH] Implementing native breakpoint interface --- makefile | 2 +- src/desktop/Main.java | 3 +- src/desktop/vue/Breakpoint.c | 6 +- src/desktop/vue/Breakpoint.java | 207 ++++++++++++++++++++++++-------- src/desktop/vue/NativeVue.c | 144 ++++++++++++++++++++-- src/desktop/vue/NativeVue.java | 57 +++++++++ src/desktop/vue/Vue.java | 11 +- 7 files changed, 365 insertions(+), 65 deletions(-) diff --git a/makefile b/makefile index 6d71cef..0f12504 100644 --- a/makefile +++ b/makefile @@ -10,7 +10,7 @@ default: @echo $(include_linux) @echo "Planet Virtual Boy Emulator" @echo " https://www.planetvb.com/" - @echo " October 13, 2020" + @echo " October 16, 2020" @echo @echo "Intended build environment: Debian i386 or amd64" @echo " gcc-multilib" diff --git a/src/desktop/Main.java b/src/desktop/Main.java index 4175123..7e5710a 100644 --- a/src/desktop/Main.java +++ b/src/desktop/Main.java @@ -51,7 +51,7 @@ public class Main { // Begin application operations new App(useNative); - + /* var brk = new Breakpoint(null); String exp = @@ -74,6 +74,7 @@ public class Main { brk.getErrorPosition(Breakpoint.ADDRESS) + ":" + brk.getErrorText (Breakpoint.ADDRESS) ); + */ } diff --git a/src/desktop/vue/Breakpoint.c b/src/desktop/vue/Breakpoint.c index d318c2a..63d169a 100644 --- a/src/desktop/vue/Breakpoint.c +++ b/src/desktop/vue/Breakpoint.c @@ -612,13 +612,13 @@ static void evalUnary(Vue *vue, int32_t id, int32_t *stack, int32_t size) { int32_t evaluate(Vue *vue, Breakpoint *brk, int32_t *stack) { // The condition is empty - if (brk->numCondition == 0) + if (brk->numTokens == 0) return brk->enabled; // Process tokens int size = 0; - for (int x = 0; x < brk->numCondition; x++) { - Token *tok = &brk->condition[x]; + for (int x = 0; x < brk->numTokens; x++) { + Token *tok = &brk->tokens[x]; switch (tok->type) { case BINARY: size = evalBinary( tok->value, stack, size); continue; diff --git a/src/desktop/vue/Breakpoint.java b/src/desktop/vue/Breakpoint.java index 9a1c6c6..35b6c46 100644 --- a/src/desktop/vue/Breakpoint.java +++ b/src/desktop/vue/Breakpoint.java @@ -7,15 +7,16 @@ import java.util.*; public class Breakpoint { // Instance fields - private int[][] addresses; // Applicable address ranges - private String addressText; // Un-processed address ranges + private String addresses; // Un-processed address ranges private String condition; // Un-processed condition private int[] errCode; // Error codes private int[] errPosition; // Character position of errors private String[] errText; // Offending error text + private int hooks; // Applied breakpoint types private boolean isEnabled; // Breakpoint is active private String name; // Display name - private Token[] tokens; // Evaluation tokens + private int[][] ranges; // Applicable address ranges + private Token[] tokens; // Condition tokens private Vue vue; // Containing emulation context @@ -39,6 +40,12 @@ public class Breakpoint { public static final int ADDRESS = 0; public static final int CONDITION = 1; + // Breakpoint hooks + private static final int EXCEPTION = 0x00000001; + private static final int EXECUTE = 0x00000002; + private static final int READ = 0x00000004; + private static final int WRITE = 0x00000008; + // Token types private static final int BINARY = 4; private static final int CLOSE = 6; @@ -296,6 +303,11 @@ public class Breakpoint { this.type = type; } + // Retrieve the applicable serialized "value" + int flatten() { + return type == FLOAT || type == WORD ? value : id; + } + } @@ -306,13 +318,13 @@ public class Breakpoint { // Default constructor public Breakpoint(Vue vue) { - addresses = new int[0][]; - addressText = ""; + addresses = ""; condition = ""; errCode = new int [] { NONE, NONE }; errPosition = new int [] { 0, 0 }; errText = new String[] { "", "" }; name = ""; + ranges = new int[0][]; tokens = new Token[0]; this.vue = vue; } @@ -378,8 +390,8 @@ public class Breakpoint { // Produce a string representation of the internal address ranges public String test() { var ret = new StringBuilder(); - for (int x = 0; x < addresses.length; x++) { - var range = addresses[x]; + for (int x = 0; x < ranges.length; x++) { + var range = ranges[x]; if (x > 0) ret.append("\n"); ret.append(String.format("%08X", range[0])); @@ -396,7 +408,7 @@ public class Breakpoint { // Retrieve the most recent input addresses public String getAddresses() { - return addressText; + return addresses; } // Retrieve the most recent input condition @@ -419,6 +431,26 @@ public class Breakpoint { return type < 0 || type > 1 ? null : errText[type]; } + // Retrieve whether the breakpoint hooks exceptions + public boolean getException() { + return (hooks & EXCEPTION) != 0; + } + + // Retrieve whether the breakpoint hooks executions + public boolean getExecute() { + return (hooks & EXECUTE) != 0; + } + + // Retrieve whether the breakpoint hooks reads + public boolean getRead() { + return (hooks & READ) != 0; + } + + // Retrieve whether the breakpoint hooks writes + public boolean getWrite() { + return (hooks & WRITE) != 0; + } + // Retrieve the display name public String getName() { return name; @@ -438,7 +470,7 @@ public class Breakpoint { int x = 0; // Input position // Configure instance fields - addressText = addresses == null ? addresses = "" : addresses; + this.addresses = addresses == null ? addresses = "" : addresses; // Parse the input var chars = (addresses + " ").toCharArray(); @@ -485,7 +517,7 @@ public class Breakpoint { errPosition[ADDRESS] = start + 1; errText [ADDRESS] = text; if (vue != null) - vue.update(this); + vue.updateRanges(this); return false; } @@ -535,7 +567,7 @@ public class Breakpoint { errPosition[ADDRESS] = x + 1; errText [ADDRESS] = Character.toString(c); if (vue != null) - vue.update(this); + vue.updateRanges(this); return false; } // x @@ -545,7 +577,7 @@ public class Breakpoint { errPosition[ADDRESS] = x + 1; errText [ADDRESS] = ""; if (vue != null) - vue.update(this); + vue.updateRanges(this); return false; } @@ -554,13 +586,12 @@ public class Breakpoint { ranges.add(new int[] { first, first }); // Parsing was successful - this.addresses = ranges.toArray(new int[ranges.size()][]); - this.addressText = addresses; + this.ranges = ranges.toArray(new int[ranges.size()][]); errCode [ADDRESS] = NONE; errPosition[ADDRESS] = 0; errText [ADDRESS] = ""; if (vue != null) - vue.update(this); + vue.updateRanges(this); return true; } @@ -578,7 +609,7 @@ public class Breakpoint { var tokens = parse(); if (tokens == null || !validate(tokens)) { if (vue != null) - vue.update(this); + vue.updateTokens(this); return false; } tree(tokens); @@ -586,7 +617,7 @@ public class Breakpoint { // The expression is empty if (tokens.size() == 0) { if (vue != null) - vue.update(this); + vue.updateTokens(this); return true; } @@ -616,15 +647,48 @@ public class Breakpoint { // The expression was successfully parsed if (vue != null) - vue.update(this); + vue.updateTokens(this); return true; } + // Specify whether the breakpoint is enabled + public void setEnabled(boolean enabled) { + isEnabled = enabled; + if (vue != null) + vue.updateState(this); + } + + // Specify whether the breakpoint hooks exceptions + public void setException(boolean hook) { + hooks = hook ? hooks | EXCEPTION : hooks & ~EXCEPTION; + if (vue != null) + vue.updateState(this); + } + + // Specify whether the breakpoint hooks executions + public void setExecute(boolean hook) { + hooks = hook ? hooks | EXECUTE : hooks & ~EXECUTE; + if (vue != null) + vue.updateState(this); + } + // Specify the display name public void setName(String name) { this.name = name == null ? "" : name; + } + + // Specify whether the breakpoint hooks reads + public void setRead(boolean hook) { + hooks = hook ? hooks | READ : hooks & ~READ; if (vue != null) - vue.update(this); + vue.updateState(this); + } + + // Specify whether the breakpoint hooks reads + public void setWrite(boolean hook) { + hooks = hook ? hooks | WRITE : hooks & ~WRITE; + if (vue != null) + vue.updateState(this); } @@ -634,7 +698,7 @@ public class Breakpoint { /////////////////////////////////////////////////////////////////////////// // Evaluate the condition for a Java emulation context - boolean evaluate(JavaVue vue, int[] stack) { + boolean evaluate(int[] stack) { // The condition is empty if (tokens.length == 0) @@ -645,11 +709,11 @@ public class Breakpoint { for (var tok : tokens) { switch (tok.type) { case BINARY: size = - evalBinary( tok.id, stack, size); continue; + evalBinary(tok.id, stack, size); continue; case SYMBOL: size = - evalSymbol(vue, tok.id, stack, size); continue; + evalSymbol(tok.id, stack, size); continue; case UNARY : - evalUnary (vue, tok.id, stack, size); continue; + evalUnary (tok.id, stack, size); continue; } stack[size++] = tok.type; stack[size++] = tok.value; @@ -676,6 +740,43 @@ public class Breakpoint { return max; } + // Produce a one-dimensional array from the address ranges + int[] flattenRanges() { + var ret = new int[ranges.length * 2]; + for (int x = 0; x < ranges.length; x++) { + var range = ranges[x]; + ret[x / 2 ] = range[0]; + ret[x / 2 + 1] = range[1]; + } + return ret; + } + + // Produce a one-dimensional array from the condition tokens + int[] flattenTokens() { + var ret = new int[tokens.length * 2]; + for (int x = 0; x < tokens.length; x++) { + var token = tokens[x]; + ret[x / 2 ] = token.type; + ret[x / 2 + 1] = token.flatten(); + } + return ret; + } + + // Retrieve the bit mask for enabled hooks + int getHooks() { + return hooks; + } + + // Retrieve the list of address ranges + int[][] getRanges() { + return ranges; + } + + // Retrieve the list of condition tokens + Token[] getTokens() { + return tokens; + } + // The breakpoint is being removed from its emulation context void remove() { vue = null; @@ -1155,8 +1256,9 @@ public class Breakpoint { } // Evaluate a functional symbol - private static int evalSymbol(JavaVue vue, int id, int[] stack, int size) { + private int evalSymbol(int id, int[] stack, int size) { int ret = 0; + var vue = (JavaVue) this.vue; if (id == Vue.PC) ret = vue.cpu.pc; else if (id >= 200) @@ -1166,20 +1268,20 @@ public class Breakpoint { else if (vue.cpu.stage == CPU.EXCEPTION && id == CODE) ret = vue.cpu.exception.code; else if (vue.cpu.stage == CPU.EXECUTE) switch (id) { - case ADDRESS : ret = evalAddress (vue); break; - case COND : ret = evalCond (vue); break; - case DISP : ret = evalDisp (vue); break; + case ADDRESS : ret = evalAddress (); break; + case COND : ret = evalCond (); break; + case DISP : ret = evalDisp (); break; case FORMAT : ret = vue.cpu.inst.format; break; case ID : ret = vue.cpu.inst.id ; break; - case IMM : ret = evalImm (vue); break; + case IMM : ret = evalImm (); break; case OPCODE : ret = vue.cpu.inst.opcode; break; - case REG1 : ret = evalReg1 (vue); break; - case REG2 : ret = evalReg2 (vue); break; - case REGID : ret = evalRegId (vue); break; + case REG1 : ret = evalReg1 (); break; + case REG2 : ret = evalReg2 (); break; + case REGID : ret = evalRegId (); break; case SIZE : ret = vue.cpu.inst.size ; break; - case SUBOPCODE: ret = evalSubopcode (vue); break; - case VALUE : ret = evalValue (vue); break; - case VECTOR : ret = evalVector (vue); break; + case SUBOPCODE: ret = evalSubopcode (); break; + case VALUE : ret = evalValue (); break; + case VECTOR : ret = evalVector (); break; } stack[size++] = WORD; stack[size++] = ret; @@ -1187,7 +1289,7 @@ public class Breakpoint { } // Evaluate a unary operator - private static void evalUnary(JavaVue vue, int id, int[] stack, int size) { + private void evalUnary(int id, int[] stack, int size) { int type = stack[size - 2]; int value = stack[size - 1]; boolean isWord = type == WORD; @@ -1201,7 +1303,7 @@ public class Breakpoint { case FLOAT : value = evalFloat (isWord, value); type = FLOAT; break; case FLOOR : value = evalFloor (isWord, value); break; - case READ_WORD : value = evalReadWord (isWord, value, vue); + case READ_WORD : value = evalReadWord (isWord, value); type = WORD ; break; case ROUND : value = evalRound (isWord, value); break; case TRUNC : value = evalTrunc (isWord, value); break; @@ -1414,7 +1516,8 @@ public class Breakpoint { /////////////////////////////////////////////////////////////////////////// // Evaluate address - private static int evalAddress(JavaVue vue) { + private int evalAddress() { + var vue = (JavaVue) this.vue; if (vue.cpu.inst.format == 6) return vue.cpu.program[vue.cpu.inst.reg1] + vue.cpu.inst.disp; switch (vue.cpu.inst.id) { @@ -1429,7 +1532,8 @@ public class Breakpoint { } // Evaluate cond - private static int evalCond(JavaVue vue) { + private int evalCond() { + var vue = (JavaVue) this.vue; switch (vue.cpu.inst.id) { case Vue.BCOND: return vue.cpu.inst.cond; case Vue.SETF : return vue.cpu.inst.imm; @@ -1438,7 +1542,8 @@ public class Breakpoint { } // Evaluate disp - private static int evalDisp(JavaVue vue) { + private int evalDisp() { + var vue = (JavaVue) this.vue; switch (vue.cpu.inst.format) { case 3: case 4: case 6: return vue.cpu.inst.disp; } @@ -1446,7 +1551,8 @@ public class Breakpoint { } // Evaluate imm - private static int evalImm(JavaVue vue) { + private int evalImm() { + var vue = (JavaVue) this.vue; switch (vue.cpu.inst.format) { case 2: case 5: return vue.cpu.inst.imm; } @@ -1454,7 +1560,8 @@ public class Breakpoint { } // Evaluate reg1 - private static int evalReg1(JavaVue vue) { + private int evalReg1() { + var vue = (JavaVue) this.vue; switch (vue.cpu.inst.format) { case 1: case 5: case 6: case 7: return vue.cpu.inst.reg1; } @@ -1462,7 +1569,8 @@ public class Breakpoint { } // Evaluate reg2 - private static int evalReg2(JavaVue vue) { + private int evalReg2() { + var vue = (JavaVue) this.vue; switch (vue.cpu.inst.format) { case 1: case 2: case 5: case 6: case 7: return vue.cpu.inst.reg2; } @@ -1470,7 +1578,8 @@ public class Breakpoint { } // Evaluate regid - private static int evalRegId(JavaVue vue) { + private int evalRegId() { + var vue = (JavaVue) this.vue; switch (vue.cpu.inst.id) { case Vue.LDSR: case Vue.STSR: return vue.cpu.inst.imm; } @@ -1478,7 +1587,8 @@ public class Breakpoint { } // Evaluate subopcode - private static int evalSubopcode(JavaVue vue) { + private int evalSubopcode() { + var vue = (JavaVue) this.vue; switch (vue.cpu.inst.opcode) { case 0x1F: return vue.cpu.inst.imm; case 0x3E: return vue.cpu.inst.subopcode; @@ -1487,12 +1597,14 @@ public class Breakpoint { } // Evaluate value - private static int evalValue(JavaVue vue) { + private int evalValue() { + var vue = (JavaVue) this.vue; return vue.cpu.inst.format == 6 ? vue.cpu.access.value : 0; } // Evaluate vector - private static int evalVector(JavaVue vue) { + private int evalVector() { + var vue = (JavaVue) this.vue; return vue.cpu.inst.id == Vue.TRAP ? vue.cpu.inst.imm : 0; } @@ -1533,7 +1645,8 @@ public class Breakpoint { } // Evaluate [] - private static int evalReadWord(boolean isWord, int value, JavaVue vue) { + private int evalReadWord(boolean isWord, int value) { + var vue = (JavaVue) this.vue; return vue.read(isWord ? value : toWord(asFloat(value)), Vue.S32); } diff --git a/src/desktop/vue/NativeVue.c b/src/desktop/vue/NativeVue.c index 56efc1d..a402403 100644 --- a/src/desktop/vue/NativeVue.c +++ b/src/desktop/vue/NativeVue.c @@ -22,19 +22,27 @@ static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; // Types // /////////////////////////////////////////////////////////////////////////////// -// Breakpoint token +// Breakpoint address range typedef struct { - int32_t type; - int32_t value; + int32_t start; // First address, inclusive + int32_t end; // Last address, inclusive +} Range; + +// Breakpoint condition token +typedef struct { + int32_t type; // Token category + int32_t value; // Operator or symbol ID, or literal value } Token; // Precompiled breakpoint typedef struct { - int32_t enabled; // The breakpoint is enabled - int32_t numAddresses; // Number of address ranges - int32_t numCondition; // Number of tokens in condition - int32_t *addresses; // Address ranges - Token *condition; // Condition tokens in RPN order + int32_t depth; // Maximum number of stack entries + int32_t enabled; // The breakpoint is enabled + int32_t hooks; // Events hooked by the breakpoint + int32_t numRanges; // Number of address ranges + int32_t numTokens; // Number of condition tokens + Range *ranges; // Address ranges + Token *tokens; // Condition tokens in RPN order } Breakpoint; // Core context state type @@ -67,7 +75,7 @@ typedef struct { /////////////////////////////////////////////////////////////////////////////// -// Method Functions // +// Public Methods // /////////////////////////////////////////////////////////////////////////////// // Native constructor @@ -83,7 +91,18 @@ JNIEXPORT jlong JNICALL Java_vue_NativeVue_construct // Release any used resources JNIEXPORT void JNICALL Java_vue_NativeVue_dispose (JNIEnv *env, jobject vue, jlong handle) { - Core *core = *(Core **)&handle; + Core *core = *(Core **)&handle; + Breakpoint *brk; // Handle to breakpoint + int x; // Iterator + + // Delete breakpoints + for (x = 0; x < core->numBreakpoints; x++) { + brk = &core->breakpoints[x]; + if (brk->ranges != NULL) free(brk->ranges); + if (brk->tokens != NULL) free(brk->tokens); + } + + // Delete core if (core->breakpoints != NULL) free(core->breakpoints); if (core->stack != NULL) free(core->stack ); if (core->vue.pak.rom != NULL) free(core->vue.pak.rom); @@ -234,3 +253,108 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVue_writeBytes (*env)->ReleaseByteArrayElements(env, data, elems, 0); return JNI_TRUE; } + + + +/////////////////////////////////////////////////////////////////////////////// +// Private Methods // +/////////////////////////////////////////////////////////////////////////////// + +// Produce a new breakpoint and add it to the collection +JNIEXPORT void JNICALL Java_vue_NativeVue_breakpoint + (JNIEnv *env, jobject vue, jlong handle) { + Core *core = *(Core **)&handle; + int32_t size; // Number of bytes to allocate + + // Allocate memory for the breakpoint + core->numBreakpoints++; + size = core->numBreakpoints * sizeof (Breakpoint); + core->breakpoints = core->breakpoints == NULL ? + malloc(size) : realloc(core->breakpoints, size); + + // Initialize the breakpoint + memset(&core->breakpoints[core->numBreakpoints-1], 0, sizeof (Breakpoint)); +} + +// Remove a breakpoint from the collection +JNIEXPORT void JNICALL Java_vue_NativeVue_remove + (JNIEnv *env, jobject vue, jlong handle, jint index) { + Core *core = *(Core **)&handle; + Breakpoint *brk = &core->breakpoints[index]; + + // Delete the breakpoint + if (brk->ranges != NULL) free(brk->ranges); + if (brk->tokens != NULL) free(brk->tokens); + + // Move all subsequent breakpoints forward + if (index != core->numBreakpoints - 1) + memmove(brk, &brk[1], + (core->numBreakpoints - index) * sizeof (Breakpoint)); + core->numBreakpoints--; +} + +// A breakpoint's address ranges have changed +JNIEXPORT void JNICALL Java_vue_NativeVue_updateRanges + (JNIEnv *env, jobject vue, jlong handle, jint index, jintArray ranges) { + Core *core = *(Core **)&handle; + Breakpoint *brk = &core->breakpoints[index]; + jint *elems; // Array elements + int32_t size; // Number of bytes to allocate + + // Determine the number of address ranges + brk->numRanges = (*env)->GetArrayLength(env, ranges) / 2; + if (brk->numRanges == 0) { + if (brk->ranges != NULL) + free(brk->ranges); + brk->ranges = NULL; + return; + } + + // Allocate memory for the address ranges + size = brk->numRanges * sizeof (Range); + brk->ranges = brk->ranges == NULL ? + malloc(size) : realloc(brk->ranges, size); + + // Initialize address ranges + elems = (*env)->GetIntArrayElements(env, ranges, NULL); + memcpy(brk->ranges, elems, size); + (*env)->ReleaseIntArrayElements(env, ranges, elems, JNI_ABORT); +} + +// A breakpoint's enabled/hook state has changed +JNIEXPORT void JNICALL Java_vue_NativeVue_updateState + (JNIEnv *env, jobject vue, jlong handle, jint index, jboolean enabled, + jint hooks) { + Core *core = *(Core **)&handle; + Breakpoint *brk = &core->breakpoints[index]; + brk->enabled = enabled; + brk->hooks = hooks; +} + +// A breakpoint's condition tokens have changed +JNIEXPORT void JNICALL Java_vue_NativeVue_updateTokens + (JNIEnv *env, jobject vue, jlong handle, jint index, jintArray tokens) { + Core *core = *(Core **)&handle; + Breakpoint *brk = &core->breakpoints[index]; + jint *elems; // Array elements + int32_t size; // Number of bytes to allocate + + // Determine the number of condition tokens + brk->numTokens = (*env)->GetArrayLength(env, tokens) / 2; + if (brk->numTokens == 0) { + if (brk->tokens != NULL) + free(brk->tokens); + brk->tokens = NULL; + return; + } + + // Allocate memory for the condition tokens + size = brk->numTokens * sizeof (Token); + brk->tokens = brk->tokens == NULL ? + malloc(size) : realloc(brk->tokens, size); + + // Initialize condition tokens + elems = (*env)->GetIntArrayElements(env, tokens, NULL); + memcpy(brk->tokens, elems, size); + (*env)->ReleaseIntArrayElements(env, tokens, elems, JNI_ABORT); +} diff --git a/src/desktop/vue/NativeVue.java b/src/desktop/vue/NativeVue.java index 279c49f..cc1f61e 100644 --- a/src/desktop/vue/NativeVue.java +++ b/src/desktop/vue/NativeVue.java @@ -24,6 +24,13 @@ class NativeVue extends Vue { // Public Methods // /////////////////////////////////////////////////////////////////////////// + // Produce a new breakpoint and add it to the collection + public Breakpoint breakpoint() { + var brk = super.breakpoint(); + breakpoint(handle); + return brk; + } + // Release any used resources private native void dispose(long handle); public void dispose() @@ -61,6 +68,15 @@ class NativeVue extends Vue { public boolean readBytes(int address, byte[] dest, int offset, int length) { return readBytes(handle, address, dest, offset, length); } + // Remove a breakpoint from the collection + public boolean remove(Breakpoint brk) { + int index = breakpoints.indexOf(brk); + if (!super.remove(brk)) + return false; + remove(handle, index); + return true; + } + // Initialize all system components private native void reset(long handle); public void reset() @@ -100,4 +116,45 @@ class NativeVue extends Vue { return false; } + // A breakpoint's address ranges have changed + void updateRanges(Breakpoint brk) { + super.updateRanges(brk); + updateRanges(handle, breakpoints.indexOf(brk), brk.flattenRanges()); + } + + // A breakpoint's enabled/hook state has changed + void updateState(Breakpoint brk) { + super.updateState(brk); + updateState(handle, breakpoints.indexOf(brk), + brk.isEnabled(), brk.getHooks()); + } + + // A breakpoint's condition tokens have changed + void updateTokens(Breakpoint brk) { + super.updateTokens(brk); + updateTokens(handle, breakpoints.indexOf(brk), brk.flattenTokens()); + } + + + + /////////////////////////////////////////////////////////////////////////// + // Private Methods // + /////////////////////////////////////////////////////////////////////////// + + // Produce a new breakpoint and add it to the collection + private native void breakpoint(long handle); + + // Remove a breakpoint from the collection + private native void remove(long handle, int index); + + // A breakpoint's address ranges have changed + private native void updateRanges(long handle, int index, int[] ranges); + + // A breakpoint's enabled/hook state has changed + private native void updateState(long handle, int index, boolean enabled, + int hooks); + + // A breakpoint's condition tokens have changed + private native void updateTokens(long handle, int index, int[] tokens); + } diff --git a/src/desktop/vue/Vue.java b/src/desktop/vue/Vue.java index 951f4c4..c81f54b 100644 --- a/src/desktop/vue/Vue.java +++ b/src/desktop/vue/Vue.java @@ -249,8 +249,13 @@ public abstract class Vue { // Evaluate the condition in a breakpoint abstract boolean evaluate(Breakpoint brk); - // A breakpoint has been updated - void update(Breakpoint brk) { - } + // A breakpoint's address ranges have changed + void updateRanges(Breakpoint brk) { } + + // A breakpoint's enabled/hook state has changed + void updateState(Breakpoint brk) { } + + // A breakpoint's condition tokens have changed + void updateTokens(Breakpoint brk) { } }