Read about our upcoming Code of Conduct on this issue

Commit 5702afc7 authored by Alex's avatar Alex
Browse files

Merged in backtrace (pull request #849)

Stack trace (aka backtrace) in crash logs

--HG--
branch : unified
......@@ -1857,6 +1857,61 @@ static void edmac_test_task()
edmac_memcpy_res_unlock();
}
static void frozen_task()
{
NotifyBox(2000, "while(1);");
msleep(3000);
while(1);
}
static void lockup_task()
{
NotifyBox(2000, "cli(); while(1);");
msleep(3000);
cli();
while(1);
}
static void freeze_gui_task()
{
NotifyBox(2000, "GUI task locked up.");
while(1) msleep(1000);
}
static void divzero_task()
{
for (int i = -10; i < 10; i++)
{
console_show();
printf("1000/%d = %d = %d\n", i, 1000/i, (int)(1000.0 / (float)i));
msleep(500);
}
}
static void alloc_1M_task()
{
console_show();
msleep(2000);
/* after a few calls, this will fail with ERR70 */
void * ptr = _AllocateMemory(1024 * 1024);
/* do something with "ptr" to prevent a tail call (to test the stack trace) */
printf("AllocateMemory 1MB => %x\n", ptr);
/* do not free it */
}
static void alloc_10M_task()
{
console_show();
msleep(2000);
void * ptr = malloc(10 * 1024 * 1024);
printf("Alloc 10MB => %x\n", ptr);
/* do not free it */
}
static struct menu_entry selftest_menu[] =
{
{
......@@ -1936,39 +1991,54 @@ static struct menu_entry selftest_menu[] =
MENU_EOL,
}
},
#if 0
{
.name = "Fault emulation...",
.name = "Fault emulation",
.select = menu_open_submenu,
.help = "Causes intentionally wrong behavior to see DryOS reaction.",
.help2 = "You'll have to take the battery out after running most of these.",
.children = (struct menu_entry[]) {
{
.name = "Create a stuck task",
.select = run_in_separate_task,
.priv = frozen_task,
.help = "Creates a task which will become stuck in an infinite loop."
.help = "Creates a task which will become stuck in an infinite loop.",
.help2 = "Low priority tasks (prio >= 0x1A) will no longer be able to run.",
},
{
.name = "Freeze GUI task",
.name = "Freeze the GUI task",
.select = freeze_gui_task,
.help = "Freezes main GUI task. Camera will stop reacting to buttons."
.help = "Freezes main GUI task. Camera will stop reacting to buttons.",
},
{
.name = "Lock-up the ARM CPU",
.select = run_in_separate_task,
.priv = lockup_task,
.help = "Creates a task which will clear the interrupts and execute while(1).",
.help2 = "Anything still running after that would be secondary CPUs or hardware.",
},
{
.name = "Division by zero",
.select = run_in_separate_task,
.priv = divzero_task,
.help = "Performs some math operations which will divide by zero."
.help = "Performs some math operations which will divide by zero.",
},
{
.name = "Allocate 1MB of RAM",
.name = "AllocateMemory 1MB",
.select = run_in_separate_task,
.priv = alloc_1M_task,
.help = "Allocates 1MB RAM from system memory, without freeing it."
.help = "Allocates 1MB RAM using AllocateMemory, without freeing it.",
.help2 = "After running this a few times, you'll get ERR70.",
},
{
.name = "Allocate 10MB of RAM",
.select = run_in_separate_task,
.priv = alloc_10M_task,
.help = "Allocates 1MB RAM from any source, without freeing it.",
.help2 = "After running this a few times, you'll run out of memory.",
},
MENU_EOL,
}
},
#endif
};
static struct menu_entry * selftest_menu_entry(const char* entry_name)
......
......@@ -105,6 +105,7 @@ ML_OBJS-y += \
version.o
ML_SRC_OBJS = \
backtrace.o \
$(ML_BOOT_HACK_OBJ) \
fio-ml.o \
mem.o \
......@@ -247,6 +248,29 @@ clean::
$(TOP_DIR)/tcc/libtccx.o: FORCE
+$(MAKE) -C $(TOP_DIR)/tcc
# backtrace.[ch] are shared with QEMU
# the install script will copy them from src/
# but I'd still like to edit them from one place and have the changes both in QEMU and ML
# symlinks caused issues on Windows and apparently also on Mac (?!) so let's avoid them for now
# where QEMU is installed (for emulating ML)
QEMU_INSTALLED_DBI_DIR=$(TOP_DIR)/../qemu/qemu-2.5.0/hw/eos/dbi
ifneq ("$(wildcard $(QEMU_INSTALLED_DBI_DIR)/backtrace.c)","")
# copy backtrace.[ch] from QEMU (outside ML dir) if they were edited there
# optional dependency, only if QEMU is installed "near" ML dir (the install script does that)
# https://stackoverflow.com/questions/5553352/how-do-i-check-if-file-exists-in-makefile
$(SRC_DIR)/backtrace.c $(SRC_DIR)/backtrace.h:: $(SRC_DIR)/backtrace.%: $(QEMU_INSTALLED_DBI_DIR)/backtrace.%
$(call build,CP,$(CP) $^ $@)
# make sure we have the latest header when compiling after "make clean"
# normally, *.h are added as dependencies of *.o in the *.d (make)files
# but after "make clean" we don't have them
$(SRC_DIR)/backtrace.c:: $(SRC_DIR)/backtrace.h
endif
# Extract the stdio files that we need
DIET_OBJ = \
strrchr.o \
......
......@@ -55,10 +55,17 @@ static inline uint32_t
read_lr( void )
{
uint32_t lr;
asm( "mov %0, lr" : "=r"(lr) );
asm __volatile__ ( "mov %0, %%lr" : "=&r"(lr) );
return lr;
}
static inline uint32_t
read_sp( void )
{
uint32_t sp;
asm __volatile__ ( "mov %0, %%sp" : "=&r"(sp) );
return sp;
}
static inline void
select_normal_vectors( void )
......
This diff is collapsed.
#ifndef _backtrace_h_
#define _backtrace_h_
#ifdef CONFIG_MAGICLANTERN
/* simple wrappers */
void backtrace_print();
void backtrace_getstr(char * buf, int size);
/* don't use this one directly */
void eos_backtrace_rebuild(void * sp, char * buf, int size);
/* this simplifies the code and even handles non-obvious tail call patterns;
* no counterexample found yet */
#define BKT_ASSUME_TAIL_CALL_AFTER_POP_LR
/* simple and works in many cases */
#define BKT_BRUTE_FORCE_STACK
#else /* QEMU */
/* similar to callstack, but does not require any instrumentation
* it works by walking the stack backwards, with some code analysis
* to figure out the offsets where LRs are stored */
void eos_backtrace_rebuild(EOSState *s, char * buf, int size);
/* stack walker configuration */
#define BKT_ASSUME_TAIL_CALL_AFTER_POP_LR
#define BKT_BRUTE_FORCE_STACK
//#define BKT_HANDLE_UNLIKELY_CASES
//#define BKT_RANDOM_BRANCHES /* slow, minor improvement */
/* self-tests */
//#define BKT_CROSSCHECK_EXEC
//#define BKT_CROSSCHECK_CALLSTACK
#ifdef BKT_CROSSCHECK_CALLSTACK
#define BKT_TRACK_STATS
#endif
/* debugging */
//#define BKT_LOG_VERBOSE EOS_LOG_VERBOSE
//#define BKT_LOG_DISAS EOS_LOG_VERBOSE
#define BKT_LOG_VERBOSE 0
#define BKT_LOG_DISAS 0
/* internal, for BKT_CROSSCHECK_EXEC */
void eos_bkt_log_exec(EOSState *s);
#endif /* QEMU */
#endif /* _backtrace_h_ */
......@@ -41,6 +41,7 @@
#include "reloc.h"
#include "ml-cbr.h"
#include "backtrace.h"
#if defined(FEATURE_GPS_TWEAKS)
#include "gps.h"
......@@ -583,34 +584,36 @@ void hold_your_horses()
* Custom assert handler - intercept ERR70 and try to save a crash log.
* Crash log should contain Canon error message.
*/
static char assert_msg[256] = "";
static char assert_msg[512] = "";
static int (*old_assert_handler)(char*,char*,int,int) = 0;
const char* get_assert_msg() { return assert_msg; }
static int my_assert_handler(char* msg, char* file, int line, int arg4)
{
snprintf(assert_msg, sizeof(assert_msg),
int len = snprintf(assert_msg, sizeof(assert_msg),
"ASSERT: %s\n"
"at %s:%d, task %s\n"
"lv:%d mode:%d\n",
"lv:%d mode:%d\n\n",
msg,
file, line, get_current_task_name(),
lv, shooting_mode
);
backtrace_getstr(assert_msg + len, sizeof(assert_msg) - len);
request_crash_log(1);
return old_assert_handler(msg, file, line, arg4);
}
void ml_assert_handler(char* msg, char* file, int line, const char* func)
{
snprintf(assert_msg, sizeof(assert_msg),
int len = snprintf(assert_msg, sizeof(assert_msg),
"ML ASSERT:\n%s\n"
"at %s:%d (%s), task %s\n"
"lv:%d mode:%d\n",
"lv:%d mode:%d\n\n",
msg,
file, line, func, get_current_task_name(),
lv, shooting_mode
);
backtrace_getstr(assert_msg + len, sizeof(assert_msg) - len);
request_crash_log(2);
}
......
......@@ -458,7 +458,7 @@ static void save_crash_log()
FILE* f = FIO_CreateFile(log_filename);
if (f)
{
my_fprintf(f, "%s\n\n", get_assert_msg());
my_fprintf(f, "%s\n", get_assert_msg());
my_fprintf(f,
"Magic Lantern version : %s\n"
"Mercurial changeset : %s\n"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment