-
Notifications
You must be signed in to change notification settings - Fork 30.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Disassembly view #125737
Disassembly view #125737
Changes from all commits
45bdf6b
aada2f4
a83ef3a
0e7e274
f4015e1
01dd48e
fc3e9cd
b55f201
16c268e
8273972
17ffdc7
a9cf999
d2dc742
4b681e1
ec80e33
707ae1a
5914a40
451797c
cdc3714
fb797f6
a6865b4
b8e4d3e
d160870
c2119a4
73fa288
a2f7ea5
fc659a8
aa5940f
cc56194
e81f4cc
cc1d75a
4114792
b197a34
6f38fee
a94415c
fa70233
636b70d
3f8801c
a5d10cb
6be31ee
6cc269e
600cdae
7d4ba0c
aaaae0c
9dd774e
420140f
526e177
93c8ad6
a0e2977
7fb6a2e
c492064
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,8 +6,8 @@ | |
import * as resources from 'vs/base/common/resources'; | ||
import * as dom from 'vs/base/browser/dom'; | ||
import { Action, IAction } from 'vs/base/common/actions'; | ||
import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINTS_FOCUSED, State, DEBUG_SCHEME, IFunctionBreakpoint, IExceptionBreakpoint, IEnablement, IDebugModel, IDataBreakpoint, BREAKPOINTS_VIEW_ID, CONTEXT_BREAKPOINT_ITEM_TYPE, CONTEXT_BREAKPOINT_SUPPORTS_CONDITION, CONTEXT_BREAKPOINTS_EXIST, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_IN_DEBUG_MODE, IBaseBreakpoint, IBreakpointEditorContribution, BREAKPOINT_EDITOR_CONTRIBUTION_ID, CONTEXT_BREAKPOINT_INPUT_FOCUSED } from 'vs/workbench/contrib/debug/common/debug'; | ||
import { ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, DataBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel'; | ||
import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINTS_FOCUSED, State, DEBUG_SCHEME, IFunctionBreakpoint, IExceptionBreakpoint, IEnablement, IDebugModel, IDataBreakpoint, BREAKPOINTS_VIEW_ID, CONTEXT_BREAKPOINT_ITEM_TYPE, CONTEXT_BREAKPOINT_SUPPORTS_CONDITION, CONTEXT_BREAKPOINTS_EXIST, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_IN_DEBUG_MODE, IBaseBreakpoint, IBreakpointEditorContribution, BREAKPOINT_EDITOR_CONTRIBUTION_ID, CONTEXT_BREAKPOINT_INPUT_FOCUSED, IInstructionBreakpoint } from 'vs/workbench/contrib/debug/common/debug'; | ||
import { ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, DataBreakpoint, InstructionBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel'; | ||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; | ||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; | ||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; | ||
|
@@ -43,6 +43,8 @@ import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; | |
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; | ||
import { Codicon } from 'vs/base/common/codicons'; | ||
import { equals } from 'vs/base/common/arrays'; | ||
import { DisassemblyViewInput } from 'vs/workbench/contrib/debug/common/disassemblyViewInput'; | ||
import { DisassemblyView } from 'vs/workbench/contrib/debug/browser/disassemblyView'; | ||
|
||
const $ = dom.$; | ||
|
||
|
@@ -57,10 +59,10 @@ function createCheckbox(): HTMLInputElement { | |
|
||
const MAX_VISIBLE_BREAKPOINTS = 9; | ||
export function getExpandedBodySize(model: IDebugModel, countLimit: number): number { | ||
const length = model.getBreakpoints().length + model.getExceptionBreakpoints().length + model.getFunctionBreakpoints().length + model.getDataBreakpoints().length; | ||
const length = model.getBreakpoints().length + model.getExceptionBreakpoints().length + model.getFunctionBreakpoints().length + model.getDataBreakpoints().length + model.getInstructionBreakpoints().length; | ||
return Math.min(countLimit, length) * 22; | ||
} | ||
type BreakpointItem = IBreakpoint | IFunctionBreakpoint | IDataBreakpoint | IExceptionBreakpoint; | ||
type BreakpointItem = IBreakpoint | IFunctionBreakpoint | IDataBreakpoint | IExceptionBreakpoint | IInstructionBreakpoint; | ||
|
||
interface InputBoxData { | ||
breakpoint: IFunctionBreakpoint | IExceptionBreakpoint; | ||
|
@@ -120,7 +122,8 @@ export class BreakpointsView extends ViewPane { | |
new ExceptionBreakpointInputRenderer(this, this.debugService, this.contextViewService, this.themeService), | ||
this.instantiationService.createInstance(FunctionBreakpointsRenderer, this.menu, this.breakpointSupportsCondition, this.breakpointItemType), | ||
this.instantiationService.createInstance(DataBreakpointsRenderer), | ||
new FunctionBreakpointInputRenderer(this, this.debugService, this.contextViewService, this.themeService, this.labelService) | ||
new FunctionBreakpointInputRenderer(this, this.debugService, this.contextViewService, this.themeService, this.labelService), | ||
this.instantiationService.createInstance(InstructionBreakpointsRenderer), | ||
], { | ||
identityProvider: { getId: (element: IEnablement) => element.getId() }, | ||
multipleSelectionSupport: false, | ||
|
@@ -142,6 +145,8 @@ export class BreakpointsView extends ViewPane { | |
await this.debugService.removeFunctionBreakpoints(element.getId()); | ||
} else if (element instanceof DataBreakpoint) { | ||
await this.debugService.removeDataBreakpoints(element.getId()); | ||
} else if (element instanceof InstructionBreakpoint) { | ||
await this.debugService.removeInstructionBreakpoints(element.instructionReference); | ||
} | ||
}); | ||
|
||
|
@@ -157,6 +162,10 @@ export class BreakpointsView extends ViewPane { | |
if (e.element instanceof Breakpoint) { | ||
openBreakpointSource(e.element, e.sideBySide, e.editorOptions.preserveFocus || false, e.editorOptions.pinned || !e.editorOptions.preserveFocus, this.debugService, this.editorService); | ||
} | ||
if (e.element instanceof InstructionBreakpoint) { | ||
const disassemblyView = await this.editorService.openEditor(DisassemblyViewInput.instance); | ||
(disassemblyView as DisassemblyView).goToAddress(e.element.instructionReference); | ||
} | ||
if (e.browserEvent instanceof MouseEvent && e.browserEvent.detail === 2 && e.element instanceof FunctionBreakpoint && e.element !== this.inputBoxData?.breakpoint) { | ||
// double click | ||
this.renderInputBox({ breakpoint: e.element, type: 'name' }); | ||
|
@@ -214,7 +223,8 @@ export class BreakpointsView extends ViewPane { | |
private onListContextMenu(e: IListContextMenuEvent<IEnablement>): void { | ||
const element = e.element; | ||
const type = element instanceof Breakpoint ? 'breakpoint' : element instanceof ExceptionBreakpoint ? 'exceptionBreakpoint' : | ||
element instanceof FunctionBreakpoint ? 'functionBreakpoint' : element instanceof DataBreakpoint ? 'dataBreakpoint' : undefined; | ||
element instanceof FunctionBreakpoint ? 'functionBreakpoint' : element instanceof DataBreakpoint ? 'dataBreakpoint' : | ||
element instanceof InstructionBreakpoint ? 'instructionBreakpoint' : undefined; | ||
this.breakpointItemType.set(type); | ||
const session = this.debugService.getViewModel().focusedSession; | ||
const conditionSupported = element instanceof ExceptionBreakpoint ? element.supportsCondition : (!session || !!session.capabilities.supportsConditionalBreakpoints); | ||
|
@@ -288,7 +298,7 @@ export class BreakpointsView extends ViewPane { | |
|
||
private get elements(): BreakpointItem[] { | ||
const model = this.debugService.getModel(); | ||
const elements = (<ReadonlyArray<IEnablement>>model.getExceptionBreakpoints()).concat(model.getFunctionBreakpoints()).concat(model.getDataBreakpoints()).concat(model.getBreakpoints()); | ||
const elements = (<ReadonlyArray<IEnablement>>model.getExceptionBreakpoints()).concat(model.getFunctionBreakpoints()).concat(model.getDataBreakpoints()).concat(model.getBreakpoints()).concat(model.getInstructionBreakpoints()); | ||
|
||
return elements as BreakpointItem[]; | ||
} | ||
|
@@ -326,6 +336,9 @@ class BreakpointsDelegate implements IListVirtualDelegate<BreakpointItem> { | |
if (element instanceof DataBreakpoint) { | ||
return DataBreakpointsRenderer.ID; | ||
} | ||
if (element instanceof InstructionBreakpoint) { | ||
return InstructionBreakpointsRenderer.ID; | ||
} | ||
|
||
return ''; | ||
} | ||
|
@@ -362,6 +375,10 @@ interface IDataBreakpointTemplateData extends IBaseBreakpointWithIconTemplateDat | |
accessType: HTMLElement; | ||
} | ||
|
||
interface IInstructionBreakpointTemplateData extends IBaseBreakpointWithIconTemplateData { | ||
address: HTMLElement; | ||
} | ||
|
||
interface IFunctionBreakpointInputTemplateData { | ||
inputBox: InputBox; | ||
checkbox: HTMLInputElement; | ||
|
@@ -673,6 +690,71 @@ class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IDataBrea | |
} | ||
} | ||
|
||
class InstructionBreakpointsRenderer implements IListRenderer<IInstructionBreakpoint, IInstructionBreakpointTemplateData> { | ||
|
||
constructor( | ||
@IDebugService private readonly debugService: IDebugService, | ||
@ILabelService private readonly labelService: ILabelService | ||
) { | ||
// noop | ||
} | ||
|
||
static readonly ID = 'instructionBreakpoints'; | ||
|
||
get templateId() { | ||
return InstructionBreakpointsRenderer.ID; | ||
} | ||
|
||
renderTemplate(container: HTMLElement): IInstructionBreakpointTemplateData { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @isidorn we need a new icon for instruction breakpoints. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @iidorn -> @isidorn ;-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jogo- thanks for pointing that out |
||
const data: IInstructionBreakpointTemplateData = Object.create(null); | ||
data.breakpoint = dom.append(container, $('.breakpoint')); | ||
|
||
data.icon = $('.icon'); | ||
data.checkbox = createCheckbox(); | ||
data.toDispose = []; | ||
data.elementDisposable = []; | ||
data.toDispose.push(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => { | ||
this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context); | ||
})); | ||
|
||
dom.append(data.breakpoint, data.icon); | ||
dom.append(data.breakpoint, data.checkbox); | ||
|
||
data.name = dom.append(data.breakpoint, $('span.name')); | ||
|
||
data.address = dom.append(data.breakpoint, $('span.file-path')); | ||
data.actionBar = new ActionBar(data.breakpoint); | ||
data.toDispose.push(data.actionBar); | ||
|
||
return data; | ||
} | ||
|
||
renderElement(breakpoint: IInstructionBreakpoint, index: number, data: IInstructionBreakpointTemplateData): void { | ||
data.context = breakpoint; | ||
data.breakpoint.classList.toggle('disabled', !this.debugService.getModel().areBreakpointsActivated()); | ||
|
||
data.name.textContent = breakpoint.instructionReference; | ||
data.checkbox.checked = breakpoint.enabled; | ||
|
||
const { message, icon } = getBreakpointMessageAndIcon(this.debugService.state, this.debugService.getModel().areBreakpointsActivated(), breakpoint, this.labelService); | ||
data.icon.className = ThemeIcon.asClassName(icon); | ||
data.breakpoint.title = breakpoint.message || message || ''; | ||
|
||
const debugActive = this.debugService.state === State.Running || this.debugService.state === State.Stopped; | ||
if (debugActive && !breakpoint.verified) { | ||
data.breakpoint.classList.add('disabled'); | ||
} | ||
} | ||
|
||
disposeElement(_element: IInstructionBreakpoint, _index: number, templateData: IInstructionBreakpointTemplateData): void { | ||
dispose(templateData.elementDisposable); | ||
} | ||
|
||
disposeTemplate(templateData: IInstructionBreakpointTemplateData): void { | ||
dispose(templateData.toDispose); | ||
} | ||
} | ||
|
||
class FunctionBreakpointInputRenderer implements IListRenderer<IFunctionBreakpoint, IFunctionBreakpointInputTemplateData> { | ||
|
||
constructor( | ||
|
@@ -927,7 +1009,7 @@ export function openBreakpointSource(breakpoint: IBreakpoint, sideBySide: boolea | |
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP); | ||
} | ||
|
||
export function getBreakpointMessageAndIcon(state: State, breakpointsActivated: boolean, breakpoint: IBreakpoint | IFunctionBreakpoint | IDataBreakpoint, labelService?: ILabelService): { message?: string, icon: ThemeIcon } { | ||
export function getBreakpointMessageAndIcon(state: State, breakpointsActivated: boolean, breakpoint: BreakpointItem, labelService?: ILabelService): { message?: string, icon: ThemeIcon } { | ||
const debugActive = state === State.Running || state === State.Stopped; | ||
|
||
const breakpointIcon = breakpoint instanceof DataBreakpoint ? icons.dataBreakpoint : breakpoint instanceof FunctionBreakpoint ? icons.functionBreakpoint : breakpoint.logMessage ? icons.logBreakpoint : icons.breakpoint; | ||
|
@@ -985,6 +1067,32 @@ export function getBreakpointMessageAndIcon(state: State, breakpointsActivated: | |
}; | ||
} | ||
|
||
if (breakpoint instanceof InstructionBreakpoint) { | ||
if (!breakpoint.supported) { | ||
return { | ||
icon: breakpointIcon.unverified, | ||
message: localize('instructionBreakpointUnsupported', "Instruction breakpoints not supported by this debug type"), | ||
}; | ||
} | ||
const messages: string[] = []; | ||
if (breakpoint.message) { | ||
messages.push(breakpoint.message); | ||
} else if (breakpoint.instructionReference) { | ||
messages.push(localize('instructionBreakpointAtAddress', "Instruction breakpoint at address {0}", breakpoint.instructionReference)); | ||
} else { | ||
messages.push(localize('instructionBreakpoint', "Instruction breakpoint")); | ||
} | ||
|
||
if (breakpoint.hitCondition) { | ||
messages.push(localize('hitCount', "Hit Count: {0}", breakpoint.hitCondition)); | ||
} | ||
|
||
return { | ||
icon: breakpointIcon.regular, | ||
message: appendMessage(messages.join('\n')) | ||
}; | ||
} | ||
|
||
if (breakpoint.logMessage || breakpoint.condition || breakpoint.hitCondition) { | ||
const messages: string[] = []; | ||
|
||
|
@@ -1099,6 +1207,8 @@ registerAction2(class extends Action2 { | |
await debugService.removeFunctionBreakpoints(breakpoint.getId()); | ||
} else if (breakpoint instanceof DataBreakpoint) { | ||
await debugService.removeDataBreakpoints(breakpoint.getId()); | ||
} else if (breakpoint instanceof InstructionBreakpoint) { | ||
await debugService.removeInstructionBreakpoints(breakpoint.instructionReference); | ||
} | ||
} | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also have the
IInstructionBreakpoint
as the return type.Also make sure the conversion is properly done please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@isidorn supporting instruction breakpoints in the debug extension API requires more work (which is not part of this PR)
Please create a feature request "Support instruction breakpoints in debug API" for this.