Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ reason "breakpoint"; step again to continue.
Breakpoints are kept in sync with the agent's breakpoint table: adding,
editing and removing breakpoints in VS Code sends `Breakpoints.add`, `change`
and `remove`. Breakpoints apply to all contexts the agent debugs, except
instruction breakpoints, see below.
explicitly scoped function breakpoints and instruction breakpoints, see below.

| VS Code | TCF breakpoint properties |
|---------------------------------|----------------------------------------------------|
Expand All @@ -190,6 +190,25 @@ Function breakpoints stop at the first instruction of the function. The
reference TCF agent also supports a non-standard `SkipPrologue` property which
is not used, to stay within the TCF specification.

Use **Simics Target Debug: Add Function Breakpoint in Context...** from the
Command Palette, the Breakpoints toolbar, or a stack frame's context menu to
choose a core before entering the symbol. The selected call-stack context is
offered first; **All contexts** keeps the breakpoint global. Scoped entries
appear as `start_kernel @ armv8.cluster[0].core[0]` in the Breakpoints panel.
The ` @ ` suffix is reserved for the exact TCF context ID and is saved with
the breakpoint; selecting another frame does not change its scope. The same
syntax can be entered or edited using the built-in function-breakpoint `+`.
Scoped function breakpoints require the agent's `ContextIds` support and are
never silently planted globally when it is unavailable. Their scope applies
to that context (and, for a process context, its threads), not other cores.

In **Symbol Files**, right-click a configured symbol file with a context and
select **Add Function Breakpoint...** to enter a symbol directly. The breakpoint
uses the file's context rather than the selected call-stack core. Context names
are resolved to exact TCF IDs; unavailable or ambiguous contexts produce an error
instead of creating a global breakpoint. Files without a context do not offer
this action.

