mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-12 10:11:04 +01:00
fusee/sept: fix error printing
This commit is contained in:
parent
51dd668c7c
commit
72afe34cf9
@ -17,7 +17,7 @@
|
|||||||
#ifndef FUSEE_LOG_H
|
#ifndef FUSEE_LOG_H
|
||||||
#define FUSEE_LOG_H
|
#define FUSEE_LOG_H
|
||||||
|
|
||||||
#define PRINT_MESSAGE_MAX_LENGTH 512
|
#define PRINT_MESSAGE_MAX_LENGTH 1024
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
@ -17,17 +17,26 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "display/video_fb.h"
|
||||||
#include "lib/log.h"
|
#include "lib/log.h"
|
||||||
|
|
||||||
__attribute__ ((noreturn)) void generic_panic(void) {
|
__attribute__ ((noreturn)) void generic_panic(void) {
|
||||||
print(SCREEN_LOG_LEVEL_ERROR, "Panic raised!");
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
/* Lock. */
|
/* Lock. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
|
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
|
||||||
|
/* Forcefully initialize the screen if logging is disabled. */
|
||||||
|
if (log_get_log_level() == SCREEN_LOG_LEVEL_NONE) {
|
||||||
|
/* Zero-fill the framebuffer and register it as printk provider. */
|
||||||
|
video_init((void *)0xC0000000);
|
||||||
|
|
||||||
|
/* Override the global logging level. */
|
||||||
|
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Display fatal error. */
|
||||||
va_list args;
|
va_list args;
|
||||||
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
|
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
@ -19,9 +19,10 @@
|
|||||||
#include "exception_handlers.h"
|
#include "exception_handlers.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "lib/log.h"
|
#include "lib/log.h"
|
||||||
|
#include "lib/vsprintf.h"
|
||||||
|
|
||||||
#define CODE_DUMP_SIZE 0x30
|
#define CODE_DUMP_SIZE 0x30
|
||||||
#define STACK_DUMP_SIZE 0x60
|
#define STACK_DUMP_SIZE 0x30
|
||||||
|
|
||||||
extern const uint32_t exception_handler_table[];
|
extern const uint32_t exception_handler_table[];
|
||||||
|
|
||||||
@ -34,6 +35,40 @@ static const char *register_names[] = {
|
|||||||
"SP", "LR", "PC", "CPSR",
|
"SP", "LR", "PC", "CPSR",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Adapted from https://gist.github.com/ccbrown/9722406 */
|
||||||
|
static void hexdump(const void* data, size_t size, uintptr_t addrbase, char* strbuf) {
|
||||||
|
const uint8_t *d = (const uint8_t *)data;
|
||||||
|
char ascii[17];
|
||||||
|
ascii[16] = '\0';
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
if (i % 16 == 0) {
|
||||||
|
strbuf += sprintf(strbuf, "%0*" PRIXPTR ": | ", 2 * sizeof(addrbase), addrbase + i);
|
||||||
|
}
|
||||||
|
strbuf += sprintf(strbuf, "%02X ", d[i]);
|
||||||
|
if (d[i] >= ' ' && d[i] <= '~') {
|
||||||
|
ascii[i % 16] = d[i];
|
||||||
|
} else {
|
||||||
|
ascii[i % 16] = '.';
|
||||||
|
}
|
||||||
|
if ((i+1) % 8 == 0 || i+1 == size) {
|
||||||
|
strbuf += sprintf(strbuf, " ");
|
||||||
|
if ((i+1) % 16 == 0) {
|
||||||
|
strbuf += sprintf(strbuf, "| %s \n", ascii);
|
||||||
|
} else if (i+1 == size) {
|
||||||
|
ascii[(i+1) % 16] = '\0';
|
||||||
|
if ((i+1) % 16 <= 8) {
|
||||||
|
strbuf += sprintf(strbuf, " ");
|
||||||
|
}
|
||||||
|
for (size_t j = (i+1) % 16; j < 16; j++) {
|
||||||
|
strbuf += sprintf(strbuf, " ");
|
||||||
|
}
|
||||||
|
strbuf += sprintf(strbuf, "| %s \n", ascii);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setup_exception_handlers(void) {
|
void setup_exception_handlers(void) {
|
||||||
volatile uint32_t *bpmp_exception_handler_table = (volatile uint32_t *)0x6000F200;
|
volatile uint32_t *bpmp_exception_handler_table = (volatile uint32_t *)0x6000F200;
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
@ -44,38 +79,40 @@ void setup_exception_handlers(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void exception_handler_main(uint32_t *registers, unsigned int exception_type) {
|
void exception_handler_main(uint32_t *registers, unsigned int exception_type) {
|
||||||
|
char exception_log[0x400];
|
||||||
uint8_t code_dump[CODE_DUMP_SIZE];
|
uint8_t code_dump[CODE_DUMP_SIZE];
|
||||||
uint8_t stack_dump[STACK_DUMP_SIZE];
|
uint8_t stack_dump[STACK_DUMP_SIZE];
|
||||||
size_t code_dump_size;
|
size_t code_dump_size;
|
||||||
size_t stack_dump_size;
|
size_t stack_dump_size;
|
||||||
|
|
||||||
uint32_t pc = registers[15];
|
uint32_t pc = registers[15];
|
||||||
uint32_t cpsr = registers[16];
|
uint32_t cpsr = registers[16];
|
||||||
|
|
||||||
uint32_t instr_addr = pc + ((cpsr & 0x20) ? 2 : 4) - CODE_DUMP_SIZE;
|
uint32_t instr_addr = pc + ((cpsr & 0x20) ? 2 : 4) - CODE_DUMP_SIZE;
|
||||||
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR, "\nSomething went wrong...\n");
|
sprintf(exception_log + strlen(exception_log), "An exception occured!\n");
|
||||||
|
|
||||||
code_dump_size = safecpy(code_dump, (const void *)instr_addr, CODE_DUMP_SIZE);
|
code_dump_size = safecpy(code_dump, (const void *)instr_addr, CODE_DUMP_SIZE);
|
||||||
stack_dump_size = safecpy(stack_dump, (const void *)registers[13], STACK_DUMP_SIZE);
|
stack_dump_size = safecpy(stack_dump, (const void *)registers[13], STACK_DUMP_SIZE);
|
||||||
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nException type: %s\n",
|
sprintf(exception_log + strlen(exception_log), "\nException type: %s\n", exception_names[exception_type]);
|
||||||
exception_names[exception_type]);
|
sprintf(exception_log + strlen(exception_log), "\nRegisters:\n");
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nRegisters:\n\n");
|
|
||||||
|
|
||||||
/* Print r0 to pc. */
|
/* Print r0 to pc. */
|
||||||
for (int i = 0; i < 16; i += 2) {
|
for (int i = 0; i < 16; i += 2) {
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%-7s%08"PRIX32" %-7s%08"PRIX32"\n",
|
sprintf(exception_log + strlen(exception_log), "%-7s%08"PRIX32" %-7s%08"PRIX32"\n",
|
||||||
register_names[i], registers[i], register_names[i+1], registers[i+1]);
|
register_names[i], registers[i], register_names[i+1], registers[i+1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print cpsr. */
|
/* Print cpsr. */
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%-7s%08"PRIX32"\n", register_names[16], registers[16]);
|
sprintf(exception_log + strlen(exception_log), "%-7s%08"PRIX32"\n", register_names[16], registers[16]);
|
||||||
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nCode dump:\n");
|
/* Print code and stack regions. */
|
||||||
hexdump(code_dump, code_dump_size, instr_addr);
|
sprintf(exception_log + strlen(exception_log), "\nCode dump:\n");
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nStack dump:\n");
|
hexdump(code_dump, code_dump_size, instr_addr, exception_log + strlen(exception_log));
|
||||||
hexdump(stack_dump, stack_dump_size, registers[13]);
|
sprintf(exception_log + strlen(exception_log), "\nStack dump:\n");
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\n");
|
hexdump(stack_dump, stack_dump_size, registers[13], exception_log + strlen(exception_log));
|
||||||
fatal_error("An exception occured!\n");
|
sprintf(exception_log + strlen(exception_log), "\n");
|
||||||
|
|
||||||
|
/* Throw fatal error with the full exception log. */
|
||||||
|
fatal_error(exception_log);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#ifndef FUSEE_LOG_H
|
#ifndef FUSEE_LOG_H
|
||||||
#define FUSEE_LOG_H
|
#define FUSEE_LOG_H
|
||||||
|
|
||||||
#define PRINT_MESSAGE_MAX_LENGTH 512
|
#define PRINT_MESSAGE_MAX_LENGTH 1024
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ void load_stage2(const char *bct0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(config.path) + 1 + sizeof(stage2_args_t) > CHAINLOADER_ARG_DATA_MAX_SIZE) {
|
if (strlen(config.path) + 1 + sizeof(stage2_args_t) > CHAINLOADER_ARG_DATA_MAX_SIZE) {
|
||||||
print(SCREEN_LOG_LEVEL_ERROR, "Stage2's path name is too big!\n");
|
fatal_error("Stage2's path name is too big!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!check_32bit_address_loadable(config.entrypoint)) {
|
if (!check_32bit_address_loadable(config.entrypoint)) {
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "car.h"
|
#include "car.h"
|
||||||
#include "btn.h"
|
#include "btn.h"
|
||||||
#include "lib/log.h"
|
#include "lib/log.h"
|
||||||
|
#include "lib/vsprintf.h"
|
||||||
#include "display/video_fb.h"
|
#include "display/video_fb.h"
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
@ -112,11 +113,11 @@ __attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
|
|||||||
/* Turn on the backlight after initializing the lfb */
|
/* Turn on the backlight after initializing the lfb */
|
||||||
/* to avoid flickering. */
|
/* to avoid flickering. */
|
||||||
display_backlight(true);
|
display_backlight(true);
|
||||||
|
|
||||||
/* Override the global logging level. */
|
|
||||||
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Override the global logging level. */
|
||||||
|
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
|
||||||
|
|
||||||
/* Display fatal error. */
|
/* Display fatal error. */
|
||||||
va_list args;
|
va_list args;
|
||||||
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
|
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
|
||||||
@ -137,37 +138,3 @@ __attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, u
|
|||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adapted from https://gist.github.com/ccbrown/9722406 */
|
|
||||||
void hexdump(const void* data, size_t size, uintptr_t addrbase) {
|
|
||||||
const uint8_t *d = (const uint8_t *)data;
|
|
||||||
char ascii[17];
|
|
||||||
ascii[16] = '\0';
|
|
||||||
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
if (i % 16 == 0) {
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%0*" PRIXPTR ": | ", 2 * sizeof(addrbase), addrbase + i);
|
|
||||||
}
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%02X ", d[i]);
|
|
||||||
if (d[i] >= ' ' && d[i] <= '~') {
|
|
||||||
ascii[i % 16] = d[i];
|
|
||||||
} else {
|
|
||||||
ascii[i % 16] = '.';
|
|
||||||
}
|
|
||||||
if ((i+1) % 8 == 0 || i+1 == size) {
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, " ");
|
|
||||||
if ((i+1) % 16 == 0) {
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "| %s \n", ascii);
|
|
||||||
} else if (i+1 == size) {
|
|
||||||
ascii[(i+1) % 16] = '\0';
|
|
||||||
if ((i+1) % 16 <= 8) {
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, " ");
|
|
||||||
}
|
|
||||||
for (size_t j = (i+1) % 16; j < 16; j++) {
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, " ");
|
|
||||||
}
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "| %s \n", ascii);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -117,15 +117,12 @@ static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t s
|
|||||||
overlaps_a(start, end, __start__, __end__);
|
overlaps_a(start, end, __start__, __end__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hexdump(const void* data, size_t size, uintptr_t addrbase);
|
|
||||||
|
|
||||||
__attribute__((noreturn)) void watchdog_reboot(void);
|
__attribute__((noreturn)) void watchdog_reboot(void);
|
||||||
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
|
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
|
||||||
__attribute__((noreturn)) void reboot_to_self(void);
|
__attribute__((noreturn)) void reboot_to_self(void);
|
||||||
__attribute__((noreturn)) void wait_for_button_and_reboot(void);
|
__attribute__((noreturn)) void wait_for_button_and_reboot(void);
|
||||||
|
|
||||||
__attribute__((noreturn)) void generic_panic(void);
|
__attribute__((noreturn)) void generic_panic(void);
|
||||||
|
|
||||||
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
|
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "exception_handlers.h"
|
#include "exception_handlers.h"
|
||||||
@ -22,7 +23,7 @@
|
|||||||
#include "lib/log.h"
|
#include "lib/log.h"
|
||||||
|
|
||||||
#define CODE_DUMP_SIZE 0x30
|
#define CODE_DUMP_SIZE 0x30
|
||||||
#define STACK_DUMP_SIZE 0x60
|
#define STACK_DUMP_SIZE 0x30
|
||||||
|
|
||||||
extern const uint32_t exception_handler_table[];
|
extern const uint32_t exception_handler_table[];
|
||||||
|
|
||||||
@ -35,6 +36,40 @@ static const char *register_names[] = {
|
|||||||
"SP", "LR", "PC", "CPSR",
|
"SP", "LR", "PC", "CPSR",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Adapted from https://gist.github.com/ccbrown/9722406 */
|
||||||
|
static void hexdump(const void* data, size_t size, uintptr_t addrbase, char* strbuf) {
|
||||||
|
const uint8_t *d = (const uint8_t *)data;
|
||||||
|
char ascii[17];
|
||||||
|
ascii[16] = '\0';
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
if (i % 16 == 0) {
|
||||||
|
strbuf += sprintf(strbuf, "%0*" PRIXPTR ": | ", 2 * sizeof(addrbase), addrbase + i);
|
||||||
|
}
|
||||||
|
strbuf += sprintf(strbuf, "%02X ", d[i]);
|
||||||
|
if (d[i] >= ' ' && d[i] <= '~') {
|
||||||
|
ascii[i % 16] = d[i];
|
||||||
|
} else {
|
||||||
|
ascii[i % 16] = '.';
|
||||||
|
}
|
||||||
|
if ((i+1) % 8 == 0 || i+1 == size) {
|
||||||
|
strbuf += sprintf(strbuf, " ");
|
||||||
|
if ((i+1) % 16 == 0) {
|
||||||
|
strbuf += sprintf(strbuf, "| %s \n", ascii);
|
||||||
|
} else if (i+1 == size) {
|
||||||
|
ascii[(i+1) % 16] = '\0';
|
||||||
|
if ((i+1) % 16 <= 8) {
|
||||||
|
strbuf += sprintf(strbuf, " ");
|
||||||
|
}
|
||||||
|
for (size_t j = (i+1) % 16; j < 16; j++) {
|
||||||
|
strbuf += sprintf(strbuf, " ");
|
||||||
|
}
|
||||||
|
strbuf += sprintf(strbuf, "| %s \n", ascii);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setup_exception_handlers(void) {
|
void setup_exception_handlers(void) {
|
||||||
volatile uint32_t *bpmp_exception_handler_table = (volatile uint32_t *)0x6000F200;
|
volatile uint32_t *bpmp_exception_handler_table = (volatile uint32_t *)0x6000F200;
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
@ -45,38 +80,40 @@ void setup_exception_handlers(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void exception_handler_main(uint32_t *registers, unsigned int exception_type) {
|
void exception_handler_main(uint32_t *registers, unsigned int exception_type) {
|
||||||
|
char exception_log[0x400];
|
||||||
uint8_t code_dump[CODE_DUMP_SIZE];
|
uint8_t code_dump[CODE_DUMP_SIZE];
|
||||||
uint8_t stack_dump[STACK_DUMP_SIZE];
|
uint8_t stack_dump[STACK_DUMP_SIZE];
|
||||||
size_t code_dump_size;
|
size_t code_dump_size;
|
||||||
size_t stack_dump_size;
|
size_t stack_dump_size;
|
||||||
|
|
||||||
uint32_t pc = registers[15];
|
uint32_t pc = registers[15];
|
||||||
uint32_t cpsr = registers[16];
|
uint32_t cpsr = registers[16];
|
||||||
|
|
||||||
uint32_t instr_addr = pc + ((cpsr & 0x20) ? 2 : 4) - CODE_DUMP_SIZE;
|
uint32_t instr_addr = pc + ((cpsr & 0x20) ? 2 : 4) - CODE_DUMP_SIZE;
|
||||||
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR, "\nSomething went wrong...\n");
|
sprintf(exception_log + strlen(exception_log), "An exception occured!\n");
|
||||||
|
|
||||||
code_dump_size = safecpy(code_dump, (const void *)instr_addr, CODE_DUMP_SIZE);
|
code_dump_size = safecpy(code_dump, (const void *)instr_addr, CODE_DUMP_SIZE);
|
||||||
stack_dump_size = safecpy(stack_dump, (const void *)registers[13], STACK_DUMP_SIZE);
|
stack_dump_size = safecpy(stack_dump, (const void *)registers[13], STACK_DUMP_SIZE);
|
||||||
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nException type: %s\n",
|
sprintf(exception_log + strlen(exception_log), "\nException type: %s\n", exception_names[exception_type]);
|
||||||
exception_names[exception_type]);
|
sprintf(exception_log + strlen(exception_log), "\nRegisters:\n");
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nRegisters:\n\n");
|
|
||||||
|
|
||||||
/* Print r0 to pc. */
|
/* Print r0 to pc. */
|
||||||
for (int i = 0; i < 16; i += 2) {
|
for (int i = 0; i < 16; i += 2) {
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%-7s%08"PRIX32" %-7s%08"PRIX32"\n",
|
sprintf(exception_log + strlen(exception_log), "%-7s%08"PRIX32" %-7s%08"PRIX32"\n",
|
||||||
register_names[i], registers[i], register_names[i+1], registers[i+1]);
|
register_names[i], registers[i], register_names[i+1], registers[i+1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print cpsr. */
|
/* Print cpsr. */
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%-7s%08"PRIX32"\n", register_names[16], registers[16]);
|
sprintf(exception_log + strlen(exception_log), "%-7s%08"PRIX32"\n", register_names[16], registers[16]);
|
||||||
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nCode dump:\n");
|
/* Print code and stack regions. */
|
||||||
hexdump(code_dump, code_dump_size, instr_addr);
|
sprintf(exception_log + strlen(exception_log), "\nCode dump:\n");
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nStack dump:\n");
|
hexdump(code_dump, code_dump_size, instr_addr, exception_log + strlen(exception_log));
|
||||||
hexdump(stack_dump, stack_dump_size, registers[13]);
|
sprintf(exception_log + strlen(exception_log), "\nStack dump:\n");
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\n");
|
hexdump(stack_dump, stack_dump_size, registers[13], exception_log + strlen(exception_log));
|
||||||
fatal_error("An exception occurred!\n");
|
sprintf(exception_log + strlen(exception_log), "\n");
|
||||||
|
|
||||||
|
/* Throw fatal error with the full exception log. */
|
||||||
|
fatal_error(exception_log);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#ifndef FUSEE_LOG_H
|
#ifndef FUSEE_LOG_H
|
||||||
#define FUSEE_LOG_H
|
#define FUSEE_LOG_H
|
||||||
|
|
||||||
#define PRINT_MESSAGE_MAX_LENGTH 512
|
#define PRINT_MESSAGE_MAX_LENGTH 1024
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
@ -157,12 +157,18 @@ __attribute__ ((noreturn)) void generic_panic(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
|
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
|
||||||
|
/* Override the global logging level. */
|
||||||
|
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
|
||||||
|
|
||||||
|
/* Display fatal error. */
|
||||||
va_list args;
|
va_list args;
|
||||||
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
|
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vprint(SCREEN_LOG_LEVEL_ERROR, fmt, args);
|
vprint(SCREEN_LOG_LEVEL_ERROR, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\n Press POWER to reboot.\n");
|
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\n Press POWER to reboot.\n");
|
||||||
|
|
||||||
|
/* Wait for button and reboot. */
|
||||||
wait_for_button_and_reboot();
|
wait_for_button_and_reboot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,37 +180,3 @@ __attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, u
|
|||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adapted from https://gist.github.com/ccbrown/9722406 */
|
|
||||||
void hexdump(const void* data, size_t size, uintptr_t addrbase) {
|
|
||||||
const uint8_t *d = (const uint8_t *)data;
|
|
||||||
char ascii[17];
|
|
||||||
ascii[16] = '\0';
|
|
||||||
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
if (i % 16 == 0) {
|
|
||||||
printf("%0*" PRIXPTR ": | ", 2 * sizeof(addrbase), addrbase + i);
|
|
||||||
}
|
|
||||||
printf("%02X ", d[i]);
|
|
||||||
if (d[i] >= ' ' && d[i] <= '~') {
|
|
||||||
ascii[i % 16] = d[i];
|
|
||||||
} else {
|
|
||||||
ascii[i % 16] = '.';
|
|
||||||
}
|
|
||||||
if ((i+1) % 8 == 0 || i+1 == size) {
|
|
||||||
printf(" ");
|
|
||||||
if ((i+1) % 16 == 0) {
|
|
||||||
printf("| %s \n", ascii);
|
|
||||||
} else if (i+1 == size) {
|
|
||||||
ascii[(i+1) % 16] = '\0';
|
|
||||||
if ((i+1) % 16 <= 8) {
|
|
||||||
printf(" ");
|
|
||||||
}
|
|
||||||
for (size_t j = (i+1) % 16; j < 16; j++) {
|
|
||||||
printf(" ");
|
|
||||||
}
|
|
||||||
printf("| %s \n", ascii);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -118,8 +118,6 @@ static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t s
|
|||||||
overlaps_a(start, end, __start__, __end__);
|
overlaps_a(start, end, __start__, __end__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hexdump(const void* data, size_t size, uintptr_t addrbase);
|
|
||||||
|
|
||||||
__attribute__((noreturn)) void watchdog_reboot(void);
|
__attribute__((noreturn)) void watchdog_reboot(void);
|
||||||
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
|
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
|
||||||
__attribute__((noreturn)) void reboot_to_fusee_primary(void);
|
__attribute__((noreturn)) void reboot_to_fusee_primary(void);
|
||||||
@ -129,8 +127,6 @@ __attribute__((noreturn)) void wait_for_button_and_reboot(void);
|
|||||||
void wait_for_button(void);
|
void wait_for_button(void);
|
||||||
|
|
||||||
__attribute__((noreturn)) void generic_panic(void);
|
__attribute__((noreturn)) void generic_panic(void);
|
||||||
|
|
||||||
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
|
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
#include "lib/log.h"
|
#include "lib/log.h"
|
||||||
|
|
||||||
#define CODE_DUMP_SIZE 0x30
|
#define CODE_DUMP_SIZE 0x30
|
||||||
#define STACK_DUMP_SIZE 0x60
|
#define STACK_DUMP_SIZE 0x30
|
||||||
|
|
||||||
extern const uint32_t exception_handler_table[];
|
extern const uint32_t exception_handler_table[];
|
||||||
|
|
||||||
@ -34,6 +34,40 @@ static const char *register_names[] = {
|
|||||||
"SP", "LR", "PC", "CPSR",
|
"SP", "LR", "PC", "CPSR",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Adapted from https://gist.github.com/ccbrown/9722406 */
|
||||||
|
static void hexdump(const void* data, size_t size, uintptr_t addrbase, char* strbuf) {
|
||||||
|
const uint8_t *d = (const uint8_t *)data;
|
||||||
|
char ascii[17];
|
||||||
|
ascii[16] = '\0';
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
if (i % 16 == 0) {
|
||||||
|
strbuf += sprintf(strbuf, "%0*" PRIXPTR ": | ", 2 * sizeof(addrbase), addrbase + i);
|
||||||
|
}
|
||||||
|
strbuf += sprintf(strbuf, "%02X ", d[i]);
|
||||||
|
if (d[i] >= ' ' && d[i] <= '~') {
|
||||||
|
ascii[i % 16] = d[i];
|
||||||
|
} else {
|
||||||
|
ascii[i % 16] = '.';
|
||||||
|
}
|
||||||
|
if ((i+1) % 8 == 0 || i+1 == size) {
|
||||||
|
strbuf += sprintf(strbuf, " ");
|
||||||
|
if ((i+1) % 16 == 0) {
|
||||||
|
strbuf += sprintf(strbuf, "| %s \n", ascii);
|
||||||
|
} else if (i+1 == size) {
|
||||||
|
ascii[(i+1) % 16] = '\0';
|
||||||
|
if ((i+1) % 16 <= 8) {
|
||||||
|
strbuf += sprintf(strbuf, " ");
|
||||||
|
}
|
||||||
|
for (size_t j = (i+1) % 16; j < 16; j++) {
|
||||||
|
strbuf += sprintf(strbuf, " ");
|
||||||
|
}
|
||||||
|
strbuf += sprintf(strbuf, "| %s \n", ascii);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setup_exception_handlers(void) {
|
void setup_exception_handlers(void) {
|
||||||
volatile uint32_t *bpmp_exception_handler_table = (volatile uint32_t *)0x6000F200;
|
volatile uint32_t *bpmp_exception_handler_table = (volatile uint32_t *)0x6000F200;
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
@ -44,38 +78,40 @@ void setup_exception_handlers(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void exception_handler_main(uint32_t *registers, unsigned int exception_type) {
|
void exception_handler_main(uint32_t *registers, unsigned int exception_type) {
|
||||||
|
char exception_log[0x400];
|
||||||
uint8_t code_dump[CODE_DUMP_SIZE];
|
uint8_t code_dump[CODE_DUMP_SIZE];
|
||||||
uint8_t stack_dump[STACK_DUMP_SIZE];
|
uint8_t stack_dump[STACK_DUMP_SIZE];
|
||||||
size_t code_dump_size;
|
size_t code_dump_size;
|
||||||
size_t stack_dump_size;
|
size_t stack_dump_size;
|
||||||
|
|
||||||
uint32_t pc = registers[15];
|
uint32_t pc = registers[15];
|
||||||
uint32_t cpsr = registers[16];
|
uint32_t cpsr = registers[16];
|
||||||
|
|
||||||
uint32_t instr_addr = pc + ((cpsr & 0x20) ? 2 : 4) - CODE_DUMP_SIZE;
|
uint32_t instr_addr = pc + ((cpsr & 0x20) ? 2 : 4) - CODE_DUMP_SIZE;
|
||||||
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR, "\nSomething went wrong...\n");
|
sprintf(exception_log + strlen(exception_log), "An exception occured!\n");
|
||||||
|
|
||||||
code_dump_size = safecpy(code_dump, (const void *)instr_addr, CODE_DUMP_SIZE);
|
code_dump_size = safecpy(code_dump, (const void *)instr_addr, CODE_DUMP_SIZE);
|
||||||
stack_dump_size = safecpy(stack_dump, (const void *)registers[13], STACK_DUMP_SIZE);
|
stack_dump_size = safecpy(stack_dump, (const void *)registers[13], STACK_DUMP_SIZE);
|
||||||
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nException type: %s\n",
|
sprintf(exception_log + strlen(exception_log), "\nException type: %s\n", exception_names[exception_type]);
|
||||||
exception_names[exception_type]);
|
sprintf(exception_log + strlen(exception_log), "\nRegisters:\n");
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nRegisters:\n\n");
|
|
||||||
|
|
||||||
/* Print r0 to pc. */
|
/* Print r0 to pc. */
|
||||||
for (int i = 0; i < 16; i += 2) {
|
for (int i = 0; i < 16; i += 2) {
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%-7s%08"PRIX32" %-7s%08"PRIX32"\n",
|
sprintf(exception_log + strlen(exception_log), "%-7s%08"PRIX32" %-7s%08"PRIX32"\n",
|
||||||
register_names[i], registers[i], register_names[i+1], registers[i+1]);
|
register_names[i], registers[i], register_names[i+1], registers[i+1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print cpsr. */
|
/* Print cpsr. */
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%-7s%08"PRIX32"\n", register_names[16], registers[16]);
|
sprintf(exception_log + strlen(exception_log), "%-7s%08"PRIX32"\n", register_names[16], registers[16]);
|
||||||
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nCode dump:\n");
|
/* Print code and stack regions. */
|
||||||
hexdump(code_dump, code_dump_size, instr_addr);
|
sprintf(exception_log + strlen(exception_log), "\nCode dump:\n");
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nStack dump:\n");
|
hexdump(code_dump, code_dump_size, instr_addr, exception_log + strlen(exception_log));
|
||||||
hexdump(stack_dump, stack_dump_size, registers[13]);
|
sprintf(exception_log + strlen(exception_log), "\nStack dump:\n");
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\n");
|
hexdump(stack_dump, stack_dump_size, registers[13], exception_log + strlen(exception_log));
|
||||||
fatal_error("An exception occured!\n");
|
sprintf(exception_log + strlen(exception_log), "\n");
|
||||||
|
|
||||||
|
/* Throw fatal error with the full exception log. */
|
||||||
|
fatal_error(exception_log);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#ifndef FUSEE_LOG_H
|
#ifndef FUSEE_LOG_H
|
||||||
#define FUSEE_LOG_H
|
#define FUSEE_LOG_H
|
||||||
|
|
||||||
#define PRINT_MESSAGE_MAX_LENGTH 512
|
#define PRINT_MESSAGE_MAX_LENGTH 1024
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
@ -105,12 +105,18 @@ __attribute__ ((noreturn)) void generic_panic(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
|
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
|
||||||
|
/* Override the global logging level. */
|
||||||
|
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
|
||||||
|
|
||||||
|
/* Display fatal error. */
|
||||||
va_list args;
|
va_list args;
|
||||||
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
|
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vprint(SCREEN_LOG_LEVEL_ERROR, fmt, args);
|
vprint(SCREEN_LOG_LEVEL_ERROR, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX,"\nPress POWER to reboot\n");
|
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\n Press POWER to reboot.\n");
|
||||||
|
|
||||||
|
/* Wait for button and reboot. */
|
||||||
wait_for_button_and_reboot();
|
wait_for_button_and_reboot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,37 +128,3 @@ __attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, u
|
|||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adapted from https://gist.github.com/ccbrown/9722406 */
|
|
||||||
void hexdump(const void* data, size_t size, uintptr_t addrbase) {
|
|
||||||
const uint8_t *d = (const uint8_t *)data;
|
|
||||||
char ascii[17];
|
|
||||||
ascii[16] = '\0';
|
|
||||||
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
if (i % 16 == 0) {
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%0*" PRIXPTR ": | ", 2 * sizeof(addrbase), addrbase + i);
|
|
||||||
}
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%02X ", d[i]);
|
|
||||||
if (d[i] >= ' ' && d[i] <= '~') {
|
|
||||||
ascii[i % 16] = d[i];
|
|
||||||
} else {
|
|
||||||
ascii[i % 16] = '.';
|
|
||||||
}
|
|
||||||
if ((i+1) % 8 == 0 || i+1 == size) {
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, " ");
|
|
||||||
if ((i+1) % 16 == 0) {
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "| %s \n", ascii);
|
|
||||||
} else if (i+1 == size) {
|
|
||||||
ascii[(i+1) % 16] = '\0';
|
|
||||||
if ((i+1) % 16 <= 8) {
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, " ");
|
|
||||||
}
|
|
||||||
for (size_t j = (i+1) % 16; j < 16; j++) {
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, " ");
|
|
||||||
}
|
|
||||||
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "| %s \n", ascii);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -117,8 +117,6 @@ static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t s
|
|||||||
overlaps_a(start, end, __start__, __end__);
|
overlaps_a(start, end, __start__, __end__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hexdump(const void* data, size_t size, uintptr_t addrbase);
|
|
||||||
|
|
||||||
__attribute__((noreturn)) void watchdog_reboot(void);
|
__attribute__((noreturn)) void watchdog_reboot(void);
|
||||||
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
|
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
|
||||||
void prepare_for_reboot_to_self(void);
|
void prepare_for_reboot_to_self(void);
|
||||||
@ -126,7 +124,6 @@ __attribute__((noreturn)) void reboot_to_self(void);
|
|||||||
__attribute__((noreturn)) void wait_for_button_and_reboot(void);
|
__attribute__((noreturn)) void wait_for_button_and_reboot(void);
|
||||||
|
|
||||||
__attribute__((noreturn)) void generic_panic(void);
|
__attribute__((noreturn)) void generic_panic(void);
|
||||||
|
|
||||||
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
|
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user