Skip to content

Commit 9329a61

Browse files
carllocosCarlos Rojaschscholltolauwae
committed
Feat/inspect (#181)
* notifyBreakpoints prints a virtual address * loadSnapshot functions with virtual addresses - loading the PC happens via virtual address. If PC is invalid a FATAl is thrown - loadings Breakpoints happens via virtual addresses. Invalid breakpoints are ignored - the return address of a frame is a virtual address - for frames that are not functions nor guards, the block_key is passed as a virtual address * removed unneeded interruptOffset By ensuring that the interrupts operate on virtual addresses the interruptOffset becomes unnecessary. * snapshot and dumpFull interrupt print unexisting addresses as -1 - dumpCallstack: prints -1 as callsite address and frame return address if the physical pointer is a nullptr - snapshot prints the nullptr return addresses of frames as -1 - dumpfull_test.cpp and snapshot_test.cpp updates to account for the -1 address * loadingSnapshot accounts for negative return address - loadsnapshot_test.cpp: added tests for negative sp, fp and nullptr return address for frame - snapshot_state_encoder.cpp: encodes nullptr return address of frames as signed integer of value -1 * clang format * name refactor ReceiveState -> ExecutionState * moved enuk above snapshot to avoid comp error * add inspect interrupt + refactor snapshot - added the inspect interrupt that can prints parts of the wasm state depending on the payload - refactored snapshot to use the inspect method. * made executionState public * bug fixes: comma, not zero block key & break - the PC should not print the comma - the callstack state should print 0 and not bt as block key for guard and function frames - the stackstate case was missing the break * add convenience method for printing full errormessages during unit tests * add unit tests for inspect inerrupt * bug fix: inspect prints -1 for nullptr callstack return addresses * bug fix: unit test should have tested for nullptr ret addr * add constructor parameter to InterruptFixture + refactor subclasses - added in the InterruptFixture class a constructor parameter to pass the interrupt nr on construction - All fixtures extending InterruptFixture are refactored to use the new constructor - breakpointinterrupt_test.cpp got further refactor to provide one fixture for addbp and one for remove * refactor: rename memState -> memoryState * refactor: changed inspect interruptNr to 0x09 * add another callback dump dump_callbacks version 2 is different than dump_callbacks in the way how the produced json looks like. This alternative way makes the loading of the snapshots for the callbacks easier. * added callbacks and events as possible state to inspect * snapshot also dumps callbacks and events * loading snapshot can load callbacks mapping * add helper class for nlohmann json objects * refactored inspect_test.cpp to use jsconcompanion class * add tests for inspecting callbacks and events * add test to ensure that a snapshot prints all expected possible states * clang * add string encoder for unit testing * add callbacks encoder for unit testing * add test to ensure that callbackmapping can be loaded * bug fix: string encode encodes the string size as well * add method for sending no payload interrupt + refactor to use method refactor dumpfull_test.cpp to use the new method * bug fix: catch for possible incorrect value conversions * loadsnapshot also loads events if desired * add encoding for events + test to check if events can be loaded * fix interruptInspect and interruptLoadSnapshot number * refactor uint32 and uint8 to hexa string in helper class * bug fix: null termiante buffers and use Serialiser helper class * unit tests bug fix: null terminate strings * Update makefile to work on both mac and linux * Fixup! use $@ --------- Co-authored-by: Carlos Rojas <[email protected]> Co-authored-by: Christophe <[email protected]> Co-authored-by: tolauwae <[email protected]>
1 parent c43f520 commit 9329a61

18 files changed

+888
-180
lines changed

platforms/Arduino/Makefile

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ else
1010
endif
1111

1212
clean:
13-
rm Arduino.ino -f
14-
rm bin -rf
13+
rm -f Arduino.ino
14+
rm -rf bin
1515

1616
bin:
1717
mkdir bin
@@ -25,7 +25,8 @@ endif
2525

2626
Arduino.ino: bin/upload.h Arduino.ino.template
2727
cat Arduino.ino.template > $@
28-
sed -i "s/{{PAUSED}}/$(COMMAND)/" $@
28+
sed "s/{{PAUSED}}/$(COMMAND)/" $@ > Arduino.tmp
29+
mv Arduino.tmp $@
2930

3031

3132
flash: Arduino.ino

src/Debug/debugger.cpp

+184-90
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,14 @@ bool Debugger::checkDebugMessages(Module *m, RunningState *program_state) {
251251
free(interruptData);
252252
snapshot(m);
253253
break;
254+
case interruptInspect: {
255+
uint8_t *data = interruptData + 1;
256+
uint16_t numberBytes = read_B16(&data);
257+
uint8_t *state = interruptData + 3;
258+
inspect(m, numberBytes, state);
259+
free(interruptData);
260+
break;
261+
}
254262
case interruptLoadSnapshot:
255263
if (!this->receivingData) {
256264
*program_state = WARDUINOpause;
@@ -674,97 +682,145 @@ bool Debugger::handlePushedEvent(char *bytes) const {
674682
}
675683

676684
void Debugger::snapshot(Module *m) {
685+
uint16_t numberBytes = 10;
686+
uint8_t state[] = {
687+
pcState, breakpointsState, callstackState, globalsState,
688+
tableState, memoryState, branchingTableState, stackState,
689+
callbacksState, eventsState};
690+
inspect(m, numberBytes, state);
691+
}
692+
693+
void Debugger::inspect(Module *m, uint16_t sizeStateArray, uint8_t *state) {
694+
debug("asked for inspect\n");
695+
uint16_t idx = 0;
677696
auto toVA = [m](uint8_t *addr) { return toVirtualAddress(addr, m); };
678-
debug("asked for doDump\n");
679-
printf("asked for snapshot\n");
697+
bool addComma = false;
698+
680699
this->channel->write("DUMP!\n");
681700
this->channel->write("{");
682701

683-
// current PC
684-
this->channel->write("\"pc\":%" PRIu32 ",", toVA(m->pc_ptr));
685-
686-
this->channel->write("\"breakpoints\":[");
687-
size_t i = 0;
688-
for (auto bp : this->breakpoints) {
689-
this->channel->write("%" PRIu32 "%s", toVA(bp),
690-
(++i < this->breakpoints.size()) ? "," : "");
691-
}
692-
this->channel->write("],");
693-
694-
// stack
695-
this->channel->write("\"stack\":[");
696-
for (int j = 0; j <= m->sp; j++) {
697-
auto v = &m->stack[j];
698-
printValue(v, j, j == m->sp);
699-
}
700-
this->channel->write("],");
701-
702-
// Callstack
703-
this->channel->write("\"callstack\":[");
704-
for (int j = 0; j <= m->csp; j++) {
705-
Frame *f = &m->callstack[j];
706-
uint8_t bt = f->block->block_type;
707-
int ra = f->ra_ptr == nullptr ? -1 : toVA(f->ra_ptr);
708-
uint32_t block_key = (bt == 0 || bt == 0xff || bt == 0xfe)
709-
? 0
710-
: toVA(findOpcode(m, f->block));
711-
this->channel->write(
712-
R"({"type":%u,"fidx":"0x%x","sp":%d,"fp":%d,"idx":%d,)", bt,
713-
f->block->fidx, f->sp, f->fp, j);
714-
this->channel->write("\"block_key\":%" PRIu32 ",\"ra\":%d}%s",
715-
block_key, ra, (j < m->csp) ? "," : "");
716-
}
717-
718-
// Globals
719-
this->channel->write("],\"globals\":[");
720-
for (uint32_t j = 0; j < m->global_count; j++) {
721-
auto v = m->globals + j;
722-
printValue(v, j, j == (m->global_count - 1));
723-
}
724-
this->channel->write("]"); // closing globals
725-
726-
this->channel->write(R"(,"table":{"max":%d, "init":%d, "elements":[)",
727-
m->table.maximum, m->table.initial);
728-
729-
for (uint32_t j = 0; j < m->table.size; j++) {
730-
this->channel->write("%" PRIu32 "%s", m->table.entries[j],
731-
(j + 1) == m->table.size ? "" : ",");
732-
}
733-
this->channel->write("]}"); // closing table
734-
735-
// memory
736-
uint32_t total_elems =
737-
m->memory.pages * (uint32_t)PAGE_SIZE; // TODO debug PAGE_SIZE
738-
this->channel->write(
739-
R"(,"memory":{"pages":%d,"max":%d,"init":%d,"bytes":[)",
740-
m->memory.pages, m->memory.maximum, m->memory.initial);
741-
for (uint32_t j = 0; j < total_elems; j++) {
742-
this->channel->write("%" PRIu8 "%s", m->memory.bytes[j],
743-
(j + 1) == total_elems ? "" : ",");
744-
}
745-
this->channel->write("]}"); // closing memory
702+
while (idx < sizeStateArray) {
703+
switch (state[idx++]) {
704+
case pcState: { // PC
705+
this->channel->write("\"pc\":%" PRIu32 "", toVA(m->pc_ptr));
706+
addComma = true;
746707

747-
this->channel->write(R"(,"br_table":{"size":"0x%x","labels":[)",
748-
BR_TABLE_SIZE);
749-
for (uint32_t j = 0; j < BR_TABLE_SIZE; j++) {
750-
this->channel->write("%" PRIu32 "%s", m->br_table[j],
751-
(j + 1) == BR_TABLE_SIZE ? "" : ",");
708+
break;
709+
}
710+
case breakpointsState: {
711+
this->channel->write("%s\"breakpoints\":[",
712+
addComma ? "," : "");
713+
addComma = true;
714+
size_t i = 0;
715+
for (auto bp : this->breakpoints) {
716+
this->channel->write(
717+
"%" PRIu32 "%s", toVA(bp),
718+
(++i < this->breakpoints.size()) ? "," : "");
719+
}
720+
this->channel->write("]");
721+
break;
722+
}
723+
case callstackState: {
724+
this->channel->write("%s\"callstack\":[", addComma ? "," : "");
725+
addComma = true;
726+
for (int j = 0; j <= m->csp; j++) {
727+
Frame *f = &m->callstack[j];
728+
uint8_t bt = f->block->block_type;
729+
uint32_t block_key = (bt == 0 || bt == 0xff || bt == 0xfe)
730+
? 0
731+
: toVA(findOpcode(m, f->block));
732+
uint32_t fidx = bt == 0 ? f->block->fidx : 0;
733+
int ra = f->ra_ptr == nullptr ? -1 : toVA(f->ra_ptr);
734+
this->channel->write(
735+
R"({"type":%u,"fidx":"0x%x","sp":%d,"fp":%d,"idx":%d,)",
736+
bt, fidx, f->sp, f->fp, j);
737+
this->channel->write(
738+
"\"block_key\":%" PRIu32 ",\"ra\":%d}%s", block_key, ra,
739+
(j < m->csp) ? "," : "");
740+
}
741+
this->channel->write("]");
742+
break;
743+
}
744+
case stackState: {
745+
this->channel->write("%s\"stack\":[", addComma ? "," : "");
746+
addComma = true;
747+
for (int j = 0; j <= m->sp; j++) {
748+
auto v = &m->stack[j];
749+
printValue(v, j, j == m->sp);
750+
}
751+
this->channel->write("]");
752+
break;
753+
}
754+
case globalsState: {
755+
this->channel->write("%s\"globals\":[", addComma ? "," : "");
756+
addComma = true;
757+
for (uint32_t j = 0; j < m->global_count; j++) {
758+
auto v = m->globals + j;
759+
printValue(v, j, j == (m->global_count - 1));
760+
}
761+
this->channel->write("]"); // closing globals
762+
break;
763+
}
764+
case tableState: {
765+
this->channel->write(
766+
R"(%s"table":{"max":%d, "init":%d, "elements":[)",
767+
addComma ? "," : "", m->table.maximum, m->table.initial);
768+
addComma = true;
769+
for (uint32_t j = 0; j < m->table.size; j++) {
770+
this->channel->write("%" PRIu32 "%s", m->table.entries[j],
771+
(j + 1) == m->table.size ? "" : ",");
772+
}
773+
this->channel->write("]}"); // closing table
774+
break;
775+
}
776+
case branchingTableState: {
777+
this->channel->write(
778+
R"(%s"br_table":{"size":"0x%x","labels":[)",
779+
addComma ? "," : "", BR_TABLE_SIZE);
780+
for (uint32_t j = 0; j < BR_TABLE_SIZE; j++) {
781+
this->channel->write("%" PRIu32 "%s", m->br_table[j],
782+
(j + 1) == BR_TABLE_SIZE ? "" : ",");
783+
}
784+
this->channel->write("]}");
785+
break;
786+
}
787+
case memoryState: {
788+
uint32_t total_elems = m->memory.pages * (uint32_t)PAGE_SIZE;
789+
this->channel->write(
790+
R"(%s"memory":{"pages":%d,"max":%d,"init":%d,"bytes":[)",
791+
addComma ? "," : "", m->memory.pages, m->memory.maximum,
792+
m->memory.initial);
793+
addComma = true;
794+
for (uint32_t j = 0; j < total_elems; j++) {
795+
this->channel->write("%" PRIu8 "%s", m->memory.bytes[j],
796+
(j + 1) == total_elems ? "" : ",");
797+
}
798+
this->channel->write("]}"); // closing memory
799+
break;
800+
}
801+
case callbacksState: {
802+
bool noOuterBraces = false;
803+
this->channel->write(
804+
"%s%s", addComma ? "," : "",
805+
CallbackHandler::dump_callbacksV2(noOuterBraces).c_str());
806+
addComma = true;
807+
break;
808+
}
809+
case eventsState: {
810+
this->channel->write("%s", addComma ? "," : "");
811+
this->dumpEvents(0, CallbackHandler::event_count());
812+
addComma = true;
813+
break;
814+
}
815+
default: {
816+
debug("dumpExecutionState: Received unknown state request\n");
817+
break;
818+
}
819+
}
752820
}
753-
this->channel->write("]}}\n");
821+
this->channel->write("}\n");
754822
}
755823

756-
enum ReceiveState {
757-
pcState = 0x01,
758-
breakpointsState = 0x02,
759-
callstackState = 0x03,
760-
globalsState = 0x04,
761-
tblState = 0x05,
762-
memState = 0x06,
763-
brtblState = 0x07,
764-
stackvalsState = 0x08,
765-
pcErrorState = 0x09
766-
};
767-
768824
void Debugger::freeState(Module *m, uint8_t *interruptData) {
769825
debug("freeing the program state\n");
770826
uint8_t *first_msg = nullptr;
@@ -803,7 +859,7 @@ void Debugger::freeState(Module *m, uint8_t *interruptData) {
803859
m->global_count = 0;
804860
break;
805861
}
806-
case tblState: {
862+
case tableState: {
807863
debug("receiving table info\n");
808864
m->table.initial = read_B32(&first_msg);
809865
m->table.maximum = read_B32(&first_msg);
@@ -819,7 +875,7 @@ void Debugger::freeState(Module *m, uint8_t *interruptData) {
819875
m->table.size = 0; // allows to accumulatively add entries
820876
break;
821877
}
822-
case memState: {
878+
case memoryState: {
823879
debug("receiving memory info\n");
824880
// FIXME: init & max not needed
825881
m->memory.maximum = read_B32(&first_msg);
@@ -935,7 +991,7 @@ bool Debugger::saveState(Module *m, uint8_t *interruptData) {
935991
}
936992
break;
937993
}
938-
case globalsState: { // TODO merge globalsState stackvalsState into
994+
case globalsState: { // TODO merge globalsState stackState into
939995
// one case
940996
debug("receiving global state\n");
941997
uint32_t quantity_globals = read_B32(&program_state);
@@ -959,15 +1015,15 @@ bool Debugger::saveState(Module *m, uint8_t *interruptData) {
9591015
}
9601016
break;
9611017
}
962-
case tblState: {
1018+
case tableState: {
9631019
uint32_t quantity = read_B32(&program_state);
9641020
for (size_t i = 0; i < quantity; i++) {
9651021
uint32_t ne = read_B32(&program_state);
9661022
m->table.entries[m->table.size++] = ne;
9671023
}
9681024
break;
9691025
}
970-
case memState: {
1026+
case memoryState: {
9711027
debug("receiving memory\n");
9721028
uint32_t start = read_B32(&program_state);
9731029
uint32_t limit = read_B32(&program_state);
@@ -993,7 +1049,7 @@ bool Debugger::saveState(Module *m, uint8_t *interruptData) {
9931049
program_state += total_bytes;
9941050
break;
9951051
}
996-
case brtblState: {
1052+
case branchingTableState: {
9971053
debug("receiving br_table\n");
9981054
uint16_t begin_index = read_B16(&program_state);
9991055
uint16_t end_index = read_B16(&program_state);
@@ -1012,7 +1068,7 @@ bool Debugger::saveState(Module *m, uint8_t *interruptData) {
10121068
}
10131069
break;
10141070
}
1015-
case stackvalsState: {
1071+
case stackState: {
10161072
// FIXME the float does add numbers at the end. The extra
10171073
// numbers are present in the send information when dump occurs
10181074
debug("receiving stack\n");
@@ -1033,6 +1089,44 @@ bool Debugger::saveState(Module *m, uint8_t *interruptData) {
10331089
}
10341090
break;
10351091
}
1092+
case callbacksState: {
1093+
uint32_t numberMappings = read_B32(&program_state);
1094+
for (auto idx = 0; idx < numberMappings; ++idx) {
1095+
uint32_t callbackKeySize = read_B32(&program_state);
1096+
char *callbackKey = (char *)malloc(callbackKeySize + 1);
1097+
memcpy((void *)callbackKey, program_state, callbackKeySize);
1098+
callbackKey[callbackKeySize] = '\0';
1099+
program_state += callbackKeySize;
1100+
uint32_t numberTableIndexes = read_B32(&program_state);
1101+
for (auto j = 0; j < numberTableIndexes; ++j) {
1102+
uint32_t tidx = read_B32(&program_state);
1103+
std::string key{callbackKey};
1104+
CallbackHandler::add_callback(Callback(m, key, tidx));
1105+
}
1106+
}
1107+
break;
1108+
}
1109+
case eventsState: {
1110+
uint32_t numberEvents = read_B32(&program_state);
1111+
for (auto idx = 0; idx < numberEvents; ++idx) {
1112+
// read topic
1113+
uint32_t topicSize = read_B32(&program_state);
1114+
char *topic = (char *)malloc(topicSize + 1);
1115+
memcpy((void *)topic, program_state, topicSize);
1116+
topic[topicSize] = '\0';
1117+
program_state += topicSize;
1118+
1119+
// read payload
1120+
uint32_t payloadSize = read_B32(&program_state);
1121+
char *payload = (char *)malloc(payloadSize + 1);
1122+
memcpy((void *)payload, program_state, payloadSize);
1123+
payload[payloadSize] = '\0';
1124+
program_state += payloadSize;
1125+
1126+
CallbackHandler::push_event(topic, payload, payloadSize);
1127+
}
1128+
break;
1129+
}
10361130
default: {
10371131
FATAL("saveState: Received unknown program state\n");
10381132
}

0 commit comments

Comments
 (0)