An address only has a meaning in one address space, so an instruction
breakpoint is limited to the process of the context shown in the Disassembly
view (its `ProcessID`). `ContextIds` lists the process and all its threads:
Expand Down
95 changes: 65 additions & 30 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@
],
"contributes": {
"commands": [
{
"command": "simics-target-debug.addSymbolFileBreakpoint",
"title": "Add Function Breakpoint...",
"category": "Simics Target Debug",
"icon": "$(debug-breakpoint-function)"
},
{
"command": "simics-target-debug.addFunctionBreakpointInContext",
"title": "Add Function Breakpoint in Context...",
"category": "Simics Target Debug",
"icon": "$(debug-breakpoint-function)"
},
{
"command": "simics-target-debug.addPathMapRule",
"title": "Add Path Map Rule...",
Expand Down Expand Up @@ -212,19 +224,19 @@
"id": "simics-target-debug.pathMap",
"name": "Path Maps",
"icon": "$(replace-all)",
"when": "debugType == simics-target-debug"
"when": "debugType == 'simics-target-debug'"
},
{
"id": "simics-target-debug.symbolFiles",
"name": "Symbol Files",
"icon": "$(file-code)",
"when": "debugType == simics-target-debug"
"when": "debugType == 'simics-target-debug'"
},
{
"id": "simics-target-debug.consoles",
"name": "Consoles",
"icon": "$(terminal)",
"when": "debugType == simics-target-debug || simics-target-debug.hasConsoles"
"when": "debugType == 'simics-target-debug' || simics-target-debug.hasConsoles"
}
]
},
Expand All @@ -236,21 +248,29 @@
],
"menus": {
"commandPalette": [
{
"command": "simics-target-debug.addSymbolFileBreakpoint",
"when": "false"
},
{
"command": "simics-target-debug.addFunctionBreakpointInContext",
"when": "debugType == 'simics-target-debug'"
},
Comment thread
MagnusIntel marked this conversation as resolved.
Resolved
{
"command": "simics-target-debug.saveSymbolFiles",
"when": "debugType == simics-target-debug"
"when": "debugType == 'simics-target-debug'"
},
{
"command": "simics-target-debug.addPathMapRule",
"when": "debugType == simics-target-debug"
"when": "debugType == 'simics-target-debug'"
},
{
"command": "simics-target-debug.savePathMap",
"when": "debugType == simics-target-debug"
"when": "debugType == 'simics-target-debug'"
},
{
"command": "simics-target-debug.refreshPathMap",
"when": "debugType == simics-target-debug"
"when": "debugType == 'simics-target-debug'"
},
{
"command": "simics-target-debug.editPathMapRule",
Expand All @@ -270,11 +290,11 @@
},
{
"command": "simics-target-debug.locateSourceFile",
"when": "debugType == simics-target-debug"
"when": "debugType == 'simics-target-debug'"
},
{
"command": "simics-target-debug.openLaunchJson",
"when": "activeCustomEditorId == simics-target-debug.launchSettings"
"when": "activeCustomEditorId == 'simics-target-debug.launchSettings'"
},
{
"command": "simics-target-debug.copyFrameAddress",
Expand Down Expand Up @@ -336,12 +356,12 @@
"editor/title": [
{
"command": "simics-target-debug.openLaunchSettings",
"when": "resourcePath =~ /[\\\\/]\\.vscode[\\\\/]launch\\.json$/ && activeCustomEditorId != simics-target-debug.launchSettings",
"when": "resourcePath =~ /[\\\\/]\\.vscode[\\\\/]launch\\.json$/ && activeCustomEditorId != 'simics-target-debug.launchSettings'",
"group": "navigation"
},
{
"command": "simics-target-debug.openLaunchJson",
"when": "activeCustomEditorId == simics-target-debug.launchSettings",
"when": "activeCustomEditorId == 'simics-target-debug.launchSettings'",
"group": "navigation"
},
{
Expand Down Expand Up @@ -383,101 +403,111 @@
}
],
"view/title": [
{
"command": "simics-target-debug.addFunctionBreakpointInContext",
"when": "view == 'workbench.debug.viewlet.state' && debugType == 'simics-target-debug'",
"group": "navigation@1"
},
Comment thread
MagnusIntel marked this conversation as resolved.
Resolved
{
"command": "simics-target-debug.openConsole",
"when": "view == simics-target-debug.consoles && debugType == simics-target-debug && !simics-target-debug.hasConsoles",
"when": "view == 'simics-target-debug.consoles' && debugType == 'simics-target-debug' && !simics-target-debug.hasConsoles",
"group": "navigation@1"
},
{
"command": "simics-target-debug.saveSymbolFiles",
"when": "view == simics-target-debug.symbolFiles",
"when": "view == 'simics-target-debug.symbolFiles'",
"group": "navigation@2"
},
{
"command": "simics-target-debug.addPathMapRule",
"when": "view == simics-target-debug.pathMap",
"when": "view == 'simics-target-debug.pathMap'",
"group": "navigation@1"
},
{
"command": "simics-target-debug.savePathMap",
"when": "view == simics-target-debug.pathMap",
"when": "view == 'simics-target-debug.pathMap'",
"group": "navigation@2"
},
{
"command": "simics-target-debug.refreshPathMap",
"when": "view == simics-target-debug.pathMap",
"when": "view == 'simics-target-debug.pathMap'",
"group": "navigation@3"
},
{
"command": "simics-target-debug.addSymbolFile",
"when": "view == simics-target-debug.symbolFiles",
"when": "view == 'simics-target-debug.symbolFiles'",
"group": "navigation@1"
},
{
"command": "simics-target-debug.reloadSymbolFiles",
"when": "view == simics-target-debug.symbolFiles",
"when": "view == 'simics-target-debug.symbolFiles'",
"group": "navigation@3"
}
],
"view/item/context": [
{
"command": "simics-target-debug.addSymbolFileBreakpoint",
"when": "view == 'simics-target-debug.symbolFiles' && viewItem =~ /\\bsymbolFile\\b/ && viewItem =~ /\\bscoped\\b/",
"group": "breakpoints@1"
},
Comment thread
MagnusIntel marked this conversation as resolved.
Resolved
{
"command": "simics-target-debug.connectConsole",
"when": "view == simics-target-debug.consoles && viewItem =~ /\\bconnect\\b/",
"when": "view == 'simics-target-debug.consoles' && viewItem =~ /\\bconnect\\b/",
"group": "inline@0"
},
{
"command": "simics-target-debug.reconnectConsole",
"when": "view == simics-target-debug.consoles && viewItem =~ /\\breconnect\\b/",
"when": "view == 'simics-target-debug.consoles' && viewItem =~ /\\breconnect\\b/",
"group": "inline@0"
},
{
"command": "simics-target-debug.consoleKeysToVsCode",
"when": "view == simics-target-debug.consoles && viewItem =~ /\\bkeysToSimics\\b/",
"when": "view == 'simics-target-debug.consoles' && viewItem =~ /\\bkeysToSimics\\b/",
"group": "inline@0"
},
{
"command": "simics-target-debug.consoleKeysToSimics",
"when": "view == simics-target-debug.consoles && viewItem =~ /\\bkeysToVsCode\\b/",
"when": "view == 'simics-target-debug.consoles' && viewItem =~ /\\bkeysToVsCode\\b/",
"group": "inline@0"
},
{
"command": "simics-target-debug.clearConsoleHistory",
"when": "view == simics-target-debug.consoles && viewItem =~ /^simicsCli/",
"when": "view == 'simics-target-debug.consoles' && viewItem =~ /^simicsCli/",
"group": "inline@1"
},
{
"command": "simics-target-debug.editPathMapRule",
"when": "view == simics-target-debug.pathMap && viewItem == pathMapRule",
"when": "view == 'simics-target-debug.pathMap' && viewItem == 'pathMapRule'",
"group": "inline@1"
},
{
"command": "simics-target-debug.removePathMapRule",
"when": "view == simics-target-debug.pathMap && viewItem == pathMapRule",
"when": "view == 'simics-target-debug.pathMap' && viewItem == 'pathMapRule'",
"group": "inline@2"
},
{
"command": "simics-target-debug.movePathMapRuleUp",
"when": "view == simics-target-debug.pathMap && viewItem == pathMapRule",
"when": "view == 'simics-target-debug.pathMap' && viewItem == 'pathMapRule'",
"group": "order@1"
},
{
"command": "simics-target-debug.movePathMapRuleDown",
"when": "view == simics-target-debug.pathMap && viewItem == pathMapRule",
"when": "view == 'simics-target-debug.pathMap' && viewItem == 'pathMapRule'",
"group": "order@2"
},
{
"command": "simics-target-debug.editSymbolFile",
"when": "view == simics-target-debug.symbolFiles && viewItem == symbolFile",
"when": "view == 'simics-target-debug.symbolFiles' && viewItem =~ /\\bsymbolFile\\b/",
"group": "inline@1"
},
{
"command": "simics-target-debug.reloadSymbolFile",
"when": "view == simics-target-debug.symbolFiles && viewItem == symbolFile",
"when": "view == 'simics-target-debug.symbolFiles' && viewItem =~ /\\bsymbolFile\\b/",
"group": "inline@2"
},
{
"command": "simics-target-debug.removeSymbolFile",
"when": "view == simics-target-debug.symbolFiles && viewItem == symbolFile",
"when": "view == 'simics-target-debug.symbolFiles' && viewItem =~ /\\bsymbolFile\\b/",
"group": "inline@3"
}
],
Expand All @@ -488,6 +518,11 @@
}
],
"debug/callstack/context": [
{
"command": "simics-target-debug.addFunctionBreakpointInContext",
"when": "debugType == 'simics-target-debug' && callStackItemType == 'stackFrame'",
"group": "3_modification"
},
{
"command": "simics-target-debug.copyFrameAddress",
"when": "debugType == 'simics-target-debug' && callStackItemType == 'stackFrame'",
Expand Down
15 changes: 14 additions & 1 deletion src/breakpointManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "./tcf/services/breakpoints";
import { toBigInt } from "./tcf/json";
import { instructionReference, parseInstructionReference } from "./disassembly";
import { parseFunctionBreakpointName } from "./functionBreakpoint";
import type { TargetPath } from "./pathMapper";

type BreakpointKind = "source" | "function" | "data" | "instruction";
Expand Down Expand Up @@ -218,10 +219,22 @@ export class BreakpointManager {
const caps = await this.capabilities();
const specs = requested.map((r): BreakpointSpec => {
const spec: BreakpointSpec = { kind: "function", key: r.name };
const { location, contextId, hasContextDelimiter } = parseFunctionBreakpointName(r.name);
if (caps.Location === false) {
return { ...spec, error: "The TCF agent does not support breakpoints on expressions" };
}
return this.withCommonProps(spec, { Location: r.name }, r, caps);
if (hasContextDelimiter && (!contextId || !location)) {
return { ...spec, error: "Use 'symbol @ context ID' for a context-scoped function breakpoint" };
}
if (contextId && caps.ContextIds === false) {
return { ...spec, error: "Context-scoped function breakpoints require breakpoint ContextIds support" };
}
return this.withCommonProps(
spec,
{ Location: location, ...(contextId && { ContextIds: [contextId] }) },
r,
caps,
);
});
this.functionBreakpoints = await this.update(this.functionBreakpoints, specs);
return this.report(this.functionBreakpoints);
Expand Down
Loading