Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
Merge pull request #2965 from trufflesuite/stacktrace
Browse files Browse the repository at this point in the history
Add stacktraces to debugger library and print them in CLI
  • Loading branch information
haltman-at authored Apr 17, 2020
2 parents 4cabc0d + 19c7ea2 commit eb5b18d
Show file tree
Hide file tree
Showing 26 changed files with 1,188 additions and 124 deletions.
13 changes: 12 additions & 1 deletion packages/core/lib/debug/interpreter.js
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,8 @@ class DebugInterpreter {
//check if transaction failed
if (!this.session.view(evm.transaction.status)) {
this.printer.printRevertMessage();
this.printer.print("");
this.printer.printStacktrace(true); //final stacktrace
} else {
//case if transaction succeeded
this.printer.print("Transaction completed successfully.");
Expand Down Expand Up @@ -522,6 +524,14 @@ class DebugInterpreter {
this.enabledExpressions
);
break;
case "s":
if (this.session.view(selectors.session.status.loaded)) {
this.printer.printStacktrace(
this.session.view(trace.finished) //print final report if finished,
//intermediate if not
);
}
break;
case "o":
case "i":
case "u":
Expand Down Expand Up @@ -578,7 +588,8 @@ class DebugInterpreter {
cmd !== "r" &&
cmd !== "-" &&
cmd !== "t" &&
cmd !== "T"
cmd !== "T" &&
cmd !== "s"
) {
this.lastCommand = cmd;
}
Expand Down
22 changes: 20 additions & 2 deletions packages/core/lib/debug/printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ const DebugUtils = require("@truffle/debug-utils");
const Codec = require("@truffle/codec");

const selectors = require("@truffle/debugger").selectors;
const { session, solidity, trace, controller, data, evm } = selectors;
const {
session,
solidity,
trace,
controller,
data,
evm,
stacktrace
} = selectors;

class DebugPrinter {
constructor(config, session) {
Expand Down Expand Up @@ -231,7 +239,9 @@ class DebugPrinter {
}

printRevertMessage() {
this.config.logger.log("Transaction halted with a RUNTIME ERROR.");
this.config.logger.log(
DebugUtils.truffleColors.red("Transaction halted with a RUNTIME ERROR.")
);
this.config.logger.log("");
let rawRevertMessage = this.session.view(evm.current.step.returnValue);
let revertDecodings = Codec.decodeRevert(
Expand Down Expand Up @@ -287,6 +297,14 @@ class DebugPrinter {
);
}

printStacktrace(final) {
this.config.logger.log("Stacktrace:");
let report = final
? this.session.view(stacktrace.current.finalReport)
: this.session.view(stacktrace.current.report);
this.config.logger.log(DebugUtils.formatStacktrace(report));
}

async printWatchExpressionsResults(expressions) {
debug("expressions %o", expressions);
for (let expression of expressions) {
Expand Down
58 changes: 51 additions & 7 deletions packages/debug-utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ const commandReference = {
"q": "quit",
"r": "reset",
"t": "load new transaction",
"T": "unload transaction"
"T": "unload transaction",
"s": "print stacktrace"
};

const truffleColors = {
Expand All @@ -51,6 +52,8 @@ const truffleColors = {
const DEFAULT_TAB_WIDTH = 8;

var DebugUtils = {
truffleColors, //make these externally available

gatherArtifacts: async function(config) {
// Gather all available contract artifacts
let files = await dir.promiseFiles(config.contracts_build_directory);
Expand Down Expand Up @@ -118,8 +121,8 @@ var DebugUtils = {
};

//now: walk each AST
return compilation.sources.every(
source => (source ? allIDsUnseenSoFar(source.ast) : true)
return compilation.sources.every(source =>
source ? allIDsUnseenSoFar(source.ast) : true
);
},

Expand Down Expand Up @@ -188,10 +191,11 @@ var DebugUtils = {
];

var commandSections = [
//TODO
["o", "i", "u", "n"],
[";"],
["p"],
["l", "h"],
["l", "s", "h"],
["q", "r", "t", "T"],
["b", "B", "c"],
["+", "-"],
Expand Down Expand Up @@ -552,6 +556,47 @@ var DebugUtils = {
.join(OS.EOL);
},

formatStacktrace: function(stacktrace, indent = 2) {
//we want to print inner to outer, so first, let's
//reverse
stacktrace = stacktrace.slice().reverse(); //reverse is in-place so clone first
let lines = stacktrace.map(({ functionName, contractName, location }) => {
let name;
if (contractName && functionName) {
name = `${contractName}.${functionName}`;
} else if (contractName) {
name = contractName;
} else {
name = "unknown function";
}
if (location) {
let {
source: { sourcePath },
sourceRange: {
lines: {
start: { line, column }
}
}
} = location;
return `at ${name} (${sourcePath}:${line + 1}:${column + 1})`; //add 1 to account for 0-indexing
} else {
return `at ${name} (unknown location)`;
}
});
let status = stacktrace[0].status;
if (status != undefined) {
lines.unshift(
status
? "Error: Improper return (may be an unexpected self-destruct)"
: "Error: Revert or exceptional halt"
);
}
let indented = lines.map((line, index) =>
index === 0 ? line : " ".repeat(indent) + line
);
return indented.join(OS.EOL);
},

colorize: function(code) {
//I'd put these outside the function
//but then it gives me errors, because
Expand Down Expand Up @@ -698,9 +743,8 @@ var DebugUtils = {
cleanThis: function(variables, replacement) {
return Object.assign(
{},
...Object.entries(variables).map(
([variable, value]) =>
variable === "this" ? { [replacement]: value } : { [variable]: value }
...Object.entries(variables).map(([variable, value]) =>
variable === "this" ? { [replacement]: value } : { [variable]: value }
)
);
}
Expand Down
24 changes: 12 additions & 12 deletions packages/debugger/lib/controller/actions/index.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
export const ADVANCE = "ADVANCE";
export const ADVANCE = "CONTROLLER_ADVANCE";
export function advance(count) {
return { type: ADVANCE, count };
}

export const STEP_NEXT = "STEP_NEXT";
export const STEP_NEXT = "CONTROLLER_STEP_NEXT";
export function stepNext() {
return { type: STEP_NEXT };
}

export const STEP_OVER = "STEP_OVER";
export const STEP_OVER = "CONTROLLER_STEP_OVER";
export function stepOver() {
return { type: STEP_OVER };
}

export const STEP_INTO = "STEP_INTO";
export const STEP_INTO = "CONTROLLER_STEP_INTO";
export function stepInto() {
return { type: STEP_INTO };
}

export const STEP_OUT = "STEP_OUT";
export const STEP_OUT = "CONTROLLER_STEP_OUT";
export function stepOut() {
return { type: STEP_OUT };
}

export const RESET = "RESET";
export const RESET = "CONTROLLER_RESET";
export function reset() {
return { type: RESET };
}
Expand All @@ -33,7 +33,7 @@ export function interrupt() {
return { type: INTERRUPT };
}

export const CONTINUE = "CONTINUE";
export const CONTINUE = "CONTROLLER_CONTINUE";
export function continueUntilBreakpoint(breakpoints) {
//"continue" is not a legal name
return {
Expand All @@ -42,37 +42,37 @@ export function continueUntilBreakpoint(breakpoints) {
};
}

export const ADD_BREAKPOINT = "ADD_BREAKPOINT";
export const ADD_BREAKPOINT = "CONTROLLER_ADD_BREAKPOINT";
export function addBreakpoint(breakpoint) {
return {
type: ADD_BREAKPOINT,
breakpoint
};
}

export const REMOVE_BREAKPOINT = "REMOVE_BREAKPOINT";
export const REMOVE_BREAKPOINT = "CONTROLLER_REMOVE_BREAKPOINT";
export function removeBreakpoint(breakpoint) {
return {
type: REMOVE_BREAKPOINT,
breakpoint
};
}

export const REMOVE_ALL_BREAKPOINTS = "REMOVE_ALL_BREAKPOINTS";
export const REMOVE_ALL_BREAKPOINTS = "CONTROLLER_REMOVE_ALL_BREAKPOINTS";
export function removeAllBreakpoints() {
return {
type: REMOVE_ALL_BREAKPOINTS
};
}

export const START_STEPPING = "START_STEPPING";
export const START_STEPPING = "CONTROLLER_START_STEPPING";
export function startStepping() {
return {
type: START_STEPPING
};
}

export const DONE_STEPPING = "DONE_STEPPING";
export const DONE_STEPPING = "CONTROLLER_DONE_STEPPING";
export function doneStepping() {
return {
type: DONE_STEPPING
Expand Down
3 changes: 3 additions & 0 deletions packages/debugger/lib/controller/sagas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as trace from "lib/trace/sagas";
import * as data from "lib/data/sagas";
import * as evm from "lib/evm/sagas";
import * as solidity from "lib/solidity/sagas";
import * as stacktrace from "lib/stacktrace/sagas";

import * as actions from "../actions";

Expand Down Expand Up @@ -275,10 +276,12 @@ function* continueUntilBreakpoint(action) {

/**
* reset -- reset the state of the debugger
* (we'll just reset all submodules regardless of which are in use)
*/
export function* reset() {
yield* data.reset();
yield* evm.reset();
yield* solidity.reset();
yield* trace.reset();
yield* stacktrace.reset();
}
12 changes: 6 additions & 6 deletions packages/debugger/lib/data/actions/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const SCOPE = "SCOPE";
export const SCOPE = "DATA_SCOPE";
export function scope(id, pointer, parentId, sourceId, compilationId) {
return {
type: SCOPE,
Expand All @@ -10,7 +10,7 @@ export function scope(id, pointer, parentId, sourceId, compilationId) {
};
}

export const DECLARE = "DECLARE_VARIABLE";
export const DECLARE = "DATA_DECLARE_VARIABLE";
export function declare(node, compilationId) {
return {
type: DECLARE,
Expand All @@ -19,15 +19,15 @@ export function declare(node, compilationId) {
};
}

export const ASSIGN = "ASSIGN";
export const ASSIGN = "DATA_ASSIGN";
export function assign(assignments) {
return {
type: ASSIGN,
assignments
};
}

export const MAP_PATH_AND_ASSIGN = "MAP_PATH_AND_ASSIGN";
export const MAP_PATH_AND_ASSIGN = "DATA_MAP_PATH_AND_ASSIGN";
export function mapPathAndAssign(
address,
slot,
Expand All @@ -50,7 +50,7 @@ export function reset() {
return { type: RESET };
}

export const DEFINE_TYPE = "DEFINE_TYPE";
export const DEFINE_TYPE = "DATA_DEFINE_TYPE";
export function defineType(node, compilationId) {
return {
type: DEFINE_TYPE,
Expand All @@ -59,7 +59,7 @@ export function defineType(node, compilationId) {
};
}

export const ALLOCATE = "ALLOCATE";
export const ALLOCATE = "DATA_ALLOCATE";
export function allocate(storage, memory, abi, state) {
return {
type: ALLOCATE,
Expand Down
10 changes: 6 additions & 4 deletions packages/debugger/lib/debugger.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import traceSelector from "./trace/selectors";
import evmSelector from "./evm/selectors";
import soliditySelector from "./solidity/selectors";
import sessionSelector from "./session/selectors";
import stacktraceSelector from "./stacktrace/selectors";
import controllerSelector from "./controller/selectors";

import { Compilations } from "@truffle/codec";
Expand Down Expand Up @@ -45,11 +46,11 @@ export default class Debugger {
* @return {Debugger} instance
*/
static async forTx(txHash, options = {}) {
let { contracts, files, provider, compilations } = options;
let { contracts, files, provider, compilations, lightMode } = options;
if (!compilations) {
compilations = Compilations.Utils.shimArtifacts(contracts, files);
}
let session = new Session(compilations, provider, txHash);
let session = new Session(compilations, provider, { lightMode }, txHash);

try {
await session.ready();
Expand All @@ -69,11 +70,11 @@ export default class Debugger {
* @return {Debugger} instance
*/
static async forProject(options = {}) {
let { contracts, files, provider, compilations } = options;
let { contracts, files, provider, compilations, lightMode } = options;
if (!compilations) {
compilations = Compilations.Utils.shimArtifacts(contracts, files);
}
let session = new Session(compilations, provider);
let session = new Session(compilations, provider, { lightMode });

await session.ready();

Expand Down Expand Up @@ -110,6 +111,7 @@ export default class Debugger {
trace: traceSelector,
evm: evmSelector,
solidity: soliditySelector,
stacktrace: stacktraceSelector,
session: sessionSelector,
controller: controllerSelector
});
Expand Down
Loading

0 comments on commit eb5b18d

Please sign in to comment.