Skip to content

Commit

Permalink
Allow to create data breakpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
haydar-metin committed Jun 6, 2024
1 parent 866d068 commit fe7ae6d
Show file tree
Hide file tree
Showing 22 changed files with 795 additions and 40 deletions.
65 changes: 59 additions & 6 deletions media/memory-table.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,53 @@
border-bottom: 1px dotted var(--vscode-editorHoverWidget-border);
}

.memory-inspector-table .data-breakpoint {
outline: 1px solid var(--vscode-debugIcon-breakpointForeground);
outline-offset: 1px;
}

.memory-inspector-table .data-breakpoint.data-breakpoint-external {
outline-style: dashed;
}

.memory-inspector-table tbody .column-address {
position: relative;
}

.memory-inspector-table tbody .address-status {
position: absolute;
left: -1px;
align-items: center;
display: flex;
justify-content: center;
}

.memory-inspector-table tbody .address-status.codicon {
font-size: 12px;
}

.memory-inspector-table tbody .address-status.codicon-debug-breakpoint {
color: var(--vscode-debugIcon-breakpointForeground);
}

.memory-inspector-table tbody .address-status.codicon-debug-stackframe {
color: var(--vscode-debugIcon-breakpointCurrentStackframeForeground);
}

.memory-inspector-table
tbody
.address-status.codicon-debug-breakpoint.codicon-debug-stackframe:after {
content: "\ea71";
position: absolute;
left: 3px;
font-size: 6px;
color: var(--vscode-debugIcon-breakpointForeground);
}

.memory-inspector-table tbody .debug-hit {
outline-color: var(--vscode-debugIcon-breakpointCurrentStackframeForeground);
}

/* == MoreMemorySelect == */

