Skip to content

Commit

Permalink
Use dataBreakpointInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
haydar-metin committed Jun 6, 2024
1 parent 5c64dee commit 973a7d7
Show file tree
Hide file tree
Showing 12 changed files with 381 additions and 469 deletions.
10 changes: 6 additions & 4 deletions src/common/breakpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { DebugProtocol } from '@vscode/debugprotocol';
import { DebugRequestTypes } from './debug-requests';

export interface TrackedBreakpoint {
export interface TrackedDataBreakpoint {
type: TrackedBreakpointType;
breakpoint: DebugProtocol.DataBreakpoint;
/**
Expand All @@ -26,18 +26,20 @@ export interface TrackedBreakpoint {
response: DebugProtocol.SetDataBreakpointsResponse['body']['breakpoints'][0]
}

export interface TrackedBreakpoints {
export interface TrackedDataBreakpoints {
/**
* Breakpoints set from external contributors.
*/
external: TrackedBreakpoint[],
external: TrackedDataBreakpoint[],
/**
* Breakpoints set from us.
*/
internal: TrackedBreakpoint[]
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];
1 change: 1 addition & 0 deletions src/common/debug-requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ 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']]
}

Expand Down
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
4 changes: 2 additions & 2 deletions src/common/messaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ 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 type { TrackedBreakpoints } from './breakpoint';
import type { TrackedDataBreakpoints } from './breakpoint';
import { DebugEvents, DebugRequestTypes } from './debug-requests';
import type { VariableRange, WrittenMemory } from './memory-range';
import { MemoryViewSettings } from './webview-configuration';
Expand Down Expand Up @@ -56,7 +56,7 @@ 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<TrackedBreakpoints> = { method: 'setTrackedBreakpoints' };
export const setTrackedBreakpointType: NotificationType<TrackedDataBreakpoints> = { method: 'setTrackedBreakpoints' };
export const notifyStoppedType: NotificationType<StoppedEvent> = { method: 'notifyStoppedType' };
export const notifyContinuedType: NotificationType<ContinuedEvent> = { method: 'notifyContinuedType' };

