mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -04:00
Added Memory Dump app for Debug (#1588)
* Add files via upload * Add files via upload * Added single word read/write support * Add files via upload
This commit is contained in:
parent
2c0446e83d
commit
de937f02d4
@ -277,14 +277,11 @@ RegistersView::RegistersView(
|
|||||||
static_cast<int>(title.size()) * 8, 16});
|
static_cast<int>(title.size()) * 8, 16});
|
||||||
text_title.set(title);
|
text_title.set(title);
|
||||||
|
|
||||||
field_write_reg_num.set_value(0);
|
|
||||||
field_write_reg_num.on_change = [this](SymField&) {
|
field_write_reg_num.on_change = [this](SymField&) {
|
||||||
field_write_data_val.set_value(this->registers_widget.reg_read(field_write_reg_num.to_integer()));
|
field_write_data_val.set_value(this->registers_widget.reg_read(field_write_reg_num.to_integer()));
|
||||||
field_write_data_val.set_dirty();
|
field_write_data_val.set_dirty();
|
||||||
};
|
};
|
||||||
|
|
||||||
field_write_data_val.on_change = [this](SymField&) {};
|
|
||||||
|
|
||||||
const auto value = registers_widget.reg_read(0);
|
const auto value = registers_widget.reg_read(0);
|
||||||
field_write_data_val.set_value(value);
|
field_write_data_val.set_value(value);
|
||||||
|
|
||||||
@ -450,9 +447,10 @@ DebugMenuView::DebugMenuView(NavigationView& nav) {
|
|||||||
{"Buttons Test", ui::Color::dark_cyan(), &bitmap_icon_controls, [&nav]() { nav.push<DebugControlsView>(); }},
|
{"Buttons Test", ui::Color::dark_cyan(), &bitmap_icon_controls, [&nav]() { nav.push<DebugControlsView>(); }},
|
||||||
{"Debug Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { portapack::persistent_memory::debug_dump(); }},
|
{"Debug Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { portapack::persistent_memory::debug_dump(); }},
|
||||||
{"M0 Stack Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { stack_dump(); }},
|
{"M0 Stack Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { stack_dump(); }},
|
||||||
{"Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugMemoryView>(); }},
|
{"Memory Dump", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugMemoryDumpView>(); }},
|
||||||
{"P.Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugPmemView>(); }},
|
{"Memory Usage", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugMemoryView>(); }},
|
||||||
{"Peripherals", ui::Color::dark_cyan(), &bitmap_icon_peripherals, [&nav]() { nav.push<DebugPeripheralsMenuView>(); }},
|
{"Peripherals", ui::Color::dark_cyan(), &bitmap_icon_peripherals, [&nav]() { nav.push<DebugPeripheralsMenuView>(); }},
|
||||||
|
{"Pers. Memory", ui::Color::dark_cyan(), &bitmap_icon_memory, [&nav]() { nav.push<DebugPmemView>(); }},
|
||||||
//{ "Radio State", ui::Color::white(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } },
|
//{ "Radio State", ui::Color::white(), nullptr, [&nav](){ nav.push<NotImplementedView>(); } },
|
||||||
{"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [&nav]() { nav.push<SDCardDebugView>(); }},
|
{"SD Card", ui::Color::dark_cyan(), &bitmap_icon_sdcard, [&nav]() { nav.push<SDCardDebugView>(); }},
|
||||||
{"Temperature", ui::Color::dark_cyan(), &bitmap_icon_temperature, [&nav]() { nav.push<TemperatureView>(); }},
|
{"Temperature", ui::Color::dark_cyan(), &bitmap_icon_temperature, [&nav]() { nav.push<TemperatureView>(); }},
|
||||||
@ -466,6 +464,43 @@ DebugMenuView::DebugMenuView(NavigationView& nav) {
|
|||||||
set_max_rows(2); // allow wider buttons
|
set_max_rows(2); // allow wider buttons
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* DebugMemoryDumpView *********************************************************/
|
||||||
|
|
||||||
|
DebugMemoryDumpView::DebugMemoryDumpView(NavigationView& nav) {
|
||||||
|
add_children({
|
||||||
|
&button_dump,
|
||||||
|
&button_read,
|
||||||
|
&button_write,
|
||||||
|
&button_done,
|
||||||
|
&labels,
|
||||||
|
&field_starting_address,
|
||||||
|
&field_byte_count,
|
||||||
|
&field_rw_address,
|
||||||
|
&field_data_value,
|
||||||
|
});
|
||||||
|
|
||||||
|
button_done.on_select = [&nav](Button&) { nav.pop(); };
|
||||||
|
|
||||||
|
button_dump.on_select = [this](Button&) {
|
||||||
|
if (field_byte_count.to_integer() != 0)
|
||||||
|
memory_dump((uint32_t*)field_starting_address.to_integer(), ((uint32_t)field_byte_count.to_integer() + 3) / 4, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
button_read.on_select = [this](Button&) {
|
||||||
|
field_data_value.set_value(*(uint32_t*)field_rw_address.to_integer());
|
||||||
|
field_data_value.set_dirty();
|
||||||
|
};
|
||||||
|
|
||||||
|
button_write.set_style(&Styles::red);
|
||||||
|
button_write.on_select = [this](Button&) {
|
||||||
|
*(uint32_t*)field_rw_address.to_integer() = (uint32_t)field_data_value.to_integer();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugMemoryDumpView::focus() {
|
||||||
|
button_done.focus();
|
||||||
|
}
|
||||||
|
|
||||||
/* DebugPmemView *********************************************************/
|
/* DebugPmemView *********************************************************/
|
||||||
|
|
||||||
DebugPmemView::DebugPmemView(NavigationView& nav)
|
DebugPmemView::DebugPmemView(NavigationView& nav)
|
||||||
|
@ -48,8 +48,8 @@ class DebugMemoryView : public View {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Text text_title{
|
Text text_title{
|
||||||
{96, 96, 48, 16},
|
{72, 96, 96, 16},
|
||||||
"Memory",
|
"Memory Usage",
|
||||||
};
|
};
|
||||||
|
|
||||||
Text text_label_m0_core_free{
|
Text text_label_m0_core_free{
|
||||||
@ -301,6 +301,58 @@ class DebugControlsView : public View {
|
|||||||
"Done"};
|
"Done"};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DebugMemoryDumpView : public View {
|
||||||
|
public:
|
||||||
|
DebugMemoryDumpView(NavigationView& nav);
|
||||||
|
void focus() override;
|
||||||
|
std::string title() const override { return "Memory Dump"; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
Button button_dump{
|
||||||
|
{72, 4 * 16, 96, 24},
|
||||||
|
"Dump"};
|
||||||
|
|
||||||
|
Button button_read{
|
||||||
|
{16, 11 * 16, 96, 24},
|
||||||
|
"Read"};
|
||||||
|
|
||||||
|
Button button_write{
|
||||||
|
{128, 11 * 16, 96, 24},
|
||||||
|
"Write"};
|
||||||
|
|
||||||
|
Button button_done{
|
||||||
|
{128, 240, 96, 24},
|
||||||
|
"Done"};
|
||||||
|
|
||||||
|
Labels labels{
|
||||||
|
{{5 * 8, 1 * 16}, "Dump Range to File", Color::yellow()},
|
||||||
|
{{0 * 8, 2 * 16}, "Starting Address: 0x", Color::light_grey()},
|
||||||
|
{{0 * 8, 3 * 16}, "Byte Count: 0x", Color::light_grey()},
|
||||||
|
{{3 * 8, 8 * 16}, "Read/Write Single Word", Color::yellow()},
|
||||||
|
{{0 * 8, 9 * 16}, "Memory Address: 0x", Color::light_grey()},
|
||||||
|
{{0 * 8, 10 * 16}, "Data Value: 0x", Color::light_grey()}};
|
||||||
|
|
||||||
|
SymField field_starting_address{
|
||||||
|
{20 * 8, 2 * 16},
|
||||||
|
8,
|
||||||
|
SymField::Type::Hex};
|
||||||
|
|
||||||
|
SymField field_byte_count{
|
||||||
|
{20 * 8, 3 * 16},
|
||||||
|
8,
|
||||||
|
SymField::Type::Hex};
|
||||||
|
|
||||||
|
SymField field_rw_address{
|
||||||
|
{20 * 8, 9 * 16},
|
||||||
|
8,
|
||||||
|
SymField::Type::Hex};
|
||||||
|
|
||||||
|
SymField field_data_value{
|
||||||
|
{20 * 8, 10 * 16},
|
||||||
|
8,
|
||||||
|
SymField::Type::Hex};
|
||||||
|
};
|
||||||
|
|
||||||
class DebugPmemView : public View {
|
class DebugPmemView : public View {
|
||||||
public:
|
public:
|
||||||
DebugPmemView(NavigationView& nav);
|
DebugPmemView(NavigationView& nav);
|
||||||
|
@ -258,38 +258,43 @@ void draw_stack_dump() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disk I/O in this function doesn't work after a fault
|
|
||||||
// Using the stack while dumping the stack isn't ideal, but hopefully anything imporant is still on the call stack.
|
|
||||||
bool stack_dump() {
|
bool stack_dump() {
|
||||||
|
uint32_t num_words = &__process_stack_end__ - &__process_stack_base__;
|
||||||
|
return memory_dump(&__process_stack_base__, num_words, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool memory_dump(uint32_t* addr_start, uint32_t num_words, bool stack_flag) {
|
||||||
Painter painter;
|
Painter painter;
|
||||||
std::string debug_dir = "DEBUG";
|
std::string debug_dir = "DEBUG";
|
||||||
std::filesystem::path filename{};
|
std::filesystem::path filename{};
|
||||||
File stack_dump_file{};
|
File dump_file{};
|
||||||
bool error;
|
bool error;
|
||||||
std::string str;
|
std::string str;
|
||||||
|
uint32_t* addr_end;
|
||||||
uint32_t* p;
|
uint32_t* p;
|
||||||
int n{0};
|
int n{0};
|
||||||
bool data_found{false};
|
bool data_found{false};
|
||||||
|
|
||||||
make_new_directory(debug_dir);
|
make_new_directory(debug_dir);
|
||||||
filename = next_filename_matching_pattern(debug_dir + "/STACK_DUMP_????.TXT");
|
filename = next_filename_matching_pattern(debug_dir + "/" + (stack_flag ? "STACK" : "MEMORY") + "_DUMP_????.TXT");
|
||||||
error = filename.empty();
|
error = filename.empty();
|
||||||
if (!error)
|
if (!error)
|
||||||
error = stack_dump_file.create(filename) != 0;
|
error = dump_file.create(filename) != 0;
|
||||||
if (error) {
|
if (error) {
|
||||||
painter.draw_string({16, 320 - 32}, ui::Styles::red, "ERROR DUMPING " + filename.filename().string() + "!");
|
painter.draw_string({16, 320 - 32}, ui::Styles::red, "ERROR DUMPING " + filename.filename().string() + "!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (p = &__process_stack_base__; p < &__process_stack_end__; p++) {
|
addr_end = addr_start + num_words;
|
||||||
|
for (p = addr_start; p < addr_end; p++) {
|
||||||
// skip past unused stack words
|
// skip past unused stack words
|
||||||
if (!data_found) {
|
if (stack_flag && !data_found) {
|
||||||
if (*p == CRT0_STACKS_FILL_PATTERN)
|
if (*p == CRT0_STACKS_FILL_PATTERN)
|
||||||
continue;
|
continue;
|
||||||
else {
|
else {
|
||||||
data_found = true;
|
data_found = true;
|
||||||
auto stack_space_left = p - &__process_stack_base__;
|
auto stack_space_left = p - addr_start;
|
||||||
stack_dump_file.write_line(to_string_hex((uint32_t)&__process_stack_base__, 8) + ": Unused words " + to_string_dec_uint(stack_space_left));
|
dump_file.write_line(to_string_hex((uint32_t)addr_start, 8) + ": Unused words " + to_string_dec_uint(stack_space_left));
|
||||||
|
|
||||||
// align subsequent lines to start on 16-byte boundaries
|
// align subsequent lines to start on 16-byte boundaries
|
||||||
p -= (stack_space_left & 3);
|
p -= (stack_space_left & 3);
|
||||||
@ -299,20 +304,20 @@ bool stack_dump() {
|
|||||||
// write address
|
// write address
|
||||||
if (n++ == 0) {
|
if (n++ == 0) {
|
||||||
str = to_string_hex((uint32_t)p, 8) + ":";
|
str = to_string_hex((uint32_t)p, 8) + ":";
|
||||||
stack_dump_file.write(str.data(), 9);
|
dump_file.write(str.data(), 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write stack dword
|
// write stack dword
|
||||||
str = " " + to_string_hex(*p, 8);
|
str = " " + to_string_hex(*p, 8);
|
||||||
stack_dump_file.write(str.data(), 9);
|
dump_file.write(str.data(), 9);
|
||||||
|
|
||||||
if (n == 4) {
|
if (n == 4) {
|
||||||
stack_dump_file.write("\r\n", 2);
|
dump_file.write("\r\n", 2);
|
||||||
n = 0;
|
n = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
painter.draw_string({16, 320 - 32}, ui::Styles::green, filename.filename().string() + " dumped!");
|
painter.draw_string({0, 320 - 16}, ui::Styles::green, filename.filename().string() + " dumped!");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,5 +48,6 @@ inline uint32_t get_free_stack_space() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool stack_dump();
|
bool stack_dump();
|
||||||
|
bool memory_dump(uint32_t* addr_start, uint32_t num_words, bool stack_flag);
|
||||||
|
|
||||||
#endif /*__DEBUG_H__*/
|
#endif /*__DEBUG_H__*/
|
||||||
|
Loading…
Reference in New Issue
Block a user