Skip to content

Commit

Permalink
Implement stack trace API (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
rossberg authored May 16, 2019
1 parent 96d346c commit dc8cc29
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 4 deletions.
31 changes: 31 additions & 0 deletions example/trap.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ own wasm_trap_t* fail_callback(
}


void print_frame(wasm_frame_t* frame) {
printf("> %p @ 0x%zx = %"PRIu32".0x%zx\n",
wasm_frame_instance(frame),
wasm_frame_module_offset(frame),
wasm_frame_func_index(frame),
wasm_frame_func_offset(frame)
);
}


int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
Expand Down Expand Up @@ -104,6 +114,27 @@ int main(int argc, const char* argv[]) {
wasm_trap_message(trap, &message);
printf("> %s\n", message.data);

printf("Printing origin...\n");
own wasm_frame_t* frame = wasm_trap_origin(trap);
if (frame) {
print_frame(frame);
wasm_frame_delete(frame);
} else {
printf("> Empty origin.\n");
}

printf("Printing trace...\n");
own wasm_frame_vec_t trace;
wasm_trap_trace(trap, &trace);
if (trace.size > 0) {
for (size_t i = 0; i < trace.size; ++i) {
print_frame(trace.data[i]);
}
} else {
printf("> Empty trace.\n");
}

wasm_frame_vec_delete(&trace);
wasm_trap_delete(trap);
wasm_name_delete(&message);
}
Expand Down
26 changes: 26 additions & 0 deletions example/trap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ auto fail_callback(
}


void print_frame(const wasm::Frame* frame) {
std::cout << "> " << frame->instance();
std::cout << " @ 0x" << std::hex << frame->module_offset();
std::cout << " = " << frame->func_index();
std::cout << ".0x" << std::hex << frame->func_offset() << std::endl;
}


void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
Expand Down Expand Up @@ -85,6 +93,24 @@ void run() {

std::cout << "Printing message..." << std::endl;
std::cout << "> " << trap->message().get() << std::endl;

std::cout << "Printing origin..." << std::endl;
auto frame = trap->origin();
if (frame) {
print_frame(frame.get());
} else {
std::cout << "> Empty origin." << std::endl;
}

std::cout << "Printing trace..." << std::endl;
auto trace = trap->trace();
if (trace.size() > 0) {
for (size_t i = 0; i < trace.size(); ++i) {
print_frame(trace[i].get());
}
} else {
std::cout << "> Empty trace." << std::endl;
}
}

// Shut down.
Expand Down
14 changes: 14 additions & 0 deletions include/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,18 @@ WASM_DECLARE_VEC(val, )
WASM_DECLARE_REF_BASE(ref)


// Frames

WASM_DECLARE_OWN(frame)
WASM_DECLARE_VEC(frame, *)
own wasm_frame_t* wasm_frame_copy(const wasm_frame_t*);

struct wasm_instance_t* wasm_frame_instance(const wasm_frame_t*);
uint32_t wasm_frame_func_index(const wasm_frame_t*);
size_t wasm_frame_func_offset(const wasm_frame_t*);
size_t wasm_frame_module_offset(const wasm_frame_t*);


// Traps

typedef wasm_name_t wasm_message_t; // null terminated
Expand All @@ -354,6 +366,8 @@ WASM_DECLARE_REF(trap)
own wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t*);

void wasm_trap_message(const wasm_trap_t*, own wasm_message_t* out);
own wasm_frame_t* wasm_trap_origin(const wasm_trap_t*);
void wasm_trap_trace(const wasm_trap_t*, own wasm_frame_vec_t* out);


// Foreign Objects
Expand Down
18 changes: 18 additions & 0 deletions include/wasm.hh
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,22 @@ template<> inline auto Val::get<uint64_t>() const -> uint64_t {

using Message = vec<byte_t>; // null terminated

class Instance;

class Frame {
public:
Frame() = delete;
~Frame();
void operator delete(void*);

auto copy() const -> own<Frame*>;

auto instance() const -> Instance*;
auto func_index() const -> uint32_t;
auto func_offset() const -> size_t;
auto module_offset() const -> size_t;
};

class Trap : public Ref {
public:
Trap() = delete;
Expand All @@ -593,6 +609,8 @@ public:
auto copy() const -> own<Trap*>;

auto message() const -> Message;
auto origin() const -> own<Frame*>; // may be null
auto trace() const -> vec<Frame*>; // may be empty, origin first
};


Expand Down
38 changes: 38 additions & 0 deletions src/wasm-c.cc
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,31 @@ void wasm_val_copy(wasm_val_t* out, const wasm_val_t* v) {
///////////////////////////////////////////////////////////////////////////////
// Runtime Objects

// Frames

WASM_DEFINE_OWN(frame, Frame)
WASM_DEFINE_VEC(frame, Frame, *)

wasm_frame_t* wasm_frame_copy(const wasm_frame_t* frame) {
return release(frame->copy());
}

wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame);
// Defined below along with wasm_instance_t.

uint32_t wasm_frame_func_index(const wasm_frame_t* frame) {
return reveal(frame)->func_index();
}

size_t wasm_frame_func_offset(const wasm_frame_t* frame) {
return reveal(frame)->func_offset();
}

size_t wasm_frame_module_offset(const wasm_frame_t* frame) {
return reveal(frame)->module_offset();
}


// Traps

WASM_DEFINE_REF(trap, Trap)
Expand All @@ -681,6 +706,14 @@ void wasm_trap_message(const wasm_trap_t* trap, wasm_message_t* out) {
*out = release(reveal(trap)->message());
}

wasm_frame_t* wasm_trap_origin(const wasm_trap_t* trap) {
return release(reveal(trap)->origin());
}

void wasm_trap_trace(const wasm_trap_t* trap, wasm_frame_vec_t* out) {
*out = release(reveal(trap)->trace());
}


// Foreign Objects

Expand Down Expand Up @@ -982,4 +1015,9 @@ void wasm_instance_exports(
*out = release(instance->exports());
}


wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) {
return hide(reveal(frame)->instance());
}

} // extern "C"
79 changes: 75 additions & 4 deletions src/wasm-v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ namespace v8 {
extern bool FLAG_experimental_wasm_mv;
extern bool FLAG_experimental_wasm_anyref;
extern bool FLAG_experimental_wasm_bulk_memory;
extern bool FLAG_experimental_wasm_return_call;
}
}

