rockbox/firmware/panic.c
Frank Gevaerts 25e50ed8f1 Print `last logf lines on panic().
If logf is enabled, panic() will print the last lines. On small
screens this is more or less useless, but on large screens it
can be very useful for debugging.

Change-Id: I26dfc76e9ac4a2ddc2def8db1616a04f943dbba3
Reviewed-on: http://gerrit.rockbox.org/709
Reviewed-by: Thomas Martitz <kugel@rockbox.org>
Reviewed-by: Frank Gevaerts <frank@gevaerts.be>
Tested: Frank Gevaerts <frank@gevaerts.be>
2014-01-11 11:37:18 +01:00

138 lines
3.3 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by wavey@wavey.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "panic.h"
#include "lcd.h"
#include "font.h"
#include "debug.h"
#include "led.h"
#include "power.h"
#include "system.h"
#include "logf.h"
#if defined(CPU_ARM)
#include "gcc_extensions.h"
#include <backtrace.h>
#endif
static char panic_buf[128];
#define LINECHARS (LCD_WIDTH/SYSFONT_WIDTH) - 2
#if defined(CPU_ARM)
void panicf_f( const char *fmt, ...);
/* we wrap panicf() here with naked function to catch SP value */
void panicf( const char *fmt, ...)
{
(void)fmt;
asm volatile ("mov r4, sp \n"
"b panicf_f \n"
);
}
/*
* "Dude. This is pretty fucked-up, right here."
*/
void panicf_f( const char *fmt, ...)
{
int sp;
asm volatile ("mov %[SP],r4 \n"
: [SP] "=r" (sp)
);
int pc = (int)__builtin_return_address(0);
#else
void panicf( const char *fmt, ...)
{
#endif
va_list ap;
#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
/* Disable interrupts */
#ifdef CPU_ARM
disable_interrupt(IRQ_FIQ_STATUS);
#else
set_irq_level(DISABLE_INTERRUPTS);
#endif
#endif /* SIMULATOR */
va_start( ap, fmt );
vsnprintf( panic_buf, sizeof(panic_buf), fmt, ap );
va_end( ap );
lcd_set_viewport(NULL);
#ifdef HAVE_LCD_CHARCELLS
lcd_double_height(false);
lcd_puts(0, 0, "*PANIC*");
lcd_puts(0, 1, panic_buf);
#elif defined(HAVE_LCD_BITMAP)
int y = 1;
#if LCD_DEPTH > 1
lcd_set_backdrop(NULL);
lcd_set_drawmode(DRMODE_SOLID);
lcd_set_foreground(LCD_BLACK);
lcd_set_background(LCD_WHITE);
#endif
lcd_clear_display();
lcd_setfont(FONT_SYSFIXED);
lcd_puts(1, y++, (unsigned char *)"*PANIC*");
{
/* wrap panic line */
int i, len = strlen(panic_buf);
for (i=0; i<len; i+=LINECHARS) {
unsigned char c = panic_buf[i+LINECHARS];
panic_buf[i+LINECHARS] = 0;
lcd_puts(1, y++, (unsigned char *)panic_buf+i);
panic_buf[i+LINECHARS] = c;
}
}
#if defined(CPU_ARM)
backtrace(pc, sp, &y);
#endif
#ifdef ROCKBOX_HAS_LOGF
logf_panic_dump(&y);
#endif
#else
/* no LCD */
#endif
lcd_update();
DEBUGF("%s", panic_buf);
set_cpu_frequency(0);
#ifdef HAVE_ATA_POWER_OFF
ide_power_enable(false);
#endif
system_exception_wait(); /* if this returns, try to reboot */
system_reboot();
while (1); /* halt */
}