From 4e6af5939382f53a837fe94691ebc4992677a42f Mon Sep 17 00:00:00 2001 From: Graham Bates Date: Sat, 18 Nov 2023 23:36:53 +0000 Subject: [PATCH] specify expected responses --- src/gdbClient.ts | 77 ++++++++++++++++++++++-------------------- src/variableManager.ts | 13 ++++--- 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/gdbClient.ts b/src/gdbClient.ts index 73f0465..f788bf0 100644 --- a/src/gdbClient.ts +++ b/src/gdbClient.ts @@ -47,6 +47,13 @@ const signalLabels: Record = { [HaltSignal.SEGV]: "Segmentation fault", }; +const resp = { + OK: /^OK$/, + HEX: /^[0-9a-f]/, + STOP: /^[ST]/, + ANY: /./, +}; + export class GdbClient { private socket: Socket; private requestMutex = new Mutex(); @@ -66,7 +73,7 @@ export class GdbClient { const cb = async () => { try { logger.log("Connected: initializing"); - await this.request("QStartNoAckMode", true, "OK"); + await this.request("QStartNoAckMode"); resolve(); } catch (error) { this.socket.destroy(); @@ -90,7 +97,7 @@ export class GdbClient { } public async getOffsets(): Promise { - const res = await this.request("qOffsets"); + const res = await this.request("qOffsets", resp.HEX); return res.split(";").map((a) => parseInt(a, 16)); } @@ -129,15 +136,15 @@ export class GdbClient { // Navigation: public async pause(threadId: number): Promise { - await this.request("vCont;t:" + threadId); + await this.request("vCont;t:" + threadId, resp.STOP); } public async continueExecution(threadId: number): Promise { - await this.request("vCont;c:" + threadId, false); + await this.requestNoRes("vCont;c:" + threadId); } public async stepIn(threadId: number): Promise { - await this.request("vCont;s:" + threadId); + await this.request("vCont;s:" + threadId, resp.STOP); } public async stepToRange( @@ -146,7 +153,8 @@ export class GdbClient { endAddress: number ): Promise { await this.request( - "vCont;r" + hex(startAddress) + "," + hex(endAddress) + ":" + threadId + "vCont;r" + hex(startAddress) + "," + hex(endAddress) + ":" + threadId, + resp.STOP ); } @@ -154,14 +162,14 @@ export class GdbClient { if (this.haltStatus) { return this.haltStatus; } - const response = await this.request("?"); + const response = await this.request("?", /^(OK|S|T)/); return response.indexOf("OK") < 0 ? this.parseHaltStatus(response) : null; } // Memory: public async readMemory(address: number, length: number): Promise { - return this.request("m" + hex(address) + "," + hex(length)); + return this.request("m" + hex(address) + "," + hex(length), resp.HEX); } public async writeMemory(address: number, dataToSend: string): Promise { @@ -172,7 +180,10 @@ export class GdbClient { // Registers: public async getRegisters(threadId?: number | null): Promise { - const message = await this.request(threadId ? "Hg" + threadId : "g"); + const message = await this.request( + threadId ? "Hg" + threadId : "g", + resp.HEX + ); const registers: number[] = []; const regCount = Math.floor(message.length / 8); @@ -184,28 +195,18 @@ export class GdbClient { } public async getRegister(regIdx: number): Promise { - const data = await this.request("p" + hex(regIdx)); + const data = await this.request("p" + hex(regIdx), resp.HEX); return parseInt(data, 16); } - public async setRegister(regIdx: number, value: string): Promise { - if (!value.match(/[a-z\d]{1,8}/i)) { - throw new Error("The value must be a hex string with at most 8 digits"); - } - const response = await this.request( - "P" + regIdx.toString(16) + "=" + value - ); - if (response && response.indexOf("OK") >= 0) { - return value; - } else { - throw new Error("Error setting the register value"); - } + public async setRegister(regIdx: number, value: number): Promise { + await this.request("P" + regIdx.toString(16) + "=" + value.toString(16)); } // Stack Frames: public async getFramesCount(): Promise { - const data = await this.request("qTStatus"); + const data = await this.request("qTStatus", /^T/); const frameCountPosition = data.indexOf("tframes"); if (frameCountPosition > 0) { let endFrameCountPosition = data.indexOf(";", frameCountPosition); @@ -223,7 +224,7 @@ export class GdbClient { await this.request("QTFrame:ffffffff"); return DEFAULT_FRAME_INDEX; } - const data = await this.request("QTFrame:" + hex(frameIndex)); + const data = await this.request("QTFrame:" + hex(frameIndex), /^F/); if (data === "F-1") { // No frame found @@ -253,7 +254,10 @@ export class GdbClient { // Commands: public async monitor(command: string): Promise { - const response = await this.request("qRcmd," + stringToHex(command)); + const response = await this.request( + "qRcmd," + stringToHex(command), + resp.ANY + ); return response; } @@ -287,17 +291,13 @@ export class GdbClient { private async request( text: string, - responseExpected = true, - expectedResponse?: string + expectedResponse = resp.OK ): Promise { return this.requestMutex.runExclusive(async () => { const req = `$${text}#${calculateChecksum(text)}`; logger.log(`[GDB] --> ${req}`); this.socket.write(req); - if (!responseExpected) { - return ""; - } return await new Promise((resolve, reject) => { const timeout = setTimeout(() => { logger.log(`[GDB] TIMEOUT: ${req}`); @@ -311,10 +311,7 @@ export class GdbClient { this.responseCallback = undefined; clearTimeout(timeout); reject(new GdbError(message)); - } else if ( - !message.match(/^O[0-9a-f]/i) && // Ignore output - (!expectedResponse || message.startsWith(expectedResponse)) - ) { + } else if (message.match(expectedResponse)) { this.responseCallback = undefined; clearTimeout(timeout); resolve(message); @@ -326,6 +323,14 @@ export class GdbClient { }); } + private async requestNoRes(text: string): Promise { + return this.requestMutex.runExclusive(async () => { + const req = `$${text}#${calculateChecksum(text)}`; + logger.log(`[GDB] --> ${req}`); + this.socket.write(req); + }); + } + private handleData(data: Buffer) { const messages = [...data.toString().matchAll(/\$([^#]*)#[\da-f]{2}/g)].map( (m) => m[1] @@ -337,9 +342,7 @@ export class GdbClient { switch (message[0]) { case "S": case "T": - if (!message.startsWith("Te") || !message.includes("tframes")) { - logger.log(`[GDB] STOP: ${message}`); - } + logger.log(`[GDB] STOP: ${message}`); this.haltStatus = this.parseHaltStatus(message); this.sendEvent("stop", this.haltStatus); break; diff --git a/src/variableManager.ts b/src/variableManager.ts index e594449..d2d0076 100644 --- a/src/variableManager.ts +++ b/src/variableManager.ts @@ -926,16 +926,19 @@ class VariableManager { value: string ): Promise { const scopeRef = this.scopes.get(variablesReference); - const numValue = await this.evaluate(value); + let numValue = await this.evaluate(value); if (typeof numValue !== "number") { throw new Error("Value is not numeric"); } switch (scopeRef?.type) { case ScopeType.Registers: - await this.gdb.setRegister( - getRegisterIndex(name), - numValue.toString(16) - ); + if (numValue < 0) { + numValue += 0x100000000; + } + if (Math.abs(numValue) > 0x100000000) { + throw new Error("Register value out of range"); + } + await this.gdb.setRegister(getRegisterIndex(name), numValue); return this.formatVariable(name, numValue, NumberFormat.HEXADECIMAL, 4); case ScopeType.Vectors: {