Expand Down Expand Up @@ -68,7 +69,7 @@ auto seal(const typename implement <C>::type* x) -> const C* {

struct Stats {
enum category_t {
BYTE, CONFIG, ENGINE, STORE,
BYTE, CONFIG, ENGINE, STORE, FRAME,
VALTYPE, FUNCTYPE, GLOBALTYPE, TABLETYPE, MEMORYTYPE,
EXTERNTYPE, IMPORTTYPE, EXPORTTYPE,
VAL, REF, TRAP,
Expand Down Expand Up @@ -176,7 +177,7 @@ struct Stats {

#ifdef DEBUG
const char* Stats::name[STRONG_COUNT] = {
"byte_t", "Config", "Engine", "Store",
"byte_t", "Config", "Engine", "Store", "Frame",
"ValType", "FuncType", "GlobalType", "TableType", "MemoryType",
"ExternType", "ImportType", "ExportType",
"Val", "Ref", "Trap",
Expand Down Expand Up @@ -210,6 +211,7 @@ Stats stats;
}

DEFINE_VEC(byte_t, BYTE)
DEFINE_VEC(Frame*, FRAME)
DEFINE_VEC(ValType*, VALTYPE)
DEFINE_VEC(FuncType*, FUNCTYPE)
DEFINE_VEC(GlobalType*, GLOBALTYPE)
Expand Down Expand Up @@ -295,8 +297,9 @@ auto Engine::make(own<Config*>&& config) -> own<Engine*> {
v8::internal::FLAG_expose_gc = true;
v8::internal::FLAG_experimental_wasm_bigint = true;
v8::internal::FLAG_experimental_wasm_mv = true;
// v8::internal::FLAG_experimental_wasm_anyref = true;
// v8::internal::FLAG_experimental_wasm_bulk_memory = true;
v8::internal::FLAG_experimental_wasm_anyref = true;
v8::internal::FLAG_experimental_wasm_bulk_memory = true;
v8::internal::FLAG_experimental_wasm_return_call = true;
// v8::V8::SetFlagsFromCommandLine(&argc, const_cast<char**>(argv), false);
auto engine = new(std::nothrow) EngineImpl;
if (!engine) return own<Engine*>();
Expand Down Expand Up @@ -1217,6 +1220,64 @@ void Ref::set_host_info(void* info, void (*finalizer)(void*)) {
///////////////////////////////////////////////////////////////////////////////
// Runtime Objects

// Frames

struct FrameImpl {
FrameImpl(
own<Instance*>&& instance, uint32_t func_index,
size_t func_offset, size_t module_offset
) :
instance(std::move(instance)),
func_index(func_index),
func_offset(func_offset),
module_offset(module_offset)
{
stats.make(Stats::FRAME, this);
}

~FrameImpl() { stats.free(Stats::FRAME, this); }

own<Instance*> instance;
uint32_t func_index;
size_t func_offset;
size_t module_offset;
};

template<> struct implement<Frame> { using type = FrameImpl; };


Frame::~Frame() {
impl(this)->~FrameImpl();
}

void Frame::operator delete(void *p) {
::operator delete(p);
}

auto Frame::copy() const -> own<Frame*> {
auto self = impl(this);
return own<Frame*>(seal<Frame>(new(std::nothrow) FrameImpl(
self->instance->copy(), self->func_index, self->func_offset,
self->module_offset)));
}

auto Frame::instance() const -> Instance* {
return impl(this)->instance.get();
}

auto Frame::func_index() const -> uint32_t {
return impl(this)->func_index;
}

auto Frame::func_offset() const -> size_t {
return impl(this)->func_offset;
}

auto Frame::module_offset() const -> size_t {
return impl(this)->module_offset;
}


// Traps

template<> struct implement<Trap> { using type = RefImpl<Trap>; };
Expand Down Expand Up @@ -1249,6 +1310,16 @@ auto Trap::message() const -> Message {
return vec<byte_t>::make(std::string(*string));
}

auto Trap::origin() const -> own<Frame*> {
// TODO(v8): implement
return own<Frame*>(nullptr);
}

auto Trap::trace() const -> vec<Frame*> {
// TODO(v8): implement
return vec<Frame*>::make();
}


// Foreign Objects

Expand Down

0 comments on commit dc8cc29

Please sign in to comment.