.bytes-select {
Expand Down Expand Up @@ -90,7 +137,7 @@

.memory-inspector-table span.p-column-resizer {
border-right: 2px solid var(--vscode-editor-lineHighlightBorder);
transition: border-right .1s ease-out;
transition: border-right 0.1s ease-out;
}

.memory-inspector-table span.p-column-resizer:hover {
Expand All @@ -111,7 +158,7 @@
/* Basic hover formatting (copied from Monaco hovers) */
.memory-hover {
min-width: fit-content;
max-width: var(--vscode-hover-maxWidth,500px);
max-width: var(--vscode-hover-maxWidth, 500px);
border: 1px solid var(--vscode-editorHoverWidget-border);
border-radius: 3px;

Expand All @@ -127,34 +174,40 @@
border-collapse: collapse;
border-style: hidden;
}

.memory-hover table caption {
padding: 4px;
border-bottom: 1px solid var(--vscode-editorHoverWidget-border);
}

.memory-hover td {
border: 1px solid var(--vscode-editorHoverWidget-border);
padding: 2px 8px;
}

.memory-hover td:first-child {
text-align: right;
}

/* Colors for the hover fields */
.memory-hover .label-value-pair>.label {
color: var(--vscode-debugTokenExpression-string);
white-space: nowrap;
.memory-hover .label-value-pair > .label {
color: var(--vscode-debugTokenExpression-string);
white-space: nowrap;
}
.memory-hover .label-value-pair>.value {

.memory-hover .label-value-pair > .value {
color: var(--vscode-debugTokenExpression-number);
}

/* Colors for specific hover fields */
.memory-hover .address-hover .primary {
background-color: var(--vscode-list-hoverBackground);
}

.memory-hover table caption {
color: var(--vscode-symbolIcon-variableForeground);
}

.memory-hover .address-hover .value.utf8,
.memory-hover .data-hover .value.utf8,
.memory-hover .variable-hover .value.type {
Expand Down
55 changes: 55 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,36 @@
"title": "Go to value in Memory Inspector",
"category": "Memory"
},
{
"command": "memory-inspector.data-breakpoint.set.read",
"title": "Break on Value Read",
"enablement": "memory-inspector.canWrite",
"category": "Memory"
},
{
"command": "memory-inspector.data-breakpoint.set.readWrite",
"title": "Break on Value Access",
"enablement": "memory-inspector.canWrite",
"category": "Memory"
},
{
"command": "memory-inspector.data-breakpoint.set.write",
"title": "Break on Value Change",
"enablement": "memory-inspector.canWrite",
"category": "Memory"
},
{
"command": "memory-inspector.data-breakpoint.remove",
"title": "Remove Breakpoint",
"enablement": "memory-inspector.canWrite",
"category": "Memory"
},
{
"command": "memory-inspector.data-breakpoint.remove-all",
"title": "Remove All Breakpoints",
"enablement": "memory-inspector.canWrite",
"category": "Memory"
},
{
"command": "memory-inspector.toggle-variables-column",
"title": "Toggle Variables Column",
Expand Down Expand Up @@ -214,6 +244,31 @@
"command": "memory-inspector.go-to-value",
"group": "display@7",
"when": "webviewId === memory-inspector.memory && memory-inspector.variable.isPointer"
},
{
"command": "memory-inspector.data-breakpoint.set.read",
"group": "breakpoints@1",
"when": "webviewId === memory-inspector.memory && memory-inspector.breakpoint.isBreakable"
},
{
"command": "memory-inspector.data-breakpoint.set.write",
"group": "breakpoints@2",
"when": "webviewId === memory-inspector.memory && memory-inspector.breakpoint.isBreakable"
},
{
"command": "memory-inspector.data-breakpoint.set.readWrite",
"group": "breakpoints@3",
"when": "webviewId === memory-inspector.memory && memory-inspector.breakpoint.isBreakable"
},
{
"command": "memory-inspector.data-breakpoint.remove",
"group": "breakpoints@4",
"when": "webviewId === memory-inspector.memory && memory-inspector.breakpoint.type === 'internal'"
},
{
"command": "memory-inspector.data-breakpoint.remove-all",
"group": "breakpoints@5",
"when": "webviewId === memory-inspector.memory && memory-inspector.breakpoint.type === 'internal'"
}
]
},
Expand Down
45 changes: 45 additions & 0 deletions src/common/breakpoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/********************************************************************************
* Copyright (C) 2024 EclipseSource.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { DebugProtocol } from '@vscode/debugprotocol';
import { DebugRequestTypes } from './debug-requests';

export interface TrackedDataBreakpoint {
type: TrackedBreakpointType;
breakpoint: DebugProtocol.DataBreakpoint;
/**
* The respective response for the breakpoint.
*/
response: DebugProtocol.SetDataBreakpointsResponse['body']['breakpoints'][0]
}

export interface TrackedDataBreakpoints {
/**
* Breakpoints set from external contributors.
*/
external: TrackedDataBreakpoint[],
/**
* Breakpoints set from us.
*/
internal: TrackedDataBreakpoint[]
}

export type TrackedBreakpointType = 'internal' | 'external';

export type DataBreakpointInfoArguments = DebugRequestTypes['dataBreakpointInfo'][0];
export type DataBreakpointInfoResult = DebugRequestTypes['dataBreakpointInfo'][1];
export type SetDataBreakpointsArguments = DebugRequestTypes['setDataBreakpoints'][0];
export type SetDataBreakpointsResult = DebugRequestTypes['setDataBreakpoints'][1];
24 changes: 19 additions & 5 deletions src/common/debug-requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export interface DebugRequestTypes {
'scopes': [DebugProtocol.ScopesArguments, DebugProtocol.ScopesResponse['body']]
'variables': [DebugProtocol.VariablesArguments, DebugProtocol.VariablesResponse['body']]
'writeMemory': [DebugProtocol.WriteMemoryArguments, DebugProtocol.WriteMemoryResponse['body']]
'dataBreakpointInfo': [DebugProtocol.DataBreakpointInfoArguments, DebugProtocol.DataBreakpointInfoResponse['body']]
'setDataBreakpoints': [DebugProtocol.SetDataBreakpointsArguments, DebugProtocol.SetDataBreakpointsResponse['body']]
}

export interface DebugEvents {
Expand Down Expand Up @@ -59,16 +61,28 @@ export function isDebugEvaluateArguments(args: DebugProtocol.EvaluateArguments |
}

export function isDebugRequest<K extends keyof DebugRequestTypes>(command: K, message: unknown): message is DebugRequest<K, DebugRequestTypes[K][0]> {
const assumed = message ? message as DebugProtocol.Request : undefined;
return !!assumed && assumed.type === 'request' && assumed.command === command;
return isDebugRequestType(message) && message.command === command;
}

export function isDebugResponse<K extends keyof DebugRequestTypes>(command: K, message: unknown): message is DebugResponse<K, DebugRequestTypes[K][1]> {
const assumed = message ? message as DebugProtocol.Response : undefined;
return !!assumed && assumed.type === 'response' && assumed.command === command;
return isDebugResponseType(message) && message.command === command;
}

export function isDebugEvent<K extends keyof DebugEvents>(event: K, message: unknown): message is DebugEvents[K] {
return isDebugEventType(message) && message.event === event;
}

export function isDebugRequestType(message: unknown): message is DebugProtocol.Request {
const assumed = message ? message as DebugProtocol.Request : undefined;
return !!assumed && assumed.type === 'request';
}

export function isDebugResponseType(message: unknown): message is DebugProtocol.Response {
const assumed = message ? message as DebugProtocol.Response : undefined;
return !!assumed && assumed.type === 'response';
}

export function isDebugEventType(message: unknown): message is DebugProtocol.Event {
const assumed = message ? message as DebugProtocol.Event : undefined;
return !!assumed && assumed.type === 'event' && assumed.event === event;
return !!assumed && assumed.type === 'event';
}
1 change: 1 addition & 0 deletions src/common/memory-range.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export interface VariableMetadata {
type?: string;
/** If applicable, a string representation of the variable's value */
value?: string;
parentVariablesReference?: number;
isPointer?: boolean;
}

Expand Down
9 changes: 8 additions & 1 deletion src/common/messaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import type { DebugProtocol } from '@vscode/debugprotocol';
import type { NotificationType, RequestType } from 'vscode-messenger-common';
import { URI } from 'vscode-uri';
import { VariablesView } from '../plugin/external-views';
import { DebugRequestTypes } from './debug-requests';
import type { TrackedDataBreakpoints } from './breakpoint';
import { DebugEvents, DebugRequestTypes } from './debug-requests';
import type { VariableRange, WrittenMemory } from './memory-range';
import { MemoryViewSettings } from './webview-configuration';
import { WebviewContext } from './webview-context';
Expand All @@ -32,6 +33,9 @@ export type ReadMemoryResult = DebugRequestTypes['readMemory'][1];
export type WriteMemoryArguments = DebugRequestTypes['writeMemory'][0];
export type WriteMemoryResult = DebugRequestTypes['writeMemory'][1];

export type StoppedEvent = DebugEvents['stopped'];
export type ContinuedEvent = DebugEvents['continued'];

export type StoreMemoryArguments = MemoryOptions & { proposedOutputName?: string } | VariablesView.IVariablesContext | WebviewContext;
export type StoreMemoryResult = void;

Expand All @@ -52,6 +56,9 @@ export const resetMemoryViewSettingsType: NotificationType<void> = { method: 're
export const setTitleType: NotificationType<string> = { method: 'setTitle' };
export const memoryWrittenType: NotificationType<WrittenMemory> = { method: 'memoryWritten' };
export const sessionContextChangedType: NotificationType<SessionContext> = { method: 'sessionContextChanged' };
export const setTrackedBreakpointType: NotificationType<TrackedDataBreakpoints> = { method: 'setTrackedBreakpoints' };
export const notifyStoppedType: NotificationType<StoppedEvent> = { method: 'notifyStoppedType' };
export const notifyContinuedType: NotificationType<ContinuedEvent> = { method: 'notifyContinuedType' };

// Requests
export const setOptionsType: RequestType<MemoryOptions, void> = { method: 'setOptions' };
Expand Down
17 changes: 17 additions & 0 deletions src/common/webview-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ export interface WebviewVariableContext extends WebviewCellContext {
variable?: VariableMetadata
}

export interface WebviewGroupContext extends WebviewCellContext {
memoryData?: {
group: {
startAddress: string;
length: number;
}
}
}

/**
* Retrieves the currently visible (configurable) columns from the given {@link WebviewContext}.
* @returns A string array containing the visible columns ids.
Expand All @@ -62,6 +71,14 @@ export function isWebviewContext(args: WebviewContext | unknown): args is Webvie
&& typeof assumed.activeReadArguments?.memoryReference === 'string';
}

export function isWebviewGroupContext(args: WebviewVariableContext | unknown): args is Required<WebviewGroupContext> {
const assumed = args ? args as WebviewGroupContext : undefined;
return !!assumed && isWebviewContext(args)
&& !!assumed.memoryData
&& (typeof assumed.memoryData.group.startAddress === 'string')
&& (typeof assumed.memoryData.group.length === 'number');
}

export function isWebviewVariableContext(args: WebviewVariableContext | unknown): args is Required<WebviewVariableContext> {
const assumed = args ? args as WebviewVariableContext : undefined;
return !!assumed && isWebviewContext(args)
Expand Down
6 changes: 5 additions & 1 deletion src/entry-points/browser/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import * as vscode from 'vscode';
import { AdapterRegistry } from '../../plugin/adapter-registry/adapter-registry';
import { CAdapter } from '../../plugin/adapter-registry/c-adapter';
import { BreakpointProvider } from '../../plugin/breakpoints/breakpoint-provider';
import { BreakpointTracker } from '../../plugin/breakpoints/breakpoint-tracker';
import { ContextTracker } from '../../plugin/context-tracker';
import { MemoryProvider } from '../../plugin/memory-provider';
import { MemoryStorage } from '../../plugin/memory-storage';
Expand All @@ -27,8 +29,10 @@ export const activate = async (context: vscode.ExtensionContext): Promise<Adapte
const registry = new AdapterRegistry();
const sessionTracker = new SessionTracker();
new ContextTracker(sessionTracker);
const breakpointTracker = new BreakpointTracker(sessionTracker);
const breakpointProvider = new BreakpointProvider(sessionTracker, breakpointTracker);
const memoryProvider = new MemoryProvider(registry, sessionTracker);
const memoryView = new MemoryWebview(context.extensionUri, memoryProvider, sessionTracker);
const memoryView = new MemoryWebview(context.extensionUri, memoryProvider, sessionTracker, breakpointTracker, breakpointProvider);
const memoryStorage = new MemoryStorage(memoryProvider);
const cAdapter = new CAdapter(registry);

Expand Down
6 changes: 5 additions & 1 deletion src/entry-points/desktop/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import * as vscode from 'vscode';
import { AdapterRegistry } from '../../plugin/adapter-registry/adapter-registry';
import { CAdapter } from '../../plugin/adapter-registry/c-adapter';
import { BreakpointProvider } from '../../plugin/breakpoints/breakpoint-provider';
import { BreakpointTracker } from '../../plugin/breakpoints/breakpoint-tracker';
import { ContextTracker } from '../../plugin/context-tracker';
import { MemoryProvider } from '../../plugin/memory-provider';
import { MemoryStorage } from '../../plugin/memory-storage';
Expand All @@ -27,8 +29,10 @@ export const activate = async (context: vscode.ExtensionContext): Promise<Adapte
const registry = new AdapterRegistry();
const sessionTracker = new SessionTracker();
new ContextTracker(sessionTracker);
const breakpointTracker = new BreakpointTracker(sessionTracker);
const breakpointProvider = new BreakpointProvider(sessionTracker, breakpointTracker);
const memoryProvider = new MemoryProvider(registry, sessionTracker);
const memoryView = new MemoryWebview(context.extensionUri, memoryProvider, sessionTracker);
const memoryView = new MemoryWebview(context.extensionUri, memoryProvider, sessionTracker, breakpointTracker, breakpointProvider);
const memoryStorage = new MemoryStorage(memoryProvider);
const cAdapter = new CAdapter(registry);

Expand Down
Loading

0 comments on commit fe7ae6d

Please sign in to comment.