1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-12 19:22:37 +00:00
ton/crypto/vm/debugops.cpp

163 lines
5 KiB
C++
Raw Normal View History

2019-09-07 10:03:22 +00:00
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2020 Telegram Systems LLP
2019-09-07 10:03:22 +00:00
*/
#include <functional>
#include "vm/debugops.h"
#include "vm/log.h"
#include "vm/opctable.h"
#include "vm/stack.hpp"
#include "vm/excno.hpp"
#include "vm/vm.h"
2019-09-07 10:03:22 +00:00
namespace vm {
bool vm_debug_enabled = false;
2019-09-07 10:03:22 +00:00
2020-02-08 19:24:24 +00:00
void set_debug_enabled(bool enable_debug) {
vm_debug_enabled = enable_debug;
}
2019-09-07 10:03:22 +00:00
int exec_dummy_debug(VmState* st, int args) {
VM_LOG(st) << "execute DEBUG " << (args & 0xff);
return 0;
}
// similar to PUSHSLICE instruction in cellops.cpp
int exec_dummy_debug_str(VmState* st, CellSlice& cs, unsigned args, int pfx_bits) {
int data_bits = ((args & 15) + 1) * 8;
if (!cs.have(pfx_bits + data_bits)) {
throw VmError{Excno::inv_opcode, "not enough data bits for a DEBUGSTR instruction"};
}
cs.advance(pfx_bits);
auto slice = cs.fetch_subslice(data_bits);
VM_LOG(st) << "execute DEBUGSTR " << slice->as_bitslice().to_hex();
return 0;
}
std::string dump_dummy_debug_str(CellSlice& cs, unsigned args, int pfx_bits) {
int data_bits = ((args & 15) + 1) * 8;
if (!cs.have(pfx_bits + data_bits)) {
return "";
}
cs.advance(pfx_bits);
auto slice = cs.fetch_subslice(data_bits);
slice.unique_write().remove_trailing();
std::ostringstream os;
os << "DEBUGSTR ";
slice->dump_hex(os, 1, false);
return os.str();
}
int compute_len_debug_str(const CellSlice& cs, unsigned args, int pfx_bits) {
unsigned bits = pfx_bits + ((args & 15) + 1) * 8;
return cs.have(bits) ? bits : 0;
}
int exec_dump_stack(VmState* st) {
VM_LOG(st) << "execute DUMPSTK";
2020-02-08 19:24:24 +00:00
if (!vm_debug_enabled) {
return 0;
}
2019-09-07 10:03:22 +00:00
Stack& stack = st->get_stack();
int d = stack.depth();
std::cerr << "#DEBUG#: stack(" << d << " values) : ";
if (d > 255) {
std::cerr << "... ";
d = 255;
}
for (int i = d; i > 0; i--) {
2019-11-15 14:02:37 +00:00
stack[i - 1].print_list(std::cerr);
std::cerr << ' ';
2019-09-07 10:03:22 +00:00
}
std::cerr << std::endl;
return 0;
}
int exec_dump_value(VmState* st, unsigned arg) {
arg &= 15;
VM_LOG(st) << "execute DUMP s" << arg;
2020-02-08 19:24:24 +00:00
if (!vm_debug_enabled) {
return 0;
}
2019-09-07 10:03:22 +00:00
Stack& stack = st->get_stack();
if ((int)arg < stack.depth()) {
2019-11-15 14:02:37 +00:00
std::cerr << "#DEBUG#: s" << arg << " = ";
stack[arg].print_list(std::cerr);
std::cerr << std::endl;
2019-09-07 10:03:22 +00:00
} else {
std::cerr << "#DEBUG#: s" << arg << " is absent" << std::endl;
}
return 0;
}
int exec_dump_string(VmState* st) {
VM_LOG(st) << "execute STRDUMP";
if (!vm_debug_enabled) {
return 0;
}
Stack& stack = st->get_stack();
if (stack.depth() > 0){
auto cs = stack[0].as_slice();
if (cs.not_null()) { // wanted t_slice
auto size = cs->size();
if (size % 8 == 0) {
auto cnt = size / 8;
unsigned char tmp[128];
cs.write().fetch_bytes(tmp, cnt);
std::string s{tmp, tmp + cnt};
std::cerr << "#DEBUG#: " << s << std::endl;
}
else {
std::cerr << "#DEBUG#: slice contains not valid bits count" << std::endl;
}
} else {
std::cerr << "#DEBUG#: is not a slice" << std::endl;
}
} else {
std::cerr << "#DEBUG#: s0 is absent" << std::endl;
}
return 0;
}
2019-09-07 10:03:22 +00:00
void register_debug_ops(OpcodeTable& cp0) {
using namespace std::placeholders;
if (!vm_debug_enabled) {
cp0.insert(OpcodeInstr::mkfixedrange(0xfe00, 0xfef0, 16, 8, instr::dump_1c_and(0xff, "DEBUG "), exec_dummy_debug))
.insert(OpcodeInstr::mkext(0xfef, 12, 4, dump_dummy_debug_str, exec_dummy_debug_str, compute_len_debug_str));
} else {
// NB: all non-redefined opcodes in fe00..feff should be redirected to dummy debug definitions
cp0.insert(OpcodeInstr::mksimple(0xfe00, 16, "DUMPSTK", exec_dump_stack))
.insert(OpcodeInstr::mkfixedrange(0xfe01, 0xfe14, 16, 8, instr::dump_1c_and(0xff, "DEBUG "), exec_dummy_debug))
.insert(OpcodeInstr::mksimple(0xfe14, 16,"STRDUMP", exec_dump_string))
.insert(OpcodeInstr::mkfixedrange(0xfe15, 0xfe20, 16, 8, instr::dump_1c_and(0xff, "DEBUG "), exec_dummy_debug))
2019-09-07 10:03:22 +00:00
.insert(OpcodeInstr::mkfixed(0xfe2, 12, 4, instr::dump_1sr("DUMP"), exec_dump_value))
.insert(OpcodeInstr::mkfixedrange(0xfe30, 0xfef0, 16, 8, instr::dump_1c_and(0xff, "DEBUG "), exec_dummy_debug))
.insert(OpcodeInstr::mkext(0xfef, 12, 4, dump_dummy_debug_str, exec_dummy_debug_str, compute_len_debug_str));
}
}
} // namespace vm