Skip to content

Commit

Permalink
Improvements to the Disassembly View
Browse files Browse the repository at this point in the history
- Manual disassembly “file names” will now match automatic ones - preventing you from possibly having two copies of the same disassembly opened at once.
- If there are multiple functions with the same name (two static functions with the same name in two different compilation units) you can now chose between them when manually opening a disassembly view.
- Stepping mode will now reflect your currently focused editor for manually disassembled functions; if the currently focused editor is the disassembly for the current frame then instruction level stepping is used - otherwise source line level stepping is used. (If you are disassembly because it was unable to locate source or you set forced disassembly mode instruction level stepping will also be used.)
  • Loading branch information
Marus committed Jan 29, 2018
1 parent d683af0 commit 2acdaec
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 16 deletions.
17 changes: 14 additions & 3 deletions src/frontend/disassembly_content_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@ import { DisassemblyInstruction } from "../common";
export class DisassemblyContentProvider implements vscode.TextDocumentContentProvider {
provideTextDocumentContent(uri: vscode.Uri, token: vscode.CancellationToken): Thenable<string> {
return new Promise((resolve, reject) => {
let query = this.parseQuery(uri.query);
let funcname = query['function'];
let funcName: string;
let file: string;
let path = uri.path;
let pathParts = path.substring(1, path.length - 6).split('::');

vscode.debug.activeDebugSession.customRequest('disassemble', { function: funcname }).then((data) => {
if (pathParts.length === 1) {
file = null;
funcName = pathParts[0];
}
else {
file = pathParts[0];
funcName = pathParts[1];
}

vscode.debug.activeDebugSession.customRequest('disassemble', { function: funcName, file: file }).then((data) => {
let instructions: DisassemblyInstruction[] = data.instructions;

let output = '';
Expand Down
67 changes: 65 additions & 2 deletions src/frontend/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { FifoSWOSource } from "./swo/sources/fifo";
import { FileSWOSource } from "./swo/sources/file";
import { SerialSWOSource } from "./swo/sources/serial";
import { DisassemblyContentProvider } from "./disassembly_content_provider";
import { SymbolInformation, SymbolScope } from "../symbols";

interface SVDInfo {
expression: RegExp;
Expand Down Expand Up @@ -99,6 +100,7 @@ class CortexDebugExtension {
private registerProvider: RegisterTreeProvider;

private SVDDirectory: SVDInfo[] = [];
private functionSymbols: SymbolInformation[] = null;

constructor(private context: vscode.ExtensionContext) {
this.peripheralProvider = new PeripheralTreeProvider();
Expand Down Expand Up @@ -138,6 +140,7 @@ class CortexDebugExtension {
context.subscriptions.push(vscode.debug.onDidReceiveDebugSessionCustomEvent(this.receivedCustomEvent.bind(this)));
context.subscriptions.push(vscode.debug.onDidStartDebugSession(this.debugSessionStarted.bind(this)));
context.subscriptions.push(vscode.debug.onDidTerminateDebugSession(this.debugSessionTerminated.bind(this)));
context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(this.activeEditorChanged.bind(this)));

context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('jlink-gdb', new DeprecatedDebugConfigurationProvider(context, 'jlink')));
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('openocd-gdb', new DeprecatedDebugConfigurationProvider(context, 'openocd')));
Expand All @@ -151,23 +154,81 @@ class CortexDebugExtension {
return entry ? entry.path : null;
}

activeEditorChanged(editor: vscode.TextEditor) {
if (editor !== undefined && vscode.debug.activeDebugSession) {
let uri = editor.document.uri;
if (uri.scheme == 'file') {
vscode.debug.activeDebugSession.customRequest('set-active-editor', { path: uri.path });
}
else {
vscode.debug.activeDebugSession.customRequest('set-active-editor', { path: `${uri.scheme}://${uri.authority}${uri.path}` });
}
}
}

async showDisassembly() {
if (!vscode.debug.activeDebugSession) {
vscode.window.showErrorMessage('No debugging session available');
return;
}

if (!this.functionSymbols) {
try {
let resp = await vscode.debug.activeDebugSession.customRequest('load-function-symbols');
this.functionSymbols = resp.functionSymbols;
}
catch (e) {
vscode.window.showErrorMessage('Unable to load symbol table. Disassembly view unavailable.');
}
}

try {
let funcname: string = await vscode.window.showInputBox({
placeHolder: 'main',
ignoreFocusOut: true,
prompt: 'Function Name to Disassemble'
});

vscode.window.showTextDocument(vscode.Uri.parse(`disassembly:///${funcname}.cdasm?function=${funcname}`));
let functions = this.functionSymbols.filter(s => s.name == funcname);

let url: string;

if (functions.length === 0) {
vscode.window.showErrorMessage(`No function with name ${funcname} found.`);
}
else if (functions.length === 1) {
if (functions[0].scope == SymbolScope.Global) {
url = `disassembly:///${functions[0].name}.cdasm`;
}
else {
url = `disassembly:///${functions[0].file}::${functions[0].name}.cdasm`;
}
}
else {
let selected = await vscode.window.showQuickPick(functions.map(f => {
return {
label: f.name,
name: f.name,
file: f.file,
scope: f.scope,
description: f.scope == SymbolScope.Global ? 'Global Scope' : `Static in ${f.file}`
};
}), {
ignoreFocusOut: true
});

if (selected.scope == SymbolScope.Global) {
url = `disassembly:///${selected.name}.cdasm`;
}
else {
url = `disassembly:///${selected.file}::${selected.name}.cdasm`;
}
}

vscode.window.showTextDocument(vscode.Uri.parse(url));
}
catch (e) {
vscode.window.showErrorMessage('Unable to get function name');
vscode.window.showErrorMessage('Unable to show disassembly.');
}
}

Expand Down Expand Up @@ -289,6 +350,8 @@ class CortexDebugExtension {
this.swo = null;
}

this.functionSymbols = null;

session.customRequest('get-arguments').then(args => {
let svdfile = args.svdFile;
if (!svdfile) {
Expand Down
81 changes: 70 additions & 11 deletions src/gdb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ export class GDBDebugSession extends DebugSession {
protected threadID: number = 1;
protected commandServer: net.Server;
protected forceDisassembly: boolean = false;
protected activeEditorPath: string = null;

private stopped: boolean = false;
private stoppedReason: string = '';

protected breakpointMap: Map<string, Breakpoint[]> = new Map();
protected fileExistsCache: Map<string, boolean> = new Map();
Expand Down Expand Up @@ -151,6 +155,7 @@ export class GDBDebugSession extends DebugSession {
this.started = false;
this.crashed = false;
this.debugReady = false;
this.stopped = false;

portastic.find({ min: 50000, max: 52000, retrieve: this.serverController.portsNeeded.length }).then(ports => {
this.ports = {};
Expand Down Expand Up @@ -256,12 +261,25 @@ export class GDBDebugSession extends DebugSession {
case 'set-force-disassembly':
response.body = { success: true };
this.forceDisassembly = args.force;
if (this.stopped) {
this.activeEditorPath = null;
this.sendEvent(new ContinuedEvent(this.threadID, true));
this.sendEvent(new StoppedEvent(this.stoppedReason, this.threadID));
}
this.sendResponse(response);
break;
case 'load-function-symbols':
response.body = { functionSymbols: this.symbolTable.getFunctionSymbols() };
this.sendResponse(response);
break;
case 'set-active-editor':
this.activeEditorPath = args.path;
response.body = {};
if (this.stopped) {
this.sendEvent(new StoppedEvent(this.stoppedReason, this.threadID));
}
this.sendResponse(response);
break;
case 'get-arguments':
response.body = this.args;
this.sendResponse(response);
Expand Down Expand Up @@ -303,7 +321,7 @@ export class GDBDebugSession extends DebugSession {
protected async disassembleRequest(response: DebugProtocol.Response, args: any): Promise<void> {
if (args.function) {
try {
let funcInfo: SymbolInformation = await this.getDisassemblyForFunction(args.function);
let funcInfo: SymbolInformation = await this.getDisassemblyForFunction(args.function, args.file);
response.body = {
instructions: funcInfo.instructions,
name: funcInfo.name,
Expand Down Expand Up @@ -526,22 +544,28 @@ export class GDBDebugSession extends DebugSession {
}

protected handleRunning(info: MINode) {
this.stopped = false;
this.sendEvent(new ContinuedEvent(this.threadID, true));
this.sendEvent(new CustomContinuedEvent(this.threadID, true));
}

protected handleBreakpoint(info: MINode) {

this.stopped = true;
this.stoppedReason = 'breakpoint';
this.sendEvent(new StoppedEvent("breakpoint", this.threadID));
this.sendEvent(new CustomStoppedEvent("breakpoint", this.threadID));
}

protected handleBreak(info: MINode) {
this.stopped = true;
this.stoppedReason = 'step';
this.sendEvent(new StoppedEvent("step", this.threadID));
this.sendEvent(new CustomStoppedEvent("step", this.threadID));
}

protected handlePause(info: MINode) {
this.stopped = true;
this.stoppedReason = 'user request';
this.sendEvent(new StoppedEvent("user request", this.threadID));
this.sendEvent(new CustomStoppedEvent("user request", this.threadID));
}
Expand All @@ -550,6 +574,8 @@ export class GDBDebugSession extends DebugSession {
if (!this.started)
this.crashed = true;
if (!this.quit) {
this.stopped = true;
this.stoppedReason = 'exception';
this.sendEvent(new StoppedEvent("exception", this.threadID));
this.sendEvent(new CustomStoppedEvent("exception", this.threadID));
}
Expand Down Expand Up @@ -626,10 +652,8 @@ export class GDBDebugSession extends DebugSession {

if (sourcepath.startsWith('disassembly:/')) {
let sidx = 13;
if (args.source.path.startsWith('disassembly:///')) { sidx = 15; }

let eidx = sourcepath.indexOf('?');
let path = sourcepath.substring(sidx, eidx - 6); // Account for protocol and extension
if (sourcepath.startsWith('disassembly:///')) { sidx = 15; }
let path = sourcepath.substring(sidx, sourcepath.length - 6); // Account for protocol and extension
let parts = path.split('::');
let func: string;
let file: string;
Expand Down Expand Up @@ -701,8 +725,18 @@ export class GDBDebugSession extends DebugSession {
for (let element of stack) {
let file = element.file;
let disassemble = this.forceDisassembly || !file;

if (!disassemble) { disassemble = !(await this.checkFileExists(file)); }
if (!disassemble && this.activeEditorPath && this.activeEditorPath.startsWith('disassembly:///')) {
let symbolInfo = this.symbolTable.getFunctionByName(element.function, element.fileName);
let url: string;
if (symbolInfo.scope !== SymbolScope.Global) {
url = `disassembly:///${symbolInfo.file}::${symbolInfo.name}.cdasm`;
}
else {
url = `disassembly:///${symbolInfo.name}.cdasm`;
}
if (url == this.activeEditorPath) { disassemble = true; }
}

try {
if (disassemble) {
Expand All @@ -714,13 +748,14 @@ export class GDBDebugSession extends DebugSession {

if (line !== -1) {
let fname: string;
if (element.fileName) {
fname = `${element.fileName}::${element.function}`;
let url: string;
if (symbolInfo.scope !== SymbolScope.Global) {
url = `disassembly:///${symbolInfo.file}::${symbolInfo.name}.cdasm`;
}
else {
fname = element.function;
url = `disassembly:///${symbolInfo.name}.cdasm`;
}
let url = `disassembly:///${fname}.cdasm?function=${element.function}&file=${element.fileName}`;

ret.push(new StackFrame(element.level, `${element.function}@${element.address}`, new Source(fname, url), line, 0));
}
else {
Expand Down Expand Up @@ -1099,6 +1134,18 @@ export class GDBDebugSession extends DebugSession {
if (!assemblyMode) {
let frame = await this.miDebugger.getFrame(this.threadID, 0);
assemblyMode = !(await this.checkFileExists(frame.file));

if (this.activeEditorPath && this.activeEditorPath.startsWith('disassembly:///')) {
let symbolInfo = this.symbolTable.getFunctionByName(frame.function, frame.fileName);
let url: string;
if (symbolInfo.scope !== SymbolScope.Global) {
url = `disassembly:///${symbolInfo.file}::${symbolInfo.name}.cdasm`;
}
else {
url = `disassembly:///${symbolInfo.name}.cdasm`;
}
if (url == this.activeEditorPath) { assemblyMode = true; }
}
}

let done = await this.miDebugger.step(assemblyMode);
Expand All @@ -1123,6 +1170,18 @@ export class GDBDebugSession extends DebugSession {
if (!assemblyMode) {
let frame = await this.miDebugger.getFrame(this.threadID, 0);
assemblyMode = !(await this.checkFileExists(frame.file));

if (this.activeEditorPath && this.activeEditorPath.startsWith('disassembly:///')) {
let symbolInfo = this.symbolTable.getFunctionByName(frame.function, frame.fileName);
let url: string;
if (symbolInfo.scope !== SymbolScope.Global) {
url = `disassembly:///${symbolInfo.file}::${symbolInfo.name}.cdasm`;
}
else {
url = `disassembly:///${symbolInfo.name}.cdasm`;
}
if (url == this.activeEditorPath) { assemblyMode = true; }
}
}

let done = await this.miDebugger.next(assemblyMode);
Expand Down

0 comments on commit 2acdaec

Please sign in to comment.