Skip to content

Commit

Permalink
[trace-view] Added handling of aborts
Browse files Browse the repository at this point in the history
  • Loading branch information
awelc committed Nov 6, 2024
1 parent b3290a2 commit ff92b05
Show file tree
Hide file tree
Showing 41 changed files with 1,105 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import {
RuntimeValueType,
IRuntimeVariableScope,
CompoundType,
IRuntimeRefValue
IRuntimeRefValue,
ExecutionResult
} from './runtime';
import { log } from 'console';


const enum LogLevel {
Expand Down Expand Up @@ -108,6 +110,9 @@ export class MoveDebugSession extends LoggingDebugSession {
this.runtime.on(RuntimeEvents.stopOnLineBreakpoint, () => {
this.sendEvent(new StoppedEvent('breakpoint', MoveDebugSession.THREAD_ID));
});
this.runtime.on(RuntimeEvents.stopOnException, (msg) => {
this.sendEvent(new StoppedEvent('exception', MoveDebugSession.THREAD_ID, msg));
});
this.runtime.on(RuntimeEvents.end, () => {
this.sendEvent(new TerminatedEvent());
});
Expand Down Expand Up @@ -434,7 +439,8 @@ export class MoveDebugSession extends LoggingDebugSession {
): void {
let terminate = false;
try {
terminate = this.runtime.step(/* next */ true, /* stopAtCloseFrame */ false);
const executionResult = this.runtime.step(/* next */ true, /* stopAtCloseFrame */ false);
terminate = executionResult === ExecutionResult.TraceEnd;
} catch (err) {
response.success = false;
response.message = err instanceof Error ? err.message : String(err);
Expand All @@ -451,7 +457,8 @@ export class MoveDebugSession extends LoggingDebugSession {
): void {
let terminate = false;
try {
terminate = this.runtime.step(/* next */ false, /* stopAtCloseFrame */ false);
const executionResult = this.runtime.step(/* next */ false, /* stopAtCloseFrame */ false);
terminate = executionResult === ExecutionResult.TraceEnd;
} catch (err) {
response.success = false;
response.message = err instanceof Error ? err.message : String(err);
Expand All @@ -466,15 +473,17 @@ export class MoveDebugSession extends LoggingDebugSession {
response: DebugProtocol.StepOutResponse,
_args: DebugProtocol.StepOutArguments
): void {
let terminate = false;
try {
const steppedOut = this.runtime.stepOut(/* next */ false);
if (!steppedOut) {
logger.log(`Cannot step out`);
}
const executionResult = this.runtime.stepOut(/* next */ false);
terminate = executionResult === ExecutionResult.TraceEnd;
} catch (err) {
response.success = false;
response.message = err instanceof Error ? err.message : String(err);
}
if (terminate) {
this.sendEvent(new TerminatedEvent());
}
this.sendResponse(response);
}

Expand All @@ -484,7 +493,8 @@ export class MoveDebugSession extends LoggingDebugSession {
): void {
let terminate = false;
try {
terminate = this.runtime.continue();
const executionResult = this.runtime.continue();
terminate = executionResult === ExecutionResult.TraceEnd;
} catch (err) {
response.success = false;
response.message = err instanceof Error ? err.message : String(err);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,24 @@ export enum RuntimeEvents {
*/
stopOnLineBreakpoint = 'stopOnLineBreakpoint',

/**
* Stop after exception has been encountered.
*/
stopOnException = 'stopOnException',

/**
* Finish trace viewing session.
*/
end = 'end',
}
/**
* Describes result of the execution.
*/
export enum ExecutionResult {
Ok,
TraceEnd,
Exception,
}

/**
* The runtime for viewing traces.
Expand Down Expand Up @@ -252,14 +265,15 @@ export class Runtime extends EventEmitter {
* @param next determines if it's `next` (or otherwise `step`) action.
* @param stopAtCloseFrame determines if the action should stop at `CloseFrame` event
* (rather then proceedint to the following instruction).
* @returns `true` if the trace viewing session is finished, `false` otherwise.
* @returns ExecutionResult.Ok if the step action was successful, ExecutionResult.TraceEnd if we
* reached the end of the trace, and ExecutionResult.Exception if an exception was encountered.
* @throws Error with a descriptive error message if the step event cannot be handled.
*/
public step(next: boolean, stopAtCloseFrame: boolean): boolean {
public step(next: boolean, stopAtCloseFrame: boolean): ExecutionResult {
this.eventIndex++;
if (this.eventIndex >= this.trace.events.length) {
this.sendEvent(RuntimeEvents.stopOnStep);
return true;
return ExecutionResult.TraceEnd;
}
let currentEvent = this.trace.events[this.eventIndex];
if (currentEvent.type === TraceEventKind.Instruction) {
Expand Down Expand Up @@ -340,13 +354,13 @@ export class Runtime extends EventEmitter {
// also we need to make `stepOut` aware of whether it is executed
// as part of `next` (which is how `next` is implemented) or not.
this.sendEvent(RuntimeEvents.stopOnStep);
return false;
return ExecutionResult.Ok;
} else {
return this.step(next, stopAtCloseFrame);
}
}
this.sendEvent(RuntimeEvents.stopOnStep);
return false;
return ExecutionResult.Ok;
} else if (currentEvent.type === TraceEventKind.OpenFrame) {
// if function is native then the next event will be CloseFrame
if (currentEvent.isNative) {
Expand Down Expand Up @@ -377,16 +391,15 @@ export class Runtime extends EventEmitter {

if (next) {
// step out of the frame right away
this.stepOut(next);
return false;
return this.stepOut(next);
} else {
return this.step(next, stopAtCloseFrame);
}
} else if (currentEvent.type === TraceEventKind.CloseFrame) {
if (stopAtCloseFrame) {
// don't do anything as the caller needs to inspect
// the event before proceeing
return false;
return ExecutionResult.Ok;
} else {
// pop the top frame from the stack
if (this.frameStack.frames.length <= 0) {
Expand All @@ -398,6 +411,10 @@ export class Runtime extends EventEmitter {
}
} else if (currentEvent.type === TraceEventKind.Effect) {
const effect = currentEvent.effect;
if (effect.type === TraceEffectKind.ExecutionError) {
this.sendEvent(RuntimeEvents.stopOnException, effect.msg);
return ExecutionResult.Exception;
}
if (effect.type === TraceEffectKind.Write) {
const traceLocation = effect.loc;
const traceValue = effect.value;
Expand All @@ -423,15 +440,16 @@ export class Runtime extends EventEmitter {
* Handles "step out" adapter action.
*
* @param next determines if it's part of `next` (or otherwise `step`) action.
* @returns `true` if was able to step out of the frame, `false` otherwise.
* @returns ExecutionResult.Ok if the step action was successful, ExecutionResult.TraceEnd if we
* reached the end of the trace, and ExecutionResult.Exception if an exception was encountered.
* @throws Error with a descriptive error message if the step out event cannot be handled.
*/
public stepOut(next: boolean): boolean {
public stepOut(next: boolean): ExecutionResult {
const stackHeight = this.frameStack.frames.length;
if (stackHeight <= 1) {
// do nothing as there is no frame to step out to
this.sendEvent(RuntimeEvents.stopOnStep);
return false;
return ExecutionResult.Ok;
}
// newest frame is at the top of the stack
const currentFrame = this.frameStack.frames[stackHeight - 1];
Expand All @@ -443,8 +461,11 @@ export class Runtime extends EventEmitter {
// skipping over calls next-style otherwise we can miss seeing
// the actual close frame event that we are looking for
// and have the loop execute too far
if (this.step(/* next */ false, /* stopAtCloseFrame */ true)) {
// trace viewing session finished
const executionResult = this.step(/* next */ false, /* stopAtCloseFrame */ true);
if (executionResult === ExecutionResult.Exception) {
return executionResult;
}
if (executionResult === ExecutionResult.TraceEnd) {
throw new Error('Cannot find corresponding CloseFrame event for function: ' +
currentFrame.name);
}
Expand All @@ -464,13 +485,16 @@ export class Runtime extends EventEmitter {

/**
* Handles "continue" adapter action.
* @returns `true` if the trace viewing session is finished, `false` otherwise.
* @returns ExecutionResult.Ok if the step action was successful, ExecutionResult.TraceEnd if we
* reached the end of the trace, and ExecutionResult.Exception if an exception was encountered.
* @throws Error with a descriptive error message if the continue event cannot be handled.
*/
public continue(): boolean {
public continue(): ExecutionResult {
while (true) {
if (this.step(/* next */ false, /* stopAtCloseFrame */ false)) {
return true;
const executionResult = this.step(/* next */ false, /* stopAtCloseFrame */ false);
if (executionResult === ExecutionResult.TraceEnd ||
executionResult === ExecutionResult.Exception) {
return executionResult;
}
let currentEvent = this.trace.events[this.eventIndex];
if (currentEvent.type === TraceEventKind.Instruction) {
Expand All @@ -488,7 +512,7 @@ export class Runtime extends EventEmitter {
}
if (breakpoints.has(currentEvent.loc.line)) {
this.sendEvent(RuntimeEvents.stopOnLineBreakpoint);
return false;
return ExecutionResult.Ok;
}
}
}
Expand Down Expand Up @@ -910,4 +934,3 @@ function fileHash(fileContents: string): Uint8Array {
const hash = crypto.createHash('sha256').update(fileContents).digest();
return new Uint8Array(hash);
}

Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ interface JSONTraceEffect {
Pop?: JSONTracePopEffect;
Write?: JSONTraceWriteEffect;
Read?: JSONTraceReadEffect;
ExecutionError?: string;

}

interface JSONTraceCloseFrame {
Expand Down Expand Up @@ -222,15 +224,17 @@ export type TraceEvent =
* Kind of an effect of an instruction.
*/
export enum TraceEffectKind {
Write = 'Write'
Write = 'Write',
ExecutionError = 'ExecutionError'
// TODO: other effect types
}

/**
* Effect of an instruction.
*/
export type EventEffect =
| { type: TraceEffectKind.Write, loc: IRuntimeVariableLoc, value: RuntimeValueType };
| { type: TraceEffectKind.Write, loc: IRuntimeVariableLoc, value: RuntimeValueType }
| { type: TraceEffectKind.ExecutionError, msg: string };

/**
* Execution trace consisting of a sequence of trace events.
Expand Down Expand Up @@ -448,6 +452,15 @@ export function readTrace(
});
}
}
if (effect.ExecutionError) {
events.push({
type: TraceEventKind.Effect,
effect: {
type: TraceEffectKind.ExecutionError,
msg: effect.ExecutionError
}
});
}
}
}
return { events, localLifetimeEnds, tracedLines };
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "abort_assert"
edition = "2024.beta"

[dependencies]
MoveStdlib = { local = "../../../../move-stdlib" }

[addresses]
abort_assert = "0x0"
std = "0x1"
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"definition_location":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":90,"end":91},"module_name":["0000000000000000000000000000000000000000000000000000000000000000","m"],"struct_map":{},"enum_map":{},"function_map":{"0":{"definition_location":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":98,"end":101},"type_parameters":[],"parameters":[["p#0#0",{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":102,"end":103}]],"returns":[{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":111,"end":114}],"locals":[["val#1#0",{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":125,"end":128}]],"nops":{},"code_map":{"0":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":131,"end":132},"1":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":135,"end":136},"2":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":133,"end":134},"3":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":125,"end":128},"4":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":150,"end":153},"5":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":157,"end":159},"6":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":154,"end":156},"7":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":142,"end":160},"11":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":166,"end":169}},"is_native":false},"1":{"definition_location":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":185,"end":189},"type_parameters":[],"parameters":[],"returns":[],"locals":[],"nops":{},"code_map":{"0":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":202,"end":204},"1":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":198,"end":205},"3":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":205,"end":206}},"is_native":false},"2":{"definition_location":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":69,"end":208},"type_parameters":[],"parameters":[],"returns":[],"locals":[],"nops":{},"code_map":{"0":{"file_hash":[168,122,162,74,20,113,41,145,92,12,34,91,147,70,136,52,6,15,129,19,242,234,217,255,35,9,215,162,135,4,101,199],"start":69,"end":208}},"is_native":false}},"constant_map":{}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Test abort on an assertion when stepping (but not stepping over).
module abort_assert::m;

fun foo(p: u64): u64 {
let val = p + p;
assert!(val != 84);
val
}

#[test]
fun test() {
foo(42);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Test abort on an assertion when stepping (but not stepping over).
module abort_assert::m;

fun foo(p: u64): u64 {
let val = p + p;
assert!(val != 84);
val
}

#[test]
fun test() {
foo(42);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Exception
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { ExecutionResult } = require('../../out/runtime');

let action = (runtime) => {
let res = '';
// keep stepping to get abort state
runtime.step(false);
runtime.step(false);
res += ExecutionResult[runtime.step(false)];
return res;
};
run_spec(__dirname, action);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":1,"events":[{"OpenFrame":{"frame":{"frame_id":0,"function_name":"test","module":{"address":"0000000000000000000000000000000000000000000000000000000000000000","name":"m"},"binary_member_index":1,"type_instantiation":[],"parameters":[],"return_types":[],"locals_types":[],"is_native":false},"gas_left":1000000000}},{"Instruction":{"type_parameters":[],"pc":0,"gas_left":999999997,"instruction":"LD_U64"}},{"Effect":{"Push":{"RuntimeValue":{"value":42}}}},{"Instruction":{"type_parameters":[],"pc":1,"gas_left":999999997,"instruction":"CALL"}},{"OpenFrame":{"frame":{"frame_id":4,"function_name":"foo","module":{"address":"0000000000000000000000000000000000000000000000000000000000000000","name":"m"},"binary_member_index":0,"type_instantiation":[],"parameters":[{"RuntimeValue":{"value":42}}],"return_types":[{"type_":"u64","ref_type":null}],"locals_types":[{"type_":"u64","ref_type":null},{"type_":"u64","ref_type":null}],"is_native":false},"gas_left":999999997}},{"Instruction":{"type_parameters":[],"pc":0,"gas_left":999999978,"instruction":"COPY_LOC"}},{"Effect":{"Read":{"location":{"Local":[4,0]},"root_value_read":{"RuntimeValue":{"value":42}},"moved":false}}},{"Effect":{"Push":{"RuntimeValue":{"value":42}}}},{"Instruction":{"type_parameters":[],"pc":1,"gas_left":999999960,"instruction":"MOVE_LOC"}},{"Effect":{"Read":{"location":{"Local":[4,0]},"root_value_read":{"RuntimeValue":{"value":42}},"moved":true}}},{"Effect":{"Push":{"RuntimeValue":{"value":42}}}},{"Instruction":{"type_parameters":[],"pc":2,"gas_left":999999957,"instruction":"ADD"}},{"Effect":{"Pop":{"RuntimeValue":{"value":42}}}},{"Effect":{"Pop":{"RuntimeValue":{"value":42}}}},{"Effect":{"Push":{"RuntimeValue":{"value":84}}}},{"Instruction":{"type_parameters":[],"pc":3,"gas_left":999999956,"instruction":"ST_LOC"}},{"Effect":{"Pop":{"RuntimeValue":{"value":84}}}},{"Effect":{"Write":{"location":{"Local":[4,1]},"root_value_after_write":{"RuntimeValue":{"value":84}}}}},{"Instruction":{"type_parameters":[],"pc":4,"gas_left":999999938,"instruction":"COPY_LOC"}},{"Effect":{"Read":{"location":{"Local":[4,1]},"root_value_read":{"RuntimeValue":{"value":84}},"moved":false}}},{"Effect":{"Push":{"RuntimeValue":{"value":84}}}},{"Instruction":{"type_parameters":[],"pc":5,"gas_left":999999935,"instruction":"LD_U64"}},{"Effect":{"Push":{"RuntimeValue":{"value":84}}}},{"Instruction":{"type_parameters":[],"pc":6,"gas_left":999999932,"instruction":"NEQ"}},{"Effect":{"Pop":{"RuntimeValue":{"value":84}}}},{"Effect":{"Pop":{"RuntimeValue":{"value":84}}}},{"Effect":{"Push":{"RuntimeValue":{"value":false}}}},{"Instruction":{"type_parameters":[],"pc":7,"gas_left":999999931,"instruction":"BR_FALSE"}},{"Effect":{"Pop":{"RuntimeValue":{"value":false}}}},{"Instruction":{"type_parameters":[],"pc":9,"gas_left":999999928,"instruction":"LD_U64"}},{"Effect":{"Push":{"RuntimeValue":{"value":9223372066919546879}}}},{"Instruction":{"type_parameters":[],"pc":10,"gas_left":999999927,"instruction":"ABORT"}},{"Effect":{"Pop":{"RuntimeValue":{"value":9223372066919546879}}}},{"Effect":{"ExecutionError":"ABORTED"}}]}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "abort_math"
edition = "2024.beta"

[dependencies]
MoveStdlib = { local = "../../../../move-stdlib" }

[addresses]
abort_math = "0x0"
std = "0x1"
Binary file not shown.
Loading

0 comments on commit ff92b05

Please sign in to comment.