1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

Enable more verbose TVM stack dump (#669)

* Verbose stack dump

* Move vm::VmLog::DumpStack and vm::VmLog::DumpStackVerbose to the next verbosity levels
This commit is contained in:
Marat 2023-05-24 10:39:15 +01:00 committed by GitHub
parent 506cd5ee36
commit 86623b4cea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 116 additions and 17 deletions

View file

@ -1081,7 +1081,13 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
if (cfg.vm_log_verbosity > 1) { if (cfg.vm_log_verbosity > 1) {
vm_log.log_mask |= vm::VmLog::ExecLocation; vm_log.log_mask |= vm::VmLog::ExecLocation;
if (cfg.vm_log_verbosity > 2) { if (cfg.vm_log_verbosity > 2) {
vm_log.log_mask |= vm::VmLog::DumpStack | vm::VmLog::GasRemaining; vm_log.log_mask |= vm::VmLog::GasRemaining;
if (cfg.vm_log_verbosity > 3) {
vm_log.log_mask |= vm::VmLog::DumpStack;
if (cfg.vm_log_verbosity > 4) {
vm_log.log_mask |= vm::VmLog::DumpStackVerbose;
}
}
} }
} }
} }

View file

@ -185,7 +185,13 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
if (vm_log_verbosity > 1) { if (vm_log_verbosity > 1) {
log.log_mask |= vm::VmLog::ExecLocation; log.log_mask |= vm::VmLog::ExecLocation;
if (vm_log_verbosity > 2) { if (vm_log_verbosity > 2) {
log.log_mask |= vm::VmLog::DumpStack | vm::VmLog::GasRemaining; log.log_mask |= vm::VmLog::GasRemaining;
if (vm_log_verbosity > 3) {
log.log_mask |= vm::VmLog::DumpStack;
if (vm_log_verbosity > 4) {
log.log_mask |= vm::VmLog::DumpStackVerbose;
}
}
} }
} }

View file

