diff --git a/.travis.yml b/.travis.yml index dc99b3c..98fb352 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,9 +40,9 @@ install: fi - if [ $ARCH = aarch64 ]; then if [ $TRAVIS_OS_NAME = linux ]; then - wget https://web.stanford.edu/class/cs140e/files/aarch64-none-elf-linux-x64.tar.gz; - tar -xzvf aarch64-none-elf-linux-x64.tar.gz; - export PATH=$PATH:$PWD/aarch64-none-elf/bin; + wget https://developer.arm.com/-/media/Files/downloads/gnu-a/8.2-2018.11/gcc-arm-8.2-2018.11-x86_64-aarch64-elf.tar.xz; + tar -xvf gcc-arm-8.2-2018.11-x86_64-aarch64-elf.tar.xz; + export PATH=$PATH:$PWD/gcc-arm-8.2-2018.11-x86_64-aarch64-elf/bin; elif [ $TRAVIS_OS_NAME = osx ]; then brew tap SergioBenitez/osxct; brew install aarch64-none-elf; diff --git a/kernel/Makefile b/kernel/Makefile index a14b5cd..6014788 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -5,6 +5,7 @@ # make doc Generate docs # make asm Open the deassemble file of the last build # make header Open 'objdump -h' of the last build +# make addr2line Use addr2line to recover line info in backtrace # make clean Clean # # Options: @@ -141,6 +142,9 @@ else ifeq ($(arch), riscv64) prefix := riscv64-unknown-elf- else ifeq ($(arch), aarch64) prefix ?= aarch64-none-elf- +ifeq (,$(shell which $(prefix)ld)) + prefix := aarch64-elf- +endif endif ld := $(prefix)ld @@ -258,4 +262,8 @@ ifeq ($(board), k210) install: $(bin) ## baudrate no more than 600000 @python3 ../tools/k210/kflash.py $(bin) -b 600000 -endif \ No newline at end of file +endif + +.PHONY: +addr2line: + @python3 ../tools/addr2line.py $(prefix)addr2line $(arch) diff --git a/kernel/build-rv64 b/kernel/build-rv64 index 733c905..42fcb7d 100755 --- a/kernel/build-rv64 +++ b/kernel/build-rv64 @@ -102,6 +102,9 @@ then elif [[ -d $CARGO_PATH/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.4 ]] then COMPILER_BUILTINS_PATH=$CARGO_PATH/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.4 + elif [[ -d $CARGO_PATH/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.5 ]] + then + COMPILER_BUILTINS_PATH=$CARGO_PATH/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.5 else echo "Cannot find compiler_builtins crate! Please file an issue report" fi diff --git a/kernel/src/backtrace.rs b/kernel/src/backtrace.rs new file mode 100644 index 0000000..abf95fb --- /dev/null +++ b/kernel/src/backtrace.rs @@ -0,0 +1,66 @@ +use core::mem::size_of; + +extern "C" { + fn stext(); + fn etext(); +} + +/// Returns the current frame pointer. +#[inline(always)] +#[cfg(any(target_arch = "aarch64", target_arch = "riscv32", target_arch = "riscv64"))] +pub fn fp() -> usize { + let ptr: usize; + #[cfg(target_arch = "aarch64")] + unsafe { + asm!("mov $0, x29" : "=r"(ptr)); + } + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + unsafe { + asm!("mv $0, s0" : "=r"(ptr)); + } + + ptr +} + +/// Returns the current link register. +#[inline(always)] +#[cfg(any(target_arch = "aarch64", target_arch = "riscv32", target_arch = "riscv64"))] +pub fn lr() -> usize { + let ptr: usize; + #[cfg(target_arch = "aarch64")] + unsafe { + asm!("mov $0, x30" : "=r"(ptr)); + } + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + unsafe { + asm!("mv $0, ra" : "=r"(ptr)); + } + + ptr +} + +// Print the backtrace starting from the caller +pub fn backtrace() { + #[cfg(any(target_arch = "aarch64", target_arch = "riscv32", target_arch = "riscv64"))] + unsafe { + let mut current_pc = lr(); + let mut current_fp = fp(); + let mut stack_num = 0; + while current_pc >= stext as usize && current_pc <= etext as usize && current_fp as usize != 0 { + println!("#{} {:#018X} fp {:#018X}", stack_num, current_pc - size_of::(), current_fp); + stack_num = stack_num + 1; + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + { + current_fp = *(current_fp as *const usize).offset(-2); + current_pc = *(current_fp as *const usize).offset(-1); + } + #[cfg(target_arch = "aarch64")] + { + current_fp = *(current_fp as *const usize); + if current_fp != 0 { + current_pc = *(current_fp as *const usize).offset(1); + } + } + } + } +} diff --git a/kernel/src/lang.rs b/kernel/src/lang.rs index 27b0d21..903e137 100644 --- a/kernel/src/lang.rs +++ b/kernel/src/lang.rs @@ -3,6 +3,7 @@ use core::panic::PanicInfo; use core::alloc::Layout; use log::*; +use crate::backtrace; #[lang = "eh_personality"] extern fn eh_personality() { @@ -13,6 +14,7 @@ fn panic(info: &PanicInfo) -> ! { let location = info.location().unwrap(); let message = info.message().unwrap(); error!("\n\nPANIC in {} at line {}\n {}", location.file(), location.line(), message); + backtrace::backtrace(); loop { crate::arch::cpu::halt() } } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index ab18c1c..29e5ce0 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -28,6 +28,7 @@ mod fs; mod sync; mod trap; mod shell; +mod backtrace; #[allow(dead_code)] #[cfg(target_arch = "x86_64")] diff --git a/kernel/targets/aarch64.json b/kernel/targets/aarch64.json index b0c24dc..149246a 100644 --- a/kernel/targets/aarch64.json +++ b/kernel/targets/aarch64.json @@ -31,5 +31,6 @@ "target-endian": "little", "target-pointer-width": "64", "target-family": "unix", - "disable-redzone": true + "disable-redzone": true, + "eliminate-frame-pointer": false } diff --git a/kernel/targets/riscv32.json b/kernel/targets/riscv32.json index ca35687..9430baf 100644 --- a/kernel/targets/riscv32.json +++ b/kernel/targets/riscv32.json @@ -31,5 +31,6 @@ "ptx-kernel", "msp430-interrupt", "x86-interrupt" - ] + ], + "eliminate-frame-pointer": false } diff --git a/kernel/targets/riscv64.json b/kernel/targets/riscv64.json index 4742c08..7cf840a 100644 --- a/kernel/targets/riscv64.json +++ b/kernel/targets/riscv64.json @@ -31,5 +31,6 @@ "ptx-kernel", "msp430-interrupt", "x86-interrupt" - ] + ], + "eliminate-frame-pointer": false } diff --git a/tools/addr2line.py b/tools/addr2line.py new file mode 100644 index 0000000..fa84228 --- /dev/null +++ b/tools/addr2line.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +import sys +import re +import subprocess + +print('Paste backtrace here, and then input EOF(Ctrl-D or Ctrl-Z) to get annotated backtrace.') +lines = sys.stdin.readlines() +addrline = sys.argv[1] +arch = sys.argv[2] +print('--------------------------------------') +for line in lines: + match = re.search('(#[0-9]+ )(0x[0-9A-F]+)( fp 0x[0-9A-F]+)', line) + if match: + addr = match.group(2) + process = subprocess.run([addrline, '-e', 'target/{0}/debug/rcore'.format(arch), '-f', '-C', addr], capture_output=True) + res = process.stdout.decode('utf-8') + print('{0}{1}{3} {2}'.format(match.group(1), match.group(2), res.strip(), match.group(3))) + else: + print(line, end='')