Skip to content

Commit 00045fb

Browse files
committed
WATCH expression evaluation from memory
1 parent 85f40b7 commit 00045fb

File tree

2 files changed

+82
-4
lines changed

2 files changed

+82
-4
lines changed

src/cc65Debug.ts

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
readDebugFile,
2525
spansToSpanLines,
2626
} from "./dbgService";
27-
import { normalizePath, parseNumber, unquote } from "./utils";
27+
import { normalizePath, parseNumber, toHex, unquote } from "./utils";
2828

2929
export enum ErrorCodes {
3030
DAP_NOT_SUPPORTED = 1000,
@@ -83,6 +83,7 @@ export class Cc65DebugSession extends LoggingDebugSession {
8383
private _debugData: DbgMap | undefined;
8484
private _debugPathBases: string[] = [];
8585
private _requestBreakpoints: Map<number, (number | string)[]> = new Map();
86+
private _pendingResponse: Map<number, DebugProtocol.Response> = new Map();
8687

8788
static scopeVariablesReferenceBase = 1000000000;
8889

@@ -127,6 +128,7 @@ export class Cc65DebugSession extends LoggingDebugSession {
127128
case "setBreakpoints":
128129
case "setInstructionBreakpoints":
129130
case "variables":
131+
case "evaluate":
130132
// these are messages we want to modify before sending to debugger/adapter
131133
// pass to dispatcher, so the matching method will handle the modification
132134
return super.handleMessage(message);
@@ -336,9 +338,7 @@ export class Cc65DebugSession extends LoggingDebugSession {
336338

337339
for (const instruction of instructions) {
338340
if (instruction.presentationHint !== "invalid" && instruction.address != null) {
339-
const address = instruction.address.startsWith("0x")
340-
? Number.parseInt(instruction.address.slice(2), 16)
341-
: Number.parseInt(instruction.address, 10);
341+
const address = parseNumber(instruction.address);
342342

343343
const spans = addressToSpans(this._debugData, address, true);
344344
const lines = spansToSpanLines(this._debugData, spans);
@@ -412,6 +412,41 @@ export class Cc65DebugSession extends LoggingDebugSession {
412412

413413
return this.sendResponse(result);
414414
}
415+
case "readMemory": {
416+
if (this._pendingResponse.has(response.request_seq)) {
417+
const pendingResponse = this._pendingResponse.get(
418+
response.request_seq,
419+
) as DebugProtocol.EvaluateResponse;
420+
if (pendingResponse) {
421+
this._pendingResponse.delete(response.request_seq);
422+
const result = response as DebugProtocol.ReadMemoryResponse;
423+
// This is a readMemory response requested for symbol evaluation.
424+
// Convert read data to symbol value.
425+
if (!pendingResponse.body)
426+
pendingResponse.body = { result: "", variablesReference: 0 };
427+
pendingResponse.body.variablesReference = 0;
428+
pendingResponse.body.memoryReference = result.body?.address;
429+
pendingResponse.body.presentationHint = {
430+
kind: "data",
431+
attributes: ["static"],
432+
visibility: "public",
433+
};
434+
435+
const data = [...Buffer.from(result.body?.data || "", "base64")];
436+
switch (data.length) {
437+
case 1:
438+
pendingResponse.body.result = `$${toHex(data[0])}`;
439+
break;
440+
case 2:
441+
pendingResponse.body.result = `$${toHex(data[1])}${toHex(data[0])}`;
442+
break;
443+
default:
444+
pendingResponse.body.result = data.map((d) => toHex(d)).join(" ");
445+
}
446+
return this.sendResponse(pendingResponse);
447+
}
448+
}
449+
}
415450
}
416451
return this.sendResponse(response);
417452
}
@@ -783,6 +818,41 @@ export class Cc65DebugSession extends LoggingDebugSession {
783818
return this.sendMessage(request);
784819
}
785820

821+
protected evaluateRequest(
822+
response: DebugProtocol.EvaluateResponse,
823+
args: DebugProtocol.EvaluateArguments,
824+
request: DebugProtocol.Request,
825+
) {
826+
console.log("evaluateRequest", args, response);
827+
828+
const { expression } = args;
829+
830+
if (expression) {
831+
const dbgSym = this._debugData?.sym.find(
832+
(sym) => unquote(sym.name) === expression && sym.type !== "imp",
833+
);
834+
// if this expression is a symbol, send its address and size
835+
// as encoded memory address
836+
if (dbgSym?.val && dbgSym.size != null) {
837+
console.log("Memory read symbol", expression, dbgSym.val);
838+
// replace the evaluate request with a memory read request
839+
const memoryRequest: DebugProtocol.ReadMemoryRequest = {
840+
seq: request.seq,
841+
type: "request",
842+
command: "readMemory",
843+
arguments: {
844+
memoryReference: dbgSym.val,
845+
count: dbgSym.size,
846+
},
847+
};
848+
this._pendingResponse.set(request.seq, response);
849+
return this.sendMessage(memoryRequest);
850+
}
851+
}
852+
853+
return this.sendMessage(request);
854+
}
855+
786856
// --------------------------------------------------------------------
787857
private dbgFile2workspace(dbgFile: DbgFile) {
788858
const fileName = normalizePath(dbgFile.name);

src/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,11 @@ export function unquote(str: string): string {
1414
export function normalizePath(pathString: string): string {
1515
return path.normalize(unquote(pathString).replaceAll(path.win32.sep, path.posix.sep));
1616
}
17+
18+
export function parseNumber(str: string): number {
19+
return str.startsWith("0x") ? Number.parseInt(str.slice(2), 16) : Number.parseInt(str, 10);
20+
}
21+
22+
export function toHex(num: number, length = 2): string {
23+
return num.toString(16).padStart(length, "0");
24+
}

0 commit comments

Comments
 (0)