Expand Down
7 changes: 5 additions & 2 deletions src/plugin/adapter-registry/adapter-capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export class AdapterVariableTracker implements vscode.DebugAdapterTracker {
if (this.isDesiredVariable(parent) && parent.children?.length) {
this.logger.debug('Resolving children of', parent.name);
parent.children.forEach(child => {
previous.push(this.variableToVariableRange(child, session));
previous.push(this.variableToVariableRange(child, session, parent));
});
} else {
this.logger.debug('Ignoring', parent.name);
Expand All @@ -122,7 +122,10 @@ export class AdapterVariableTracker implements vscode.DebugAdapterTracker {
return candidate.presentationHint !== 'registers' && candidate.name !== 'Registers';
}

protected variableToVariableRange(_variable: DebugProtocol.Variable, _session: vscode.DebugSession): Promise<VariableRange | undefined> {
protected variableToVariableRange(
_variable: DebugProtocol.Variable,
_session: vscode.DebugSession,
_parent: WithChildren<DebugProtocol.Scope | DebugProtocol.Variable>): Promise<VariableRange | undefined> {
throw new Error('To be implemented by derived classes!');
}

Expand Down
8 changes: 6 additions & 2 deletions src/plugin/adapter-registry/c-tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { DebugProtocol } from '@vscode/debugprotocol';
import * as vscode from 'vscode';
import { sendRequest } from '../../common/debug-requests';
import { toHexStringWithRadixMarker, VariableRange } from '../../common/memory-range';
import { AdapterVariableTracker, decimalAddress, extractAddress, hexAddress, notADigit } from './adapter-capabilities';
import { AdapterVariableTracker, decimalAddress, extractAddress, hexAddress, notADigit, WithChildren } from './adapter-capabilities';

export namespace CEvaluateExpression {
export function sizeOf(expression: string): string {
Expand All @@ -35,7 +35,10 @@ export class CTracker extends AdapterVariableTracker {
* Resolves memory location and size using evaluate requests for `$(variable.name)` and `sizeof(variable.name)`
* Ignores the presence or absence of variable.memoryReference.
*/
protected override async variableToVariableRange(variable: DebugProtocol.Variable, session: vscode.DebugSession): Promise<VariableRange | undefined> {
protected override async variableToVariableRange(
variable: DebugProtocol.Variable,
session: vscode.DebugSession,
parent: WithChildren<DebugProtocol.Scope | DebugProtocol.Variable>): Promise<VariableRange | undefined> {
if (this.currentFrame === undefined || !variable.name) {
this.logger.debug('Unable to resolve', variable.name,
{ noName: !variable.name, noFrame: this.currentFrame === undefined });
Expand Down Expand Up @@ -66,6 +69,7 @@ export class CTracker extends AdapterVariableTracker {
endAddress: variableSize === undefined ? undefined : toHexStringWithRadixMarker(address + variableSize),
value: variable.value,
type: variable.type,
parentVariablesReference: parent.variablesReference,
isPointer,
};
return variableRange;
Expand Down
11 changes: 8 additions & 3 deletions src/plugin/breakpoints/breakpoint-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { SetDataBreakpointsArguments, SetDataBreakpointsResult } from '../../common/breakpoint';
import { DataBreakpointInfoArguments, DataBreakpointInfoResult, SetDataBreakpointsArguments, SetDataBreakpointsResult } from '../../common/breakpoint';
import { sendRequest } from '../../common/debug-requests';
import { SessionTracker } from '../session-tracker';
import { BreakpointTracker } from './breakpoint-tracker';
Expand All @@ -24,7 +24,7 @@ export class BreakpointProvider {
constructor(protected readonly sessionTracker: SessionTracker, protected readonly breakpointTracker: BreakpointTracker) {
this.breakpointTracker.onSetDataBreakpointResponse(() => {
this.setMemoryInspectorDataBreakpoint({
breakpoints: this.breakpointTracker.internalBreakpoints.map(bp => bp.breakpoint)
breakpoints: this.breakpointTracker.internalDataBreakpoints.map(bp => bp.breakpoint)
});
});
}
Expand All @@ -33,7 +33,7 @@ export class BreakpointProvider {
const session = this.sessionTracker.assertDebugCapability(this.sessionTracker.activeSession, 'supportsDataBreakpoints', 'set data breakpoint');
this.breakpointTracker.notifySetDataBreakpointEnabled = false;
const breakpoints = [
...this.breakpointTracker.externalBreakpoints.map(bp => bp.breakpoint),
...this.breakpointTracker.externalDataBreakpoints.map(bp => bp.breakpoint),
...args.breakpoints];
return sendRequest(session, 'setDataBreakpoints', { breakpoints })
.then(response => {
Expand All @@ -44,4 +44,9 @@ export class BreakpointProvider {
this.breakpointTracker.notifySetDataBreakpointEnabled = true;
});
}

async dataBreakpointInfo(args: DataBreakpointInfoArguments): Promise<DataBreakpointInfoResult> {
const session = this.sessionTracker.assertDebugCapability(this.sessionTracker.activeSession, 'supportsDataBreakpoints', 'data breakpoint info');
return sendRequest(session, 'dataBreakpointInfo', args);
}
}
16 changes: 8 additions & 8 deletions src/plugin/breakpoints/breakpoint-tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@

import { DebugProtocol } from '@vscode/debugprotocol';
import * as vscode from 'vscode';
import { SetDataBreakpointsResult, TrackedBreakpoint, TrackedBreakpoints } from '../../common/breakpoint';
import { SetDataBreakpointsResult, TrackedDataBreakpoint, TrackedDataBreakpoints } from '../../common/breakpoint';
import { isDebugRequest, isDebugResponse } from '../../common/debug-requests';
import { isSessionEvent, SessionContinuedEvent, SessionEvent, SessionRequest, SessionResponse, SessionStoppedEvent, SessionTracker } from '../session-tracker';

export class BreakpointTracker {
protected _dataBreakpoints: TrackedBreakpoints = { external: [], internal: [] };
protected _dataBreakpoints: TrackedDataBreakpoints = { external: [], internal: [] };
protected _stoppedEvent?: SessionStoppedEvent;
protected dataBreakpointsRequest: Record<number, DebugProtocol.SetDataBreakpointsRequest> = {};

protected _onBreakpointsChanged = new vscode.EventEmitter<TrackedBreakpoints>();
protected _onBreakpointsChanged = new vscode.EventEmitter<TrackedDataBreakpoints>();
readonly onBreakpointChanged = this._onBreakpointsChanged.event;

protected _onSetDataBreakpointResponse = new vscode.EventEmitter<DebugProtocol.SetDataBreakpointsResponse>();
Expand All @@ -39,15 +39,15 @@ export class BreakpointTracker {

notifySetDataBreakpointEnabled = true;

get breakpoints(): TrackedBreakpoints {
get dataBreakpoints(): TrackedDataBreakpoints {
return this._dataBreakpoints;
}

get internalBreakpoints(): TrackedBreakpoint[] {
get internalDataBreakpoints(): TrackedDataBreakpoint[] {
return this._dataBreakpoints.internal;
}

get externalBreakpoints(): TrackedBreakpoint[] {
get externalDataBreakpoints(): TrackedDataBreakpoint[] {
return this._dataBreakpoints.external;
}

Expand Down Expand Up @@ -92,7 +92,7 @@ export class BreakpointTracker {
...event.data,
body: {
...event.data.body,
hitBreakpointIds: this.externalBreakpoints.map(bp => bp.response.id ?? -1)
hitBreakpointIds: this.externalDataBreakpoints.map(bp => bp.response.id ?? -1)
}
}
};
Expand Down Expand Up @@ -152,6 +152,6 @@ export class BreakpointTracker {
}

protected fireDataBreakpoints(): void {
this._onBreakpointsChanged.fire(this.breakpoints);
this._onBreakpointsChanged.fire(this.dataBreakpoints);
}
}
15 changes: 11 additions & 4 deletions src/plugin/memory-webview-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ export class MemoryWebview implements vscode.CustomReadonlyEditorProvider {
}

protected setBreakpoints(webviewParticipant: WebviewIdMessageParticipant): void {
this.messenger.sendNotification(setTrackedBreakpointType, webviewParticipant, this.breakpointTracker.breakpoints);
this.messenger.sendNotification(setTrackedBreakpointType, webviewParticipant, this.breakpointTracker.dataBreakpoints);
if (this.breakpointTracker.stoppedEvent) {
this.messenger.sendNotification(notifyStoppedType, webviewParticipant, this.breakpointTracker.stoppedEvent.data);
}
Expand Down Expand Up @@ -360,13 +360,20 @@ export class MemoryWebview implements vscode.CustomReadonlyEditorProvider {
if (isWebviewGroupContext(ctx)) {
dataId = ctx.memoryData.group.startAddress;
} else if (isWebviewVariableContext(ctx)) {
dataId = ctx.variable.name;
const info = await this.breakpointProvider.dataBreakpointInfo({
name: ctx.variable.name,
variablesReference: ctx.variable.parentVariablesReference
});
if (!info.dataId) {
throw new Error(`DataBreakpointInfo returned for variable ${ctx.variable} an invalid info.`);
}
dataId = info.dataId;
} else {
throw new Error(`WebviewContext needs to be a Group or Variable context. It was: ${JSON.stringify(ctx, undefined, 2)}`);
}

// Don't remove already existing breakpoints
const breakpoints = this.breakpointTracker.internalBreakpoints.map(bp => bp.breakpoint);
const breakpoints = this.breakpointTracker.internalDataBreakpoints.map(bp => bp.breakpoint);

return this.setDataBreakpoint({
breakpoints: [
Expand All @@ -393,7 +400,7 @@ export class MemoryWebview implements vscode.CustomReadonlyEditorProvider {
throw new Error(`WebviewContext needs to be a Group or Variable context. It was: ${JSON.stringify(ctx, undefined, 2)}`);
}

const breakpoints = this.breakpointTracker.internalBreakpoints
const breakpoints = this.breakpointTracker.internalDataBreakpoints
.filter(bp => bp.breakpoint.dataId !== dataId)
.map(bp => bp.breakpoint);

Expand Down
32 changes: 20 additions & 12 deletions src/webview/breakpoints/breakpoint-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

import { DebugProtocol } from '@vscode/debugprotocol';
import { HOST_EXTENSION } from 'vscode-messenger-common';
import { TrackedBreakpoint, TrackedBreakpoints, TrackedBreakpointType } from '../../common/breakpoint';
import { BigIntMemoryRange, BigIntVariableRange, doOverlap, toHexStringWithRadixMarker, VariableRange } from '../../common/memory-range';
import { TrackedBreakpointType, TrackedDataBreakpoint, TrackedDataBreakpoints } from '../../common/breakpoint';
import { BigIntMemoryRange, BigIntVariableRange, doOverlap, isWithin, toHexStringWithRadixMarker } from '../../common/memory-range';
import { getVariablesType, notifyContinuedType, notifyStoppedType, setTrackedBreakpointType, StoppedEvent } from '../../common/messaging';
import { EventEmitter } from '../utils/events';
import { UpdateExecutor } from '../utils/view-types';
Expand All @@ -30,19 +30,19 @@ export interface BreakpointMetadata {
}

export class BreakpointService implements UpdateExecutor {
protected _breakpoints: TrackedBreakpoints = { external: [], internal: [] };
protected _breakpoints: TrackedDataBreakpoints = { external: [], internal: [] };
protected _stoppedEvent?: StoppedEvent;

protected variables: BigIntVariableRange[] = [];

protected _onDidChange = new EventEmitter<void>();
readonly onDidChange = this._onDidChange.event;

get breakpoints(): TrackedBreakpoints {
get breakpoints(): TrackedDataBreakpoints {
return this._breakpoints;
}

get allBreakpoints(): TrackedBreakpoint[] {
get allBreakpoints(): TrackedDataBreakpoint[] {
return [...this.breakpoints.external, ...this.breakpoints.internal];
}

Expand Down Expand Up @@ -77,22 +77,30 @@ export class BreakpointService implements UpdateExecutor {
});
}

findByDataId(dataId: string): TrackedBreakpoint | undefined {
findByDataId(dataId: string): TrackedDataBreakpoint | undefined {
return [...this.breakpoints.external, ...this.breakpoints.internal].find(bp => bp.breakpoint.dataId === dataId);
}

inRange(range: BigIntMemoryRange): TrackedBreakpoint[] {
inRange(range: BigIntMemoryRange): TrackedDataBreakpoint[] {
const variables = this.findVariablesInRange(range);
return this.allBreakpoints.filter(bp =>
bp.breakpoint.dataId === toHexStringWithRadixMarker(range.startAddress) ||
variables.some(v => v.name === bp.breakpoint.dataId));
return this.allBreakpoints.filter(bp => {
let isInRange = false;
try {
const bigint = BigInt(bp.breakpoint.dataId);
isInRange = isWithin(bigint, range);
} catch (ex) {
// Nothing to do
}

return isInRange || variables.some(v => v.name === bp.breakpoint.dataId);
});
}

protected findVariablesInRange(range: BigIntMemoryRange): BigIntVariableRange[] {
return this.variables.filter(v => doOverlap(v, range));
}

isHit(breakpointOrDataId: TrackedBreakpoint | string): boolean {
isHit(breakpointOrDataId: TrackedDataBreakpoint | string): boolean {
if (this.stoppedEvent === undefined ||
this.stoppedEvent.body.hitBreakpointIds === undefined ||
this.stoppedEvent.body.hitBreakpointIds.length === 0) {
Expand All @@ -103,7 +111,7 @@ export class BreakpointService implements UpdateExecutor {
return !!bp?.response.id && this.stoppedEvent.body.hitBreakpointIds.includes(bp.response.id);
}

metadata(breakpointOrDataId: TrackedBreakpoint | string): BreakpointMetadata | undefined {
metadata(breakpointOrDataId: TrackedDataBreakpoint | string): BreakpointMetadata | undefined {
const bp = typeof breakpointOrDataId === 'string' ? this.findByDataId(breakpointOrDataId) : breakpointOrDataId;

if (bp?.type === 'external') {
Expand Down
Loading

0 comments on commit 973a7d7

Please sign in to comment.