Support for displaying stack on screen after a fault (for debug) (#1416)

* Support for displaying stack on screen after a fault

* Update debug.cpp

* Highlight possible addresses on stack & support Up key

* Add small background white style

* Add small background white style

* Update debug.cpp

* Highlight fault PC in yellow

* Add bg_yellow_small style

* Add bg_yellow_small style

* Clang - trailing space
This commit is contained in:
Mark Thompson 2023-08-29 23:26:58 -05:00 committed by GitHub
parent de81156223
commit 4774b3097f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 144 additions and 14 deletions

View File

@ -50,7 +50,9 @@ void __debug_log(const std::string& msg) {
void runtime_error(uint8_t source); void runtime_error(uint8_t source);
std::string number_to_hex_string(uint32_t); std::string number_to_hex_string(uint32_t);
void draw_line(int32_t, const char*, regarm_t); void draw_line(int32_t, const char*, regarm_t);
void draw_stack_dump();
static bool error_shown = false; static bool error_shown = false;
uint32_t fault_address{0};
void draw_guru_meditation_header(uint8_t source, const char* hint) { void draw_guru_meditation_header(uint8_t source, const char* hint) {
Painter painter; Painter painter;
@ -70,7 +72,7 @@ void draw_guru_meditation_header(uint8_t source, const char* hint) {
if (source == CORTEX_M0) { if (source == CORTEX_M0) {
painter.draw_string({48 + 8, 24}, Styles::white, "0"); painter.draw_string({48 + 8, 24}, Styles::white, "0");
painter.draw_string({12, 320 - 32}, Styles::white, "Press DFU to try Stack Dump"); painter.draw_string({24, 320 - 32}, Styles::white, "Press DFU for Stack Dump");
} }
if (source == CORTEX_M4) if (source == CORTEX_M4)
@ -109,6 +111,7 @@ void draw_guru_meditation(uint8_t source, const char* hint, struct extctx* ctxp,
// to see whats causing the fault. // to see whats causing the fault.
draw_line(80 + i++ * 20, "lr:", ctxp->lr_thd); draw_line(80 + i++ * 20, "lr:", ctxp->lr_thd);
draw_line(80 + i++ * 20, "pc:", ctxp->pc); draw_line(80 + i++ * 20, "pc:", ctxp->pc);
fault_address = (uint32_t)ctxp->pc;
// see SCB_CFSR_* in libopencm3/cm3/scb.h for details // see SCB_CFSR_* in libopencm3/cm3/scb.h for details
if (cfsr != 0) if (cfsr != 0)
@ -127,7 +130,6 @@ void draw_line(int32_t y_offset, const char* label, regarm_t value) {
} }
void runtime_error(uint8_t source) { void runtime_error(uint8_t source) {
bool dumped{false};
LED led = (source == CORTEX_M0) ? hackrf::one::led_rx : hackrf::one::led_tx; LED led = (source == CORTEX_M0) ? hackrf::one::led_rx : hackrf::one::led_tx;
led.off(); led.off();
@ -138,26 +140,133 @@ void runtime_error(uint8_t source) {
; ;
led.toggle(); led.toggle();
// Stack dump is not guaranteed to work in this state, so wait for DFU button press to attempt it // Stack dump will cover entire screen, so wait for DFU button press to attempt it
if (!dumped && (swizzled_switches() & (1 << (int)Switch::Dfu))) { if (swizzled_switches() & (1 << (int)Switch::Dfu)) {
dumped = true; draw_stack_dump();
stack_dump();
} }
} }
} }
// TODO: Fix this function to work after a fault; might need to write to screen instead or to Flash memory. // This function should only be called with interrupts disabled due to reading swizzled_switches()
// Using the stack while dumping the stack isn't ideal, but hopefully anything imporant is still on the call stack.
void draw_stack_dump() {
Painter painter;
uint32_t* p{&__process_stack_base__};
constexpr int border{8};
int x, y;
int n{0};
bool clear_rect{true};
bool first_pass{true};
// NOTE: Stays in this loop forever unless LEFT button pressed
while (1) {
if (clear_rect) {
painter.fill_rectangle(
{border, border, portapack::display.width() - (border * 2), portapack::display.height() - (border * 2)},
Color::black());
x = y = border;
clear_rect = false;
}
// skip past unused stack words on 1st pass
if (first_pass) {
first_pass = false;
while ((*p == CRT0_STACKS_FILL_PATTERN) && (p < &__process_stack_end__))
p++;
auto stack_space_left = p - &__process_stack_base__;
// NOTE: in situations like a hard fault it seems not possible to write strings longer than 16 characters.
painter.draw_string({x, y}, Styles::white_small, to_string_hex((uint32_t)&__process_stack_base__, 8));
x += 8 * 5;
painter.draw_string({x, y}, Styles::white_small, " M0 STACK free=");
x += 15 * 5;
painter.draw_string({x, y}, Styles::white_small, to_string_dec_uint(stack_space_left));
x = border;
y += 8;
// align subsequent lines to start on 16-byte boundaries
p -= (stack_space_left & 3);
}
// print one page of stack dump
while ((p < &__process_stack_end__) && (y < portapack::display.height() - border - 8)) {
// show address if start of line
if (n++ == 0) {
painter.draw_string({x, y}, Styles::white_small, to_string_hex((uint32_t)p, 8) + ":");
x += 9 * 5 - 2; // note: saving 2 pixels here to prevent reaching right border
}
// show stack word -- highlight if a possible code address (low bit will be set too for !thumb) or actual fault address
bool code_addr = (*p > 0x1400) && (*p < 0x80000) && (((*p) & 0x1) == 0x1); // approximate address range of code .text region in ROM
Style style = (fault_address && *p == fault_address) ? Styles::bg_yellow_small : (code_addr ? Styles::bg_white_small : Styles::white_small);
painter.draw_string({x, y}, style, " " + to_string_hex(*p, 8));
x += 9 * 5;
// new line?
if (n == 4) {
n = 0;
x = border;
y += 8;
}
// point to next stack word
p++;
}
// Out of room on the screen or end of stack - allow Up/Down paging.
// First wait for button release from previous press.
// NOTE: can't call swizzle_switches() with interrupted enabled!
while (swizzled_switches() & ((1 << (int)Switch::Right) | (1 << (int)Switch::Left) | (1 << (int)Switch::Down) | (1 << (int)Switch::Up) | (1 << (int)Switch::Sel) | (1 << (int)Switch::Dfu)))
;
painter.draw_string({border, portapack::display.height() - border - 8}, Styles::white_small, "Use UP/DOWN key");
// Wait for button press.
while (1) {
auto switches = swizzled_switches();
// If LEFT button pressed, exit
if (switches & (1 << (int)Switch::Left))
return;
// If DOWN pressed; continue to show next page
if (switches & (1 << (int)Switch::Down))
break;
// If UP pressed, scroll back by one page
if (switches & (1 << (int)Switch::Up)) {
// Back up pointer by offset on this screen plus one full screen of 8 pixels per line & 4 words per line
// (underflow can't happen here due to stack address range in RAM)
p -= ((y - border) + (portapack::display.height() - (border * 2 + 1 * 8))) / (8 / 4);
if (p < &__process_stack_base__)
p = &__process_stack_base__;
break;
}
// If SEL button pressed, try writing to file (likely to hang in fault condition but heh)
if (switches & (1 << (int)Switch::Sel))
stack_dump();
}
// clear screen to allow new range to be displayed, if we're not at the end
if (p < &__process_stack_end__)
clear_rect = true;
}
}
// 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. // 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() {
ui::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 stack_dump_file{};
bool error; bool error;
std::string str; std::string str;
uint32_t* p; uint32_t* p;
int n; int n{0};
bool data_found; 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_DUMP_????.TXT");
@ -169,25 +278,28 @@ bool stack_dump() {
return false; return false;
} }
for (p = &__process_stack_base__, n = 0, data_found = false; p < &__process_stack_end__; p++) { for (p = &__process_stack_base__; p < &__process_stack_end__; p++) {
// skip past unused stack words
if (!data_found) { if (!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 - &__process_stack_base__;
stack_dump_file.write_line(to_string_hex((uint32_t)&__process_stack_base__, 8) + ": Unused bytes " + to_string_dec_uint(stack_space_left * sizeof(uint32_t))); stack_dump_file.write_line(to_string_hex((uint32_t)&__process_stack_base__, 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);
} }
} }
// 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); stack_dump_file.write(str.data(), 9);
} }
// write stack dword
str = " " + to_string_hex(*p, 8); str = " " + to_string_hex(*p, 8);
stack_dump_file.write(str.data(), 9); stack_dump_file.write(str.data(), 9);

View File

@ -44,6 +44,18 @@ const Style Styles::white_small{
.foreground = Color::white(), .foreground = Color::white(),
}; };
const Style Styles::bg_white_small{
.font = ui::font::fixed_5x8,
.background = ui::Color::white(),
.foreground = ui::Color::black(),
};
const Style Styles::bg_yellow_small{
.font = ui::font::fixed_5x8,
.background = ui::Color::yellow(),
.foreground = ui::Color::black(),
};
const Style Styles::yellow{ const Style Styles::yellow{
.font = font::fixed_8x16, .font = font::fixed_8x16,
.background = Color::black(), .background = Color::black(),
@ -102,4 +114,4 @@ const Style Styles::orange{
.font = font::fixed_8x16, .font = font::fixed_8x16,
.background = Color::black(), .background = Color::black(),
.foreground = Color::orange(), .foreground = Color::orange(),
}; };

View File

@ -37,6 +37,12 @@ class Styles {
/* White foreground, small font. */ /* White foreground, small font. */
static const Style white_small; static const Style white_small;
/* White background, small font. */
static const Style bg_white_small;
/* Red background, small font. */
static const Style bg_yellow_small;
/* Yellow foreground. */ /* Yellow foreground. */
static const Style yellow; static const Style yellow;
@ -70,4 +76,4 @@ class Styles {
} // namespace ui } // namespace ui
#endif /*__UI_STYLES_H__*/ #endif /*__UI_STYLES_H__*/