Skip to content

Commit

Permalink
allow breaking on byte ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
connor4312 committed Mar 6, 2024
1 parent 886b1b6 commit e680ab8
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 8 deletions.
6 changes: 6 additions & 0 deletions sampleWorkspace/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ If a Mock Debug session is active, breakpoints are "validated" according to thes
* if a line starts with `!`, "hardware" breakpoints can be set on the line
* a breakpoint on a line containing the word `lazy` is not immediately validated, but only after hitting it once.

!some line

## Data Breakpoints

Data Breakpoints can be set for different access modes in the VARIABLES view of the editor via the context menu.
Expand All @@ -51,6 +53,10 @@ Examples:
- Read Access: $i
- Write Access: $i=999

You can also set data breakpoints on "memory addresses". In mock debug, the "address" of a variable is the zero-indexed order in which it was made, so asking to pause on read/writes to `0x2` will pause when the third variable is written to, which is `b1` in this readme:

- Read Access: $b1

## Disassembly View

If a markdown line contains the word 'disassembly', the context menu's "Open Disassembly View" command is enabled and the Disassembly view shows (fake) assembly instructions and "instruction stepping" and "instruction breakpoints" are supported.
Expand Down
18 changes: 17 additions & 1 deletion src/mockDebug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ export class MockDebugSession extends LoggingDebugSession {

// make VS Code support data breakpoints
response.body.supportsDataBreakpoints = true;
response.body.supportsDataBreakpointBytes = true;

// make VS Code support completion in REPL
response.body.supportsCompletionsRequest = true;
Expand Down Expand Up @@ -688,6 +689,11 @@ export class MockDebugSession extends LoggingDebugSession {
response.body.accessTypes = ["read", "write", "readWrite"];
response.body.canPersist = true;
}
} else if (args.asAddress) {
response.body.dataId = `range:${args.name}:${args.bytes || 1}`;
response.body.description = `${args.bytes} variables after ${args.name}`;
response.body.accessTypes = ["read", "write", "readWrite"];
response.body.canPersist = true;
}

this.sendResponse(response);
Expand All @@ -703,7 +709,17 @@ export class MockDebugSession extends LoggingDebugSession {
};

for (const dbp of args.breakpoints) {
const ok = this._runtime.setDataBreakpoint(dbp.dataId, dbp.accessType || 'write');
let ok = false;
if (dbp.dataId.startsWith('range:')) {
const [, start, bytes] = dbp.dataId.split(':').map(Number);
for (let i = 0; i < bytes; i++) {
this._runtime.setDataBreakpoint(start + i, dbp.accessType || 'write')
ok = true;
}
} else {
ok = this._runtime.setDataBreakpoint(dbp.dataId, dbp.accessType || 'write');
}

response.body.breakpoints.push({
verified: ok
});
Expand Down
18 changes: 11 additions & 7 deletions src/mockRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export class RuntimeVariable {
private _memory?: Uint8Array;

public reference?: number;
public ordinal?: number;

public get value() {
return this._value;
Expand Down Expand Up @@ -144,7 +145,7 @@ export class MockRuntime extends EventEmitter {
// so that the frontend can match events with breakpoints.
private breakpointId = 1;

private breakAddresses = new Map<string, string>();
private breakAddresses = new Map<string | number, string>();

private namedException: string | undefined;
private otherExceptions = false;
Expand Down Expand Up @@ -371,17 +372,17 @@ export class MockRuntime extends EventEmitter {
this.breakPoints.delete(this.normalizePathAndCasing(path));
}

public setDataBreakpoint(address: string, accessType: 'read' | 'write' | 'readWrite'): boolean {
public setDataBreakpoint(nameOrOrdinal: string | number, accessType: 'read' | 'write' | 'readWrite'): boolean {

const x = accessType === 'readWrite' ? 'read write' : accessType;

const t = this.breakAddresses.get(address);
const t = this.breakAddresses.get(nameOrOrdinal);
if (t) {
if (t !== x) {
this.breakAddresses.set(address, 'read write');
this.breakAddresses.set(nameOrOrdinal, 'read write');
}
} else {
this.breakAddresses.set(address, x);
this.breakAddresses.set(nameOrOrdinal, x);
}
return true;
}
Expand Down Expand Up @@ -589,15 +590,18 @@ export class MockRuntime extends EventEmitter {
// the first write access to a variable is the "declaration" and not a "write access"
access = 'write';
}
v.ordinal = this.variables.size;
this.variables.set(name, v);
} else {
if (this.variables.has(name)) {
const existing = this.variables.get(name);
if (existing) {
// variable must exist in order to trigger a read access
access = 'read';
v.ordinal = existing.ordinal;
}
}

const accessType = this.breakAddresses.get(name);
const accessType = this.breakAddresses.get(name) || this.breakAddresses.get(v.ordinal!);
if (access && accessType && accessType.indexOf(access) >= 0) {
this.sendEvent('stopOnDataBreakpoint', access);
return true;
Expand Down

0 comments on commit e680ab8

Please sign in to comment.