@ -22,6 +22,8 @@
#include "vm/log.h" #include "vm/log.h"
#include "vm/vm.h" #include "vm/vm.h"
#include "vm/vmstate.h" #include "vm/vmstate.h"
#include "vm/boc.h"
#include "td/utils/misc.h"
namespace vm { namespace vm {
@ -254,6 +256,16 @@ bool Continuation::deserialize_to(Ref<Cell> cell, Ref<Continuation>& cont, int m
return deserialize_to(cs, cont, mode & ~0x1000) && cs.empty_ext(); return deserialize_to(cs, cont, mode & ~0x1000) && cs.empty_ext();
} }
std::ostream& operator<<(std::ostream& os, const Continuation& cont) {
CellBuilder cb;
if (cont.serialize(cb)) {
auto boc = vm::std_boc_serialize(cb.finalize());
if (boc.is_ok()) {
os << td::buffer_to_hex(boc.move_as_ok().as_slice());
}
}
}
bool QuitCont::serialize(CellBuilder& cb) const { bool QuitCont::serialize(CellBuilder& cb) const {
// vmc_quit$1000 exit_code:int32 = VmCont; // vmc_quit$1000 exit_code:int32 = VmCont;
return cb.store_long_bool(8, 4) && cb.store_long_bool(exit_code, 32); return cb.store_long_bool(8, 4) && cb.store_long_bool(exit_code, 32);
@ -269,6 +281,10 @@ Ref<QuitCont> QuitCont::deserialize(CellSlice& cs, int mode) {
} }
} }
std::string QuitCont::type() const {
return "vmc_quit";
}
int ExcQuitCont::jump(VmState* st) const & { int ExcQuitCont::jump(VmState* st) const & {
int n = 0; int n = 0;
try { try {
@ -280,6 +296,10 @@ int ExcQuitCont::jump(VmState* st) const & {
return ~n; return ~n;
} }
std::string ExcQuitCont::type() const {
return "vmc_quit_exc";
}
bool ExcQuitCont::serialize(CellBuilder& cb) const { bool ExcQuitCont::serialize(CellBuilder& cb) const {
// vmc_quit_exc$1001 = VmCont; // vmc_quit_exc$1001 = VmCont;
return cb.store_long_bool(9, 4); return cb.store_long_bool(9, 4);
@ -302,6 +322,10 @@ int PushIntCont::jump_w(VmState* st) & {
return st->jump(std::move(next)); return st->jump(std::move(next));
} }
std::string PushIntCont::type() const {
return "vmc_pushint";
}
bool PushIntCont::serialize(CellBuilder& cb) const { bool PushIntCont::serialize(CellBuilder& cb) const {
// vmc_pushint$1111 value:int32 next:^VmCont = VmCont; // vmc_pushint$1111 value:int32 next:^VmCont = VmCont;
return cb.store_long_bool(15, 4) && cb.store_long_bool(push_val, 32) && next->serialize_ref(cb); return cb.store_long_bool(15, 4) && cb.store_long_bool(push_val, 32) && next->serialize_ref(cb);
@ -353,6 +377,10 @@ Ref<ArgContExt> ArgContExt::deserialize(CellSlice& cs, int mode) {
: Ref<ArgContExt>{}; : Ref<ArgContExt>{};
} }
std::string ArgContExt::type() const {
return "vmc_envelope";
}
int RepeatCont::jump(VmState* st) const & { int RepeatCont::jump(VmState* st) const & {
VM_LOG(st) << "repeat " << count << " more times (slow)\n"; VM_LOG(st) << "repeat " << count << " more times (slow)\n";
if (count <= 0) { if (count <= 0) {
@ -401,6 +429,10 @@ Ref<RepeatCont> RepeatCont::deserialize(CellSlice& cs, int mode) {
} }
} }
std::string RepeatCont::type() const {
return "vmc_repeat";
}
int VmState::repeat(Ref<Continuation> body, Ref<Continuation> after, long long count) { int VmState::repeat(Ref<Continuation> body, Ref<Continuation> after, long long count) {
if (count <= 0) { if (count <= 0) {
body.clear(); body.clear();
@ -444,6 +476,10 @@ Ref<AgainCont> AgainCont::deserialize(CellSlice& cs, int mode) {
} }
} }
std::string AgainCont::type() const {
return "vmc_again";
}
int VmState::again(Ref<Continuation> body) { int VmState::again(Ref<Continuation> body) {
return jump(Ref<AgainCont>{true, std::move(body)}); return jump(Ref<AgainCont>{true, std::move(body)});
} }
@ -493,6 +529,10 @@ Ref<UntilCont> UntilCont::deserialize(CellSlice& cs, int mode) {
} }
} }
std::string UntilCont::type() const {
return "vmc_until";
}
int VmState::until(Ref<Continuation> body, Ref<Continuation> after) { int VmState::until(Ref<Continuation> body, Ref<Continuation> after) {
if (!body->has_c0()) { if (!body->has_c0()) {
set_c0(Ref<UntilCont>{true, body, std::move(after)}); set_c0(Ref<UntilCont>{true, body, std::move(after)});
@ -575,6 +615,10 @@ Ref<WhileCont> WhileCont::deserialize(CellSlice& cs, int mode) {
} }
} }
std::string WhileCont::type() const {
return chkcond ? "vmc_while_cond" : "vmc_while_body";
}
int VmState::loop_while(Ref<Continuation> cond, Ref<Continuation> body, Ref<Continuation> after) { int VmState::loop_while(Ref<Continuation> cond, Ref<Continuation> body, Ref<Continuation> after) {
if (!cond->has_c0()) { if (!cond->has_c0()) {
set_c0(Ref<WhileCont>{true, cond, std::move(body), std::move(after), true}); set_c0(Ref<WhileCont>{true, cond, std::move(body), std::move(after), true});
@ -610,4 +654,8 @@ Ref<OrdCont> OrdCont::deserialize(CellSlice& cs, int mode) {
: Ref<OrdCont>{}; : Ref<OrdCont>{};
} }
std::string OrdCont::type() const {
return "vmc_std";
}
} // namespace vm } // namespace vm

View file

@ -191,8 +191,11 @@ class Continuation : public td::CntObject {
return (cont = deserialize(cs, mode)).not_null(); return (cont = deserialize(cs, mode)).not_null();
} }
static bool deserialize_to(Ref<Cell> cell, Ref<Continuation>& cont, int mode = 0); static bool deserialize_to(Ref<Cell> cell, Ref<Continuation>& cont, int mode = 0);
virtual std::string type() const = 0;
}; };
std::ostream& operator<<(std::ostream& os, const Continuation& cont);
class QuitCont : public Continuation { class QuitCont : public Continuation {
int exit_code; int exit_code;
@ -205,6 +208,7 @@ class QuitCont : public Continuation {
} }
bool serialize(CellBuilder& cb) const override; bool serialize(CellBuilder& cb) const override;
static Ref<QuitCont> deserialize(CellSlice& cs, int mode = 0); static Ref<QuitCont> deserialize(CellSlice& cs, int mode = 0);
std::string type() const override;
}; };
class ExcQuitCont : public Continuation { class ExcQuitCont : public Continuation {
@ -214,6 +218,7 @@ class ExcQuitCont : public Continuation {
int jump(VmState* st) const & override; int jump(VmState* st) const & override;
bool serialize(CellBuilder& cb) const override; bool serialize(CellBuilder& cb) const override;
static Ref<ExcQuitCont> deserialize(CellSlice& cs, int mode = 0); static Ref<ExcQuitCont> deserialize(CellSlice& cs, int mode = 0);
std::string type() const override;
}; };
class PushIntCont : public Continuation { class PushIntCont : public Continuation {
@ -228,6 +233,7 @@ class PushIntCont : public Continuation {
int jump_w(VmState* st) & override; int jump_w(VmState* st) & override;
bool serialize(CellBuilder& cb) const override; bool serialize(CellBuilder& cb) const override;
static Ref<PushIntCont> deserialize(CellSlice& cs, int mode = 0); static Ref<PushIntCont> deserialize(CellSlice& cs, int mode = 0);
std::string type() const override;
}; };
class RepeatCont : public Continuation { class RepeatCont : public Continuation {
@ -243,6 +249,7 @@ class RepeatCont : public Continuation {
int jump_w(VmState* st) & override; int jump_w(VmState* st) & override;
bool serialize(CellBuilder& cb) const override; bool serialize(CellBuilder& cb) const override;
static Ref<RepeatCont> deserialize(CellSlice& cs, int mode = 0); static Ref<RepeatCont> deserialize(CellSlice& cs, int mode = 0);
std::string type() const override;
}; };
class AgainCont : public Continuation { class AgainCont : public Continuation {
@ -256,6 +263,7 @@ class AgainCont : public Continuation {
int jump_w(VmState* st) & override; int jump_w(VmState* st) & override;
bool serialize(CellBuilder& cb) const override; bool serialize(CellBuilder& cb) const override;
static Ref<AgainCont> deserialize(CellSlice& cs, int mode = 0); static Ref<AgainCont> deserialize(CellSlice& cs, int mode = 0);
std::string type() const override;
}; };
class UntilCont : public Continuation { class UntilCont : public Continuation {
@ -269,6 +277,7 @@ class UntilCont : public Continuation {
int jump_w(VmState* st) & override; int jump_w(VmState* st) & override;
bool serialize(CellBuilder& cb) const override; bool serialize(CellBuilder& cb) const override;
static Ref<UntilCont> deserialize(CellSlice& cs, int mode = 0); static Ref<UntilCont> deserialize(CellSlice& cs, int mode = 0);
std::string type() const override;
}; };
class WhileCont : public Continuation { class WhileCont : public Continuation {
@ -284,6 +293,7 @@ class WhileCont : public Continuation {
int jump_w(VmState* st) & override; int jump_w(VmState* st) & override;
bool serialize(CellBuilder& cb) const override; bool serialize(CellBuilder& cb) const override;
static Ref<WhileCont> deserialize(CellSlice& cs, int mode = 0); static Ref<WhileCont> deserialize(CellSlice& cs, int mode = 0);
std::string type() const override;
}; };
class ArgContExt : public Continuation { class ArgContExt : public Continuation {
@ -315,6 +325,7 @@ class ArgContExt : public Continuation {
} }
bool serialize(CellBuilder& cb) const override; bool serialize(CellBuilder& cb) const override;
static Ref<ArgContExt> deserialize(CellSlice& cs, int mode = 0); static Ref<ArgContExt> deserialize(CellSlice& cs, int mode = 0);
std::string type() const override;
}; };
class OrdCont : public Continuation { class OrdCont : public Continuation {
@ -369,6 +380,7 @@ class OrdCont : public Continuation {
} }
bool serialize(CellBuilder& cb) const override; bool serialize(CellBuilder& cb) const override;
static Ref<OrdCont> deserialize(CellSlice& cs, int mode = 0); static Ref<OrdCont> deserialize(CellSlice& cs, int mode = 0);
std::string type() const override;
}; };
ControlData* force_cdata(Ref<Continuation>& cont); ControlData* force_cdata(Ref<Continuation>& cont);

View file

@ -31,7 +31,7 @@ namespace vm {
struct VmLog { struct VmLog {
td::LogInterface *log_interface{td::log_interface}; td::LogInterface *log_interface{td::log_interface};
td::LogOptions log_options{td::log_options}; td::LogOptions log_options{td::log_options};
enum { DumpStack = 2, ExecLocation = 4, GasRemaining = 8 }; enum { DumpStack = 2, ExecLocation = 4, GasRemaining = 8, DumpStackVerbose = 16 };
int log_mask{1}; int log_mask{1};
static VmLog Null() { static VmLog Null() {
VmLog res; VmLog res;

View file

@ -21,6 +21,8 @@
#include "vm/box.hpp" #include "vm/box.hpp"
#include "vm/atom.h" #include "vm/atom.h"
#include "vm/vmstate.h" #include "vm/vmstate.h"
#include "vm/boc.h"
#include "td/utils/misc.h"
namespace td { namespace td {
template class td::Cnt<std::string>; template class td::Cnt<std::string>;
@ -81,7 +83,7 @@ std::string StackEntry::to_lisp_string() const {
return std::move(os).str(); return std::move(os).str();
} }
void StackEntry::dump(std::ostream& os) const { void StackEntry::dump(std::ostream& os, bool verbose) const {
switch (tp) { switch (tp) {
case t_null: case t_null:
os << "(null)"; os << "(null)";
@ -91,14 +93,23 @@ void StackEntry::dump(std::ostream& os) const {
break; break;
case t_cell: case t_cell:
if (ref.not_null()) { if (ref.not_null()) {
os << "C{" << static_cast<Ref<Cell>>(ref)->get_hash().to_hex() << "}"; if (verbose) {
std::string serialized = "???";
auto boc = vm::std_boc_serialize(as_cell());
if (boc.is_ok()) {
serialized = td::buffer_to_hex(boc.move_as_ok().as_slice());
}
os << "C{" << serialized << "}";
} else {
os << "C{" << *as_cell() << "}";
}
} else { } else {
os << "C{null}"; os << "C{null}";
} }
break; break;
case t_builder: case t_builder:
if (ref.not_null()) { if (ref.not_null()) {
os << "BC{" << static_cast<Ref<CellBuilder>>(ref)->to_hex() << "}"; os << "BC{" << *as_builder() << "}";
} else { } else {
os << "BC{null}"; os << "BC{null}";
} }
@ -149,12 +160,24 @@ void StackEntry::dump(std::ostream& os) const {
os << "Object{" << (const void*)&*ref << "}"; os << "Object{" << (const void*)&*ref << "}";
break; break;
} }
case t_vmcont: {
if (ref.not_null()) {
if (verbose) {
os << "Cont{" << *as_cont() << "}";
} else {
os << "Cont{" << as_cont()->type() << "}";
}
} else {
os << "Cont{null}";
}
break;
}
default: default:
os << "???"; os << "???";
} }
} }
void StackEntry::print_list(std::ostream& os) const { void StackEntry::print_list(std::ostream& os, bool verbose) const {
switch (tp) { switch (tp) {
case t_null: case t_null:
os << "()"; os << "()";
@ -163,7 +186,7 @@ void StackEntry::print_list(std::ostream& os) const {
const auto& tuple = *static_cast<Ref<Tuple>>(ref); const auto& tuple = *static_cast<Ref<Tuple>>(ref);
if (is_list()) { if (is_list()) {
os << '('; os << '(';
tuple[0].print_list(os); tuple[0].print_list(os, verbose);
print_list_tail(os, &tuple[1]); print_list_tail(os, &tuple[1]);
break; break;
} }
@ -172,7 +195,7 @@ void StackEntry::print_list(std::ostream& os) const {
os << "[]"; os << "[]";
} else if (n == 1) { } else if (n == 1) {
os << "["; os << "[";
tuple[0].print_list(os); tuple[0].print_list(os, verbose);
os << "]"; os << "]";
} else { } else {
os << "["; os << "[";
@ -181,14 +204,14 @@ void StackEntry::print_list(std::ostream& os) const {
if (c++) { if (c++) {
os << " "; os << " ";
} }
entry.print_list(os); entry.print_list(os, verbose);
} }
os << ']'; os << ']';
} }
break; break;
} }
default: default:
dump(os); dump(os, verbose);
} }
} }
@ -687,12 +710,12 @@ void Stack::dump(std::ostream& os, int mode) const {
os << " [ "; os << " [ ";
if (mode & 2) { if (mode & 2) {
for (const auto& x : stack) { for (const auto& x : stack) {
x.print_list(os); x.print_list(os, mode & 4);
os << ' '; os << ' ';
} }
} else { } else {
for (const auto& x : stack) { for (const auto& x : stack) {
x.dump(os); x.dump(os, mode & 4);
os << ' '; os << ' ';
} }
} }

View file

@ -292,8 +292,8 @@ class StackEntry {
} }
bool for_each_scalar(const std::function<bool(const StackEntry&)>& func) const; bool for_each_scalar(const std::function<bool(const StackEntry&)>& func) const;
void for_each_scalar(const std::function<void(const StackEntry&)>& func) const; void for_each_scalar(const std::function<void(const StackEntry&)>& func) const;
void dump(std::ostream& os) const; void dump(std::ostream& os, bool verbose = false) const;
void print_list(std::ostream& os) const; void print_list(std::ostream& os, bool verbose = false) const;
std::string to_string() const; std::string to_string() const;
std::string to_lisp_string() const; std::string to_lisp_string() const;
@ -558,7 +558,7 @@ class Stack : public td::CntObject {
} }
bool for_each_scalar(const std::function<bool(const StackEntry&)>& func) const; bool for_each_scalar(const std::function<bool(const StackEntry&)>& func) const;
void for_each_scalar(const std::function<void(const StackEntry&)>& func) const; void for_each_scalar(const std::function<void(const StackEntry&)>& func) const;
// mode: +1 = add eoln, +2 = Lisp-style lists // mode: +1 = add eoln, +2 = Lisp-style lists, +4 = serialized bocs
void dump(std::ostream& os, int mode = 1) const; void dump(std::ostream& os, int mode = 1) const;
bool serialize(vm::CellBuilder& cb, int mode = 0) const; bool serialize(vm::CellBuilder& cb, int mode = 0) const;
bool deserialize(vm::CellSlice& cs, int mode = 0); bool deserialize(vm::CellSlice& cs, int mode = 0);

View file

@ -435,7 +435,11 @@ int VmState::step() {
CHECK(code.not_null() && stack.not_null()); CHECK(code.not_null() && stack.not_null());
if (log.log_mask & vm::VmLog::DumpStack) { if (log.log_mask & vm::VmLog::DumpStack) {
std::stringstream ss; std::stringstream ss;
stack->dump(ss, 3); int mode = 3;
if (log.log_mask & vm::VmLog::DumpStackVerbose) {
mode += 4;
}
stack->dump(ss, mode);
VM_LOG(this) << "stack:" << ss.str(); VM_LOG(this) << "stack:" << ss.str();
} }
if (stack_trace) { if (stack_trace) {