Added examining memory locations (fix #64)
also added a way to run mi commands over unix domain sockets so other applications can communicate with code-debug
This commit is contained in:
parent
e78733308e
commit
87ff8b8644
5 changed files with 184 additions and 7 deletions
19
package.json
19
package.json
|
|
@ -6,8 +6,12 @@
|
|||
"publisher": "webfreak",
|
||||
"icon": "images/icon-plain.svg",
|
||||
"engines": {
|
||||
"vscode": "^1.3.0"
|
||||
"vscode": "^0.10.10"
|
||||
},
|
||||
"main": "./out/src/frontend/extension",
|
||||
"activationEvents": [
|
||||
"onCommand:code-debug.examineMemoryLocation"
|
||||
],
|
||||
"categories": [
|
||||
"Debuggers"
|
||||
],
|
||||
|
|
@ -16,6 +20,12 @@
|
|||
"url": "https://github.com/WebFreak001/code-debug.git"
|
||||
},
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "code-debug.examineMemoryLocation",
|
||||
"title": "Code-Debug: Examine memory location"
|
||||
}
|
||||
],
|
||||
"debuggers": [
|
||||
{
|
||||
"type": "gdb",
|
||||
|
|
@ -347,7 +357,7 @@
|
|||
},
|
||||
"autorun": {
|
||||
"type": "array",
|
||||
"description": "LLDB commands to run when starting to debug",
|
||||
"description": "lldb commands to run when starting to debug",
|
||||
"default": []
|
||||
}
|
||||
}
|
||||
|
|
@ -439,7 +449,7 @@
|
|||
},
|
||||
"autorun": {
|
||||
"type": "array",
|
||||
"description": "Mago commands to run when starting to debug",
|
||||
"description": "mago commands to run when starting to debug",
|
||||
"default": []
|
||||
}
|
||||
}
|
||||
|
|
@ -460,7 +470,8 @@
|
|||
"scripts": {
|
||||
"vscode:prepublish": "node ./node_modules/vscode/bin/compile",
|
||||
"compile": "node ./node_modules/vscode/bin/compile -watch -p ./",
|
||||
"test": "node ./node_modules/vscode/bin/test"
|
||||
"test": "node ./node_modules/vscode/bin/test",
|
||||
"postinstall": "node ./node_modules/vscode/bin/install"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-debugadapter": "^1.10.0",
|
||||
|
|
|
|||
|
|
@ -56,4 +56,5 @@ export interface IBackend {
|
|||
evalExpression(name: string): Thenable<any>;
|
||||
isReady(): boolean;
|
||||
changeVariable(name: string, rawValue: string): Thenable<any>;
|
||||
examineMemory(from: number, to: number): Thenable<any>;
|
||||
}
|
||||
|
|
@ -556,6 +556,14 @@ export class MI2 extends EventEmitter implements IBackend {
|
|||
});
|
||||
}
|
||||
|
||||
examineMemory(from: number, length: number): Thenable<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.sendCommand("data-read-memory-bytes 0x" + from.toString(16) + " " + length).then((result) => {
|
||||
resolve(result.result("memory[0].contents"));
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
|
||||
evalExpression(name: string): Thenable<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.sendCommand("data-evaluate-expression " + name).then((result) => {
|
||||
|
|
|
|||
125
src/frontend/extension.ts
Normal file
125
src/frontend/extension.ts
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import * as vscode from "vscode";
|
||||
import * as net from "net";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as os from "os";
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider("debugmemory", new MemoryContentProvider()));
|
||||
context.subscriptions.push(vscode.commands.registerCommand("code-debug.examineMemoryLocation", examineMemory));
|
||||
}
|
||||
|
||||
var memoryLocationRegex = /^0x[0-9a-f]+$/;
|
||||
|
||||
function getMemoryRange(range: string) {
|
||||
if (!range)
|
||||
return undefined;
|
||||
range = range.replace(/\s+/g, "").toLowerCase();
|
||||
var index;
|
||||
if ((index = range.indexOf("+")) != -1) {
|
||||
var from = range.substr(0, index);
|
||||
var length = range.substr(index + 1);
|
||||
if (!memoryLocationRegex.exec(from))
|
||||
return undefined;
|
||||
if (memoryLocationRegex.exec(length))
|
||||
length = parseInt(length.substr(2), 16).toString();
|
||||
return "from=" + encodeURIComponent(from) + "&length=" + encodeURIComponent(length);
|
||||
}
|
||||
else if ((index = range.indexOf("-")) != -1) {
|
||||
var from = range.substr(0, index);
|
||||
var to = range.substr(index + 1);
|
||||
if (!memoryLocationRegex.exec(from))
|
||||
return undefined;
|
||||
if (!memoryLocationRegex.exec(to))
|
||||
return undefined;
|
||||
return "from=" + encodeURIComponent(from) + "&to=" + encodeURIComponent(to);
|
||||
}
|
||||
else if (memoryLocationRegex.exec(range))
|
||||
return "at=" + encodeURIComponent(range);
|
||||
else return undefined;
|
||||
}
|
||||
|
||||
function examineMemory() {
|
||||
let socketlists = path.join(os.tmpdir(), "code-debug-sockets");
|
||||
if (!fs.existsSync(socketlists))
|
||||
return vscode.window.showErrorMessage("No debugging sessions available");
|
||||
fs.readdir(socketlists, (err, files) => {
|
||||
if (err)
|
||||
return vscode.window.showErrorMessage("No debugging sessions available");
|
||||
var pickedFile = (file) => {
|
||||
vscode.window.showInputBox({ placeHolder: "Memory Location or Range", validateInput: range => getMemoryRange(range) === undefined ? "Range must either be in format 0xF00-0xF01, 0xF100+32 or 0xABC154" : "" }).then(range => {
|
||||
vscode.commands.executeCommand("vscode.previewHtml", vscode.Uri.parse("debugmemory://" + file + "#" + getMemoryRange(range)));
|
||||
});
|
||||
};
|
||||
if (files.length == 1)
|
||||
pickedFile(files[0]);
|
||||
else if (files.length > 0)
|
||||
vscode.window.showQuickPick(files, { placeHolder: "Running debugging instance" }).then(file => pickedFile(file));
|
||||
else
|
||||
vscode.window.showErrorMessage("No debugging sessions available");
|
||||
});
|
||||
}
|
||||
|
||||
class MemoryContentProvider implements vscode.TextDocumentContentProvider {
|
||||
provideTextDocumentContent(uri: vscode.Uri, token: vscode.CancellationToken): Thenable<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
var conn = net.connect(path.join(os.tmpdir(), "code-debug-sockets", uri.authority));
|
||||
var from, to;
|
||||
var highlightAt = -1;
|
||||
var splits = uri.fragment.split("&");
|
||||
if (splits[0].split("=")[0] == "at") {
|
||||
var loc = parseInt(splits[0].split("=")[1].substr(2), 16);
|
||||
highlightAt = 64;
|
||||
from = Math.max(loc - 64, 0);
|
||||
to = Math.max(loc + 768, 0);
|
||||
}
|
||||
else if (splits[0].split("=")[0] == "from") {
|
||||
from = parseInt(splits[0].split("=")[1].substr(2), 16);
|
||||
if (splits[1].split("=")[0] == "to") {
|
||||
to = parseInt(splits[1].split("=")[1].substr(2), 16);
|
||||
}
|
||||
else if (splits[1].split("=")[0] == "length") {
|
||||
to = from + parseInt(splits[1].split("=")[1]);
|
||||
}
|
||||
else return reject("Invalid Range");
|
||||
}
|
||||
else return reject("Invalid Range");
|
||||
if (to < from)
|
||||
return reject("Negative Range");
|
||||
conn.write("examineMemory " + JSON.stringify([from, to - from + 1]));
|
||||
conn.once("data", data => {
|
||||
var formattedCode = "";
|
||||
var hexString = data.toString();
|
||||
var x = 0;
|
||||
var asciiLine = "";
|
||||
var byteNo = 0;
|
||||
for (var i = 0; i < hexString.length; i += 2) {
|
||||
var digit = hexString.substr(i, 2);
|
||||
var digitNum = parseInt(digit, 16);
|
||||
if (digitNum >= 32 && digitNum <= 126)
|
||||
asciiLine += String.fromCharCode(digitNum);
|
||||
else
|
||||
asciiLine += ".";
|
||||
if (highlightAt == byteNo) {
|
||||
formattedCode += "<b>" + digit + "</b> ";
|
||||
} else
|
||||
formattedCode += digit + " ";
|
||||
if (++x > 16) {
|
||||
formattedCode += asciiLine + "\n";
|
||||
x = 0;
|
||||
asciiLine = "";
|
||||
}
|
||||
byteNo++;
|
||||
}
|
||||
if (x > 0) {
|
||||
for (var i = 0; i <= 16 - x; i++) {
|
||||
formattedCode += " ";
|
||||
}
|
||||
formattedCode += asciiLine;
|
||||
}
|
||||
resolve("<h2>Memory Range from 0x" + from.toString(16) + " to 0x" + to.toString(16) + "</h2><code><pre>" + formattedCode + "</pre></code>");
|
||||
conn.destroy();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,9 @@ import { expandValue, isExpandable } from './backend/gdb_expansion';
|
|||
import { MI2 } from './backend/mi2/mi2';
|
||||
import { posix } from "path";
|
||||
import * as systemPath from "path";
|
||||
import * as net from "net";
|
||||
import * as os from "os";
|
||||
import * as fs from "fs";
|
||||
|
||||
let resolve = posix.resolve;
|
||||
let relative = posix.relative;
|
||||
|
|
@ -23,6 +26,7 @@ export class MI2DebugSession extends DebugSession {
|
|||
protected debugReady: boolean;
|
||||
protected miDebugger: MI2;
|
||||
protected threadID: number = 1;
|
||||
protected commandServer: net.Server;
|
||||
|
||||
public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false, threadID: number = 1) {
|
||||
super(debuggerLinesStartAt1, isServer);
|
||||
|
|
@ -39,6 +43,31 @@ export class MI2DebugSession extends DebugSession {
|
|||
this.miDebugger.on("step-out-end", this.handleBreak.bind(this));
|
||||
this.miDebugger.on("signal-stop", this.handlePause.bind(this));
|
||||
this.sendEvent(new InitializedEvent());
|
||||
try {
|
||||
this.commandServer = net.createServer(c => {
|
||||
c.on("data", data => {
|
||||
var rawCmd = data.toString();
|
||||
var spaceIndex = rawCmd.indexOf(" ");
|
||||
var func = rawCmd;
|
||||
var args = [];
|
||||
if (spaceIndex != -1) {
|
||||
func = rawCmd.substr(0, spaceIndex);
|
||||
args = JSON.parse(rawCmd.substr(spaceIndex + 1));
|
||||
}
|
||||
Promise.resolve(this.miDebugger[func].apply(this.miDebugger, args)).then(data => {
|
||||
c.write(data.toString());
|
||||
});
|
||||
});
|
||||
});
|
||||
this.commandServer.on("error", err => {
|
||||
this.handleMsg("stderr", "Code-Debug Utility Command Server: Error in command socket " + err.toString());
|
||||
});
|
||||
if (!fs.existsSync(systemPath.join(os.tmpdir(), "code-debug-sockets")))
|
||||
fs.mkdirSync(systemPath.join(os.tmpdir(), "code-debug-sockets"));
|
||||
this.commandServer.listen(systemPath.join(os.tmpdir(), "code-debug-sockets", "Debug-Instance-" + Math.floor(Math.random() * 36 * 36 * 36 * 36).toString(36)));
|
||||
} catch (e) {
|
||||
this.handleMsg("stderr", "Code-Debug Utility Command Server: Failed to start " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected handleMsg(type: string, msg: string) {
|
||||
|
|
@ -78,6 +107,8 @@ export class MI2DebugSession extends DebugSession {
|
|||
this.miDebugger.detach();
|
||||
else
|
||||
this.miDebugger.stop();
|
||||
this.commandServer.close();
|
||||
this.commandServer = undefined;
|
||||
this.sendResponse(response);
|
||||
}
|
||||
|
||||
|
|
@ -88,7 +119,7 @@ export class MI2DebugSession extends DebugSession {
|
|||
};
|
||||
this.sendResponse(response);
|
||||
}, err => {
|
||||
this.sendErrorResponse(response, 11, `Could not continue: ${err}`);
|
||||
this.sendErrorResponse(response, 11, `Could not continue: ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -179,6 +210,8 @@ export class MI2DebugSession extends DebugSession {
|
|||
stackFrames: ret
|
||||
};
|
||||
this.sendResponse(response);
|
||||
}, err => {
|
||||
this.sendErrorResponse(response, 12, `Failed to get Stack Trace: ${err.toString()}`)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -219,8 +252,7 @@ export class MI2DebugSession extends DebugSession {
|
|||
stack.forEach(variable => {
|
||||
if (variable.valueStr !== undefined) {
|
||||
let expanded = expandValue(createVariable, "{" + variable.name + "=" + variable.valueStr + ")");
|
||||
if (expanded)
|
||||
{
|
||||
if (expanded) {
|
||||
if (typeof expanded[0] == "string")
|
||||
expanded = [
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue