Do the same for arm9 exceptions

This commit is contained in:
TuxSH
2018-05-22 20:26:14 +02:00
parent 55bd62d7a9
commit c0bd69309a
15 changed files with 99 additions and 105 deletions

View File

@@ -1,42 +0,0 @@
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/base_tools
name := arm9_exceptions
dir_source := source
dir_build := build
dir_out := ../../$(dir_build)
ASFLAGS := -mcpu=arm946e-s
CFLAGS := -Wall -Wextra -marm $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -Os -ffast-math
LDFLAGS := -nostartfiles -Wl,--nmagic
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
.PHONY: all
all: $(dir_out)/$(name).bin
.PHONY: clean
clean:
@rm -rf $(dir_build)
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
$(OBJCOPY) -S -O binary $< $@
$(dir_build)/$(name).elf: $(objects)
$(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(dir_build)/%.o: $(dir_source)/%.s
@mkdir -p "$(@D)"
$(COMPILE.s) $(OUTPUT_OPTION) $<

View File

@@ -1,14 +0,0 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x01FF8000;
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
. = ALIGN(4);
}

View File

@@ -1,152 +0,0 @@
@ This file is part of Luma3DS
@ Copyright (C) 2016-2019 Aurora Wright, TuxSH
@
@ 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 3 of the License, or
@ (at your option) any later version.
@
@ This program is distributed in the hope that it will be useful,
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@ GNU General Public License for more details.
@
@ You should have received a copy of the GNU General Public License
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
@
@ Additional Terms 7.b and 7.c of GPLv3 apply to this file:
@ * Requiring preservation of specified reasonable legal notices or
@ author attributions in that material or in the Appropriate Legal
@ Notices displayed by works containing it.
@ * Prohibiting misrepresentation of the origin of that material,
@ or requiring that modified versions of such material be marked in
@ reasonable ways as different from the original version.
.macro GEN_USUAL_HANDLER name, index
\name\()Handler:
ldr sp, =_regs
stmia sp, {r0-r7}
mov r0, #\index
b _commonHandler
.endm
.text
.arm
.balign 4
.global _commonHandler
.type _commonHandler, %function
_commonHandler:
mov r1, r0
mov r0, sp
mrs r2, spsr
mrs r3, cpsr
add r6, r0, #(8 * 4)
orr r3, #0xc0 @ mask interrupts
msr cpsr_cx, r3
ands r4, r2, #0xf @ get the mode that triggered the exception
moveq r4, #0xf @ usr => sys
bic r5, r3, #0xf
orr r5, r4
msr cpsr_c, r5 @ change processor mode
stmia r6!, {r8-lr}
msr cpsr_c, r3 @ restore processor mode
str lr, [r6], #4
str r2, [r6]
msr cpsr_cxsf, #0xdf @ finally, switch to system mode, mask interrupts and clear flags (in case of double faults)
ldr sp, =0x02000000
b mainHandler
.global FIQHandler
.type FIQHandler, %function
GEN_USUAL_HANDLER FIQ, 0
.global undefinedInstructionHandler
.type undefinedInstructionHandler, %function
GEN_USUAL_HANDLER undefinedInstruction, 1
.global prefetchAbortHandler
.type prefetchAbortHandler, %function
prefetchAbortHandler:
msr cpsr_cx, #0xd7 @ mask interrupts (abort mode)
mrs sp, spsr
and sp, #0x3f
cmp sp, #0x13
bne _prefetchAbortNormalHandler
ldr sp, =BreakPtr
ldr sp, [sp]
cmp sp, #0
beq _prefetchAbortNormalHandler
add sp, #(1*4 + 4)
cmp lr, sp
bne _prefetchAbortNormalHandler
mov sp, r8
pop {r8-r11}
ldr lr, [sp, #8]!
ldr sp, [sp, #4]
msr spsr_cxsf, sp
tst sp, #0x20
addne lr, #2 @ adjust address for later
GEN_USUAL_HANDLER _prefetchAbortNormal, 2
.global dataAbortHandler
.type dataAbortHandler, %function
dataAbortHandler:
msr cpsr_cx, #0xd7 @ mask interrupts (abort mode)
mrs sp, spsr
and sp, #0x3f
cmp sp, #0x1f
bne _dataAbortNormalHandler
sub lr, #8
adr sp, safecpy
cmp lr, sp
blo _j_dataAbortNormalHandler
adr sp, _safecpy_end
cmp lr, sp
bhs _j_dataAbortNormalHandler
msr spsr_f, #(1 << 30)
mov r12, #0
adds pc, lr, #4
_j_dataAbortNormalHandler:
add lr, #8
GEN_USUAL_HANDLER _dataAbortNormal, 3
.global safecpy
.type safecpy, %function
safecpy:
push {r4, lr}
mov r3, #0
movs r12, #1
_safecpy_loop:
ldrb r4, [r1, r3]
cmp r12, #0
beq _safecpy_loop_end
strb r4, [r0, r3]
add r3, #1
cmp r3, r2
blo _safecpy_loop
_safecpy_loop_end:
mov r0, r3
pop {r4, pc}
_safecpy_end:
.bss
.balign 4
_regs: .skip (4 * 17)

View File

@@ -1,82 +0,0 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include "i2c.h"
#include "handlers.h"
#define FINAL_BUFFER 0x25000000
#define REG_DUMP_SIZE 4 * 17
#define CODE_DUMP_SIZE 48
void __attribute__((noreturn)) mainHandler(u32 *registerDump, u32 type)
{
ExceptionDumpHeader dumpHeader;
u8 codeDump[CODE_DUMP_SIZE];
dumpHeader.magic[0] = 0xDEADC0DE;
dumpHeader.magic[1] = 0xDEADCAFE;
dumpHeader.versionMajor = 1;
dumpHeader.versionMinor = 2;
dumpHeader.processor = 9;
dumpHeader.core = 0;
dumpHeader.type = type;
dumpHeader.registerDumpSize = REG_DUMP_SIZE;
dumpHeader.codeDumpSize = CODE_DUMP_SIZE;
dumpHeader.additionalDataSize = 0;
u32 cpsr = registerDump[16];
u32 pc = registerDump[15] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8);
registerDump[15] = pc;
//Dump code
u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //wouldn't work well on 32-bit Thumb instructions, but it isn't much of a problem
dumpHeader.codeDumpSize = ((u32)instr & (((cpsr & 0x20) != 0) ? 1 : 3)) != 0 ? 0 : safecpy(codeDump, instr, dumpHeader.codeDumpSize);
//Copy register dump and code dump
u8 *final = (u8 *)(FINAL_BUFFER + sizeof(ExceptionDumpHeader));
final += safecpy(final, registerDump, dumpHeader.registerDumpSize);
final += safecpy(final, codeDump, dumpHeader.codeDumpSize);
//Dump stack in place
dumpHeader.stackDumpSize = safecpy(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF));
dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize + dumpHeader.additionalDataSize;
//Copy header (actually optimized by the compiler)
*(ExceptionDumpHeader *)FINAL_BUFFER = dumpHeader;
if(ARESCREENSINITIALIZED) I2C_writeReg(I2C_DEV_MCU, 0x22, 1 << 0); //Shutdown LCD
((void (*)())0xFFFF0830)(); //Ensure that all memory transfers have completed and that the data cache has been flushed
I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 2); //Reboot
while(true);
}

View File

@@ -1,45 +0,0 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
//Common data types
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;
#define PDN_GPU_CNT (*(vu32 *)0x10141200)
#define ARESCREENSINITIALIZED ((PDN_GPU_CNT & 0xFF) != 1)

View File

@@ -1,188 +0,0 @@
#!/usr/bin/env python
# Requires Python >= 3.2 or >= 2.7
# This file is part of Luma3DS
# Copyright (C) 2016-2019 Aurora Wright, TuxSH
#
# 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 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
# reasonable legal notices or author attributions in that material or in the Appropriate Legal
# Notices displayed by works containing it.
__author__ = "TuxSH"
__copyright__ = "Copyright (c) 2016 TuxSH"
__license__ = "GPLv3"
__version__ = "v1.2"
"""
Parses Luma3DS exception dumps
"""
import argparse
from struct import unpack_from
import os
import subprocess
# Source of hexdump: https://gist.github.com/ImmortalPC/c340564823f283fe530b
# Credits for hexdump go to the original authors
# Slightly edited by TuxSH
def hexdump(addr, src, length=16, sep='.' ):
'''
@brief Return {src} in hex dump.
@param[in] length {Int} Nb Bytes by row.
@param[in] sep {Char} For the text part, {sep} will be used for non ASCII char.
@return {Str} The hexdump
@note Full support for python2 and python3 !
'''
result = []
# Python3 support
try:
xrange(0,1)
except NameError:
xrange = range
for i in xrange(0, len(src), length):
subSrc = src[i:i+length]
hexa = ''
isMiddle = False
for h in xrange(0,len(subSrc)):
if h == length/2:
hexa += ' '
h = subSrc[h]
if not isinstance(h, int):
h = ord(h)
h = hex(h).replace('0x','')
if len(h) == 1:
h = '0'+h
hexa += h+' '
hexa = hexa.strip(' ')
text = ''
for c in subSrc:
if not isinstance(c, int):
c = ord(c)
if 0x20 <= c < 0x7F:
text += chr(c)
else:
text += sep
result.append(('%08x: %-'+str(length*(2+1)+1)+'s |%s|') % (addr + i, hexa, text))
return '\n'.join(result)
def makeRegisterLine(A, rA, B, rB):
return "{0:<15}{1:<20}{2:<15}{3:<20}".format(A, "{0:08x}".format(rA), B, "{0:08x}".format(rB))
handledExceptionNames = ("FIQ", "undefined instruction", "prefetch abort", "data abort")
registerNames = tuple("r{0}".format(i) for i in range(13)) + ("sp", "lr", "pc", "cpsr") + ("dfsr", "ifsr", "far") + ("fpexc", "fpinst", "fpinst2")
svcBreakReasons = ("(svcBreak: panic)", "(svcBreak: assertion failed)", "(svcBreak: user-related)")
faultStatusSources = {
0b1:'Alignment', 0b100:'Instruction cache maintenance operation fault',
0b1100:'External Abort on translation - First-level', 0b1110:'External Abort on translation - Second-level',
0b101:'Translation - Section', 0b111:'Translation - Page', 0b11:'Access bit - Section', 0b110:'Access bit - Page',
0b1001:'Domain - Section', 0b1011:'Domain - Page', 0b1101:'Permission - Section', 0b1111:'Permission - Page',
0b1000:'Precise External Abort', 0b10110:'Imprecise External Abort', 0b10:'Debug event'
}
def main(args=None):
parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps")
parser.add_argument("filename")
args = parser.parse_args()
data = b""
with open(args.filename, "rb") as f: data = f.read()
if unpack_from("<2I", data) != (0xdeadc0de, 0xdeadcafe):
raise SystemExit("Invalid file format")
version, processor, exceptionType, _, nbRegisters, codeDumpSize, stackDumpSize, additionalDataSize = unpack_from("<8I", data, 8)
nbRegisters //= 4
if version < (1 << 16) | 2:
raise SystemExit("Incompatible format version, please use the appropriate parser.")
registers = unpack_from("<{0}I".format(nbRegisters), data, 40)
codeOffset = 40 + 4 * nbRegisters
codeDump = data[codeOffset : codeOffset + codeDumpSize]
stackOffset = codeOffset + codeDumpSize
stackDump = data[stackOffset : stackOffset + stackDumpSize]
addtionalDataOffset = stackOffset + stackDumpSize
additionalData = data[addtionalDataOffset : addtionalDataOffset + additionalDataSize]
if processor == 9: print("Processor: ARM9")
else: print("Processor: ARM11 (core {0})".format(processor >> 16))
typeDetailsStr = ""
if exceptionType == 2:
if (registers[16] & 0x20) == 0 and codeDumpSize >= 4:
instr = unpack_from("<I", codeDump[-4:])[0]
if instr == 0xe12fff7e:
typeDetailsStr = " (kernel panic)"
elif instr == 0xef00003c:
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
elif (registers[16] & 0x20) == 1 and codeDumpSize >= 2:
instr = unpack_from("<I", codeDump[-4:])[0]
if instr == 0xdf3c:
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
elif processor != 9 and (registers[20] & 0x80000000) != 0:
typeDetailsStr = " (VFP exception)"
print("Exception type: {0}{1}".format("unknown" if exceptionType >= len(handledExceptionNames) else handledExceptionNames[exceptionType], typeDetailsStr))
if processor == 11 and exceptionType >= 2:
xfsr = registers[18] if exceptionType == 2 else registers[17]
print("Fault status: " + faultStatusSources[xfsr & 0xf])
if additionalDataSize != 0:
print("Current process: {0} ({1:016x})".format(additionalData[:8].decode("ascii"), unpack_from("<Q", additionalData, 8)[0]))
print("\nRegister dump:\n")
for i in range(0, nbRegisters - (nbRegisters % 2), 2):
if i == 16: print("")
print(makeRegisterLine(registerNames[i], registers[i], registerNames[i+1], registers[i+1]))
if nbRegisters % 2 == 1: print("{0:<15}{1:<20}".format(registerNames[nbRegisters - 1], "{0:08x}".format(registers[nbRegisters - 1])))
if processor == 11 and exceptionType == 3:
print("{0:<15}{1:<20}Access type: {2}".format("FAR", "{0:08x}".format(registers[19]), "Write" if registers[17] & (1 << 11) != 0 else "Read"))
thumb = registers[16] & 0x20 != 0
addr = registers[15] - codeDumpSize + (2 if thumb else 4)
print("\nCode dump:\n")
objdump_res = ""
try:
path = os.path.join(os.environ["DEVKITARM"], "bin", "arm-none-eabi-objdump")
if os.name == "nt" and path[0] == '/':
path = ''.join((path[1], ':', path[2:]))
objdump_res = subprocess.check_output((
path, "-marm", "-b", "binary",
"--adjust-vma="+hex(addr - codeOffset), "--start-address="+hex(addr),
"--stop-address="+hex(addr + codeDumpSize), "-D", "-z", "-M",
"reg-names-std" + (",force-thumb" if thumb else ""), args.filename
)).decode("utf-8")
objdump_res = '\n'.join(objdump_res[objdump_res.find('<.data+'):].split('\n')[1:])
except: objdump_res = ""
print(objdump_res if objdump_res != "" else hexdump(addr, codeDump))
print("\nStack dump:\n")
print(hexdump(registers[13], stackDump))
if __name__ == "__main__":
main()

View File

@@ -1,13 +0,0 @@
from setuptools import setup, find_packages
setup(
name='luma3ds_exception_dump_parser',
version='1.2',
url='https://github.com/AuroraWright/Luma3DS',
author='TuxSH',
license='GPLv3',
description='Parses Luma3DS exception dumps',
install_requires=[''],
packages=find_packages(),
entry_points={'console_scripts': ['luma3ds_exception_dump_parser=luma3ds_exception_dump_parser.__main__:main']},
)