1616#include " include/proxy-wasm/v8.h"
1717
1818#include < cassert>
19-
19+ # include < iomanip >
2020#include < memory>
2121#include < optional>
22+ #include < sstream>
2223#include < utility>
2324#include < vector>
2425
@@ -84,7 +85,9 @@ class V8 : public WasmVm {
8485#undef _GET_MODULE_FUNCTION
8586
8687private:
88+ void buildFunctionNameIndex ();
8789 wasm::vec<byte_t > getStrippedSource ();
90+ std::string getFailMessage (std::string_view function_name, wasm::own<wasm::Trap> trap);
8891
8992 template <typename ... Args>
9093 void registerHostFunctionImpl (std::string_view module_name, std::string_view function_name,
@@ -112,6 +115,8 @@ class V8 : public WasmVm {
112115
113116 absl::flat_hash_map<std::string, FuncDataPtr> host_functions_;
114117 absl::flat_hash_map<std::string, wasm::own<wasm::Func>> module_functions_;
118+
119+ absl::flat_hash_map<uint32_t , std::string> function_names_index_;
115120};
116121
117122// Helper functions.
@@ -263,9 +268,58 @@ bool V8::load(const std::string &code, bool allow_precompiled) {
263268 assert ((shared_module_ != nullptr ));
264269 }
265270
271+ buildFunctionNameIndex ();
272+
266273 return module_ != nullptr ;
267274}
268275
276+ void V8::buildFunctionNameIndex () {
277+ // build function index -> function name map for backtrace
278+ // https://webassembly.github.io/spec/core/appendix/custom.html#binary-namesubsection
279+ auto name_section = getCustomSection (" name" );
280+ if (name_section.size ()) {
281+ const byte_t *pos = name_section.data ();
282+ const byte_t *end = name_section.data () + name_section.size ();
283+ while (pos < end) {
284+ if (*pos++ != 1 ) {
285+ pos += parseVarint (pos, end);
286+ } else {
287+ const auto size = parseVarint (pos, end);
288+ if (size == static_cast <uint32_t >(-1 ) || pos + size > end) {
289+ function_names_index_ = {};
290+ return ;
291+ }
292+ const auto start = pos;
293+ const auto namemap_vector_size = parseVarint (pos, end);
294+ if (namemap_vector_size == static_cast <uint32_t >(-1 ) || pos + namemap_vector_size > end) {
295+ function_names_index_ = {};
296+ return ;
297+ }
298+ for (auto i = 0 ; i < namemap_vector_size; i++) {
299+ const auto func_index = parseVarint (pos, end);
300+ if (func_index == static_cast <uint32_t >(-1 )) {
301+ function_names_index_ = {};
302+ return ;
303+ }
304+
305+ const auto func_name_size = parseVarint (pos, end);
306+ if (func_name_size == static_cast <uint32_t >(-1 ) || pos + func_name_size > end) {
307+ function_names_index_ = {};
308+ return ;
309+ }
310+ function_names_index_.insert ({func_index, std::string (pos, func_name_size)});
311+ pos += func_name_size;
312+ }
313+
314+ if (start + size != pos) {
315+ function_names_index_ = {};
316+ return ;
317+ }
318+ }
319+ }
320+ }
321+ }
322+
269323std::unique_ptr<WasmVm> V8::clone () {
270324 assert (shared_module_ != nullptr );
271325
@@ -274,6 +328,7 @@ std::unique_ptr<WasmVm> V8::clone() {
274328 clone->store_ = wasm::Store::make (engine ());
275329
276330 clone->module_ = wasm::Module::obtain (clone->store_ .get (), shared_module_.get ());
331+ clone->function_names_index_ = function_names_index_;
277332
278333 return clone;
279334}
@@ -500,6 +555,7 @@ bool V8::link(std::string_view debug_name) {
500555 } break ;
501556 }
502557 }
558+
503559 return !isFailed ();
504560}
505561
@@ -618,8 +674,7 @@ void V8::getModuleFunctionImpl(std::string_view function_name,
618674 SaveRestoreContext saved_context (context);
619675 auto trap = func->call (params, nullptr );
620676 if (trap) {
621- fail (FailState::RuntimeError, " Function: " + std::string (function_name) + " failed: " +
622- std::string (trap->message ().get (), trap->message ().size ()));
677+ fail (FailState::RuntimeError, getFailMessage (std::string (function_name), std::move (trap)));
623678 }
624679 };
625680}
@@ -651,15 +706,45 @@ void V8::getModuleFunctionImpl(std::string_view function_name,
651706 SaveRestoreContext saved_context (context);
652707 auto trap = func->call (params, results);
653708 if (trap) {
654- fail (FailState::RuntimeError, " Function: " + std::string (function_name) + " failed: " +
655- std::string (trap->message ().get (), trap->message ().size ()));
709+ fail (FailState::RuntimeError, getFailMessage (std::string (function_name), std::move (trap)));
656710 return R{};
657711 }
658712 R rvalue = results[0 ].get <typename ConvertWordTypeToUint32<R>::type>();
659713 return rvalue;
660714 };
661715}
662716
717+ std::string V8::getFailMessage (std::string_view function_name, wasm::own<wasm::Trap> trap) {
718+ auto message = " Function: " + std::string (function_name) + " failed: " ;
719+ message += std::string (trap->message ().get (), trap->message ().size ());
720+
721+ if (function_names_index_.empty ()) {
722+ return message;
723+ }
724+
725+ auto trace = trap->trace ();
726+ message += " \n Proxy-Wasm plugin in-VM backtrace:" ;
727+ for (size_t i = 0 ; i < trace.size (); ++i) {
728+ auto frame = trace[i].get ();
729+ std::ostringstream oss;
730+ oss << std::setw (3 ) << std::setfill (' ' ) << std::to_string (i);
731+ message += " \n " + oss.str () + " : " ;
732+
733+ std::stringstream address;
734+ address << std::hex << frame->module_offset ();
735+ message += " 0x" + address.str () + " - " ;
736+
737+ auto func_index = frame->func_index ();
738+ auto it = function_names_index_.find (func_index);
739+ if (it != function_names_index_.end ()) {
740+ message += it->second ;
741+ } else {
742+ message += " unknown(function index:" + std::to_string (func_index) + " )" ;
743+ }
744+ }
745+ return message;
746+ }
747+
663748} // namespace
664749
665750std::unique_ptr<WasmVm> createV8Vm () { return std::make_unique<V8>(); }
0 commit comments