Skip to content

Commit

Permalink
Added examining memory locations (fix #64)
Browse files Browse the repository at this point in the history
also added a way to run mi commands over unix domain sockets so other applications can communicate with code-debug
  • Loading branch information
WebFreak001 committed Jul 23, 2016
1 parent e787333 commit 87ff8b8
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 7 deletions.
19 changes: 15 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
],
Expand All @@ -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",
Expand Down Expand Up @@ -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": []
}
}
Expand Down Expand Up @@ -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": []
}
}
Expand All @@ -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",
Expand Down
1 change: 1 addition & 0 deletions src/backend/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
}
8 changes: 8 additions & 0 deletions src/backend/mi2/mi2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
125 changes: 125 additions & 0 deletions src/frontend/extension.ts
Original file line number Diff line number Diff line change
@@ -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();
});
});
}
}
38 changes: 35 additions & 3 deletions src/mibase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
}

Expand All @@ -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}`);
});
}

Expand Down Expand Up @@ -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()}`)
});
}

Expand Down Expand Up @@ -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 = [
{
Expand Down

0 comments on commit 87ff8b8

Please sign in to comment.