Skip to content

Commit db8f45d

Browse files
committed
Add ksymbol support
1 parent 2b93d53 commit db8f45d

File tree

7 files changed

+166
-8
lines changed

7 files changed

+166
-8
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
**/target/
99

1010
os/src/link_app.S
11+
os/src/ksymbol.S
1112
os/src/linker.ld
1213
os/last-*
1314
os/Cargo.lock

os/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ bitflags = "1.2.1"
1414
xmas-elf = "0.7.0"
1515
log = "0.4"
1616
sbi-rt = { version = "0.0.2", features = ["legacy"] }
17+
rustc-demangle = "0.1.24"
1718

1819
[profile.release]
1920
debug = true

os/Makefile

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# Building
22
TARGET := riscv64gc-unknown-none-elf
33
MODE := release
4-
KERNEL_ELF := target/$(TARGET)/$(MODE)/os
4+
TARGET_PATH := target/$(TARGET)/$(MODE)
5+
KERNEL_ELF := $(TARGET_PATH)/os
6+
KERNEL_SYMTAB := $(TARGET_PATH)/os.symtab
57
KERNEL_BIN := $(KERNEL_ELF).bin
6-
DISASM_TMP := target/$(TARGET)/$(MODE)/asm
8+
DISASM_TMP := $(TARGET_PATH)/asm
79

810
# BOARD
911
BOARD := qemu
@@ -40,6 +42,13 @@ kernel:
4042
@cd ../user && make build
4143
@echo Platform: $(BOARD)
4244
@cp src/linker-$(BOARD).ld src/linker.ld
45+
@rm -f $(KERNEL_SYMTAB)
46+
@cargo build $(MODE_ARG)
47+
@echo Extract symbol table and build again
48+
# @$(OBJCOPY) --strip-debug $(KERNEL_ELF) $(KERNEL_SYMTAB)
49+
# @$(OBJCOPY) --remove-section .text --remove-section .data $(KERNEL_SYMTAB) $(KERNEL_SYMTAB)
50+
# @$(OBJCOPY) --remove-section .bss --remove-section .rodata $(KERNEL_SYMTAB) $(KERNEL_SYMTAB)
51+
@$(OBJCOPY) --only-keep-debug $(KERNEL_ELF) $(KERNEL_SYMTAB)
4352
@cargo build $(MODE_ARG)
4453
@rm src/linker.ld
4554

os/build.rs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
use std::fs::{read_dir, File};
22
use std::io::{Result, Write};
3+
use std::path::Path;
4+
5+
static USER_TARGET_PATH: &str = "../user/target/riscv64gc-unknown-none-elf/release/";
6+
static KERNEL_TARGET_PATH: &str = "target/riscv64gc-unknown-none-elf/release/";
37

48
fn main() {
59
println!("cargo:rerun-if-changed=../user/src/");
6-
println!("cargo:rerun-if-changed={}", TARGET_PATH);
10+
println!("cargo:rerun-if-changed={}", USER_TARGET_PATH);
11+
println!("cargo:rerun-if-changed=src/");
712
insert_app_data().unwrap();
13+
insert_kernel_symbol_elf().unwrap();
814
}
915

10-
static TARGET_PATH: &str = "../user/target/riscv64gc-unknown-none-elf/release/";
11-
1216
fn insert_app_data() -> Result<()> {
1317
let mut f = File::create("src/link_app.S").unwrap();
1418
let mut apps: Vec<_> = read_dir("../user/src/bin")
@@ -50,8 +54,36 @@ _num_app:
5054
app_{0}_start:
5155
.incbin "{2}{1}"
5256
app_{0}_end:"#,
53-
idx, app, TARGET_PATH
57+
idx, app, USER_TARGET_PATH
58+
)?;
59+
}
60+
Ok(())
61+
}
62+
63+
fn insert_kernel_symbol_elf() -> Result<()> {
64+
let mut f = File::create("src/ksymbol.S")?;
65+
let symtab_path = format!("{}os.symtab", KERNEL_TARGET_PATH);
66+
writeln!(
67+
f,
68+
r#"
69+
.section .rodata
70+
.align 12
71+
.global _start_ksymbol_elf
72+
_start_ksymbol_elf:"#
73+
)?;
74+
if Path::exists(Path::new(&symtab_path)) {
75+
writeln!(
76+
f,
77+
r#"
78+
.incbin "{}""#,
79+
symtab_path.as_str()
5480
)?;
5581
}
82+
writeln!(
83+
f,
84+
r#"
85+
.global _end_ksymbol_elf
86+
_end_ksymbol_elf:"#
87+
)?;
5688
Ok(())
5789
}

os/src/console.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ impl Write for Stdout {
1414
}
1515
}
1616

17+
/// Print a str with format to stdout.
1718
pub fn print(args: fmt::Arguments) {
1819
Stdout.write_fmt(args).unwrap();
1920
}

os/src/ksymbol.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//! ksymbol
2+
3+
use alloc::string::{String, ToString};
4+
use core::fmt::Debug;
5+
use rustc_demangle::demangle;
6+
use xmas_elf::{sections::SectionData::*, symbol_table::Entry};
7+
8+
core::arch::global_asm!(include_str!("ksymbol.S"));
9+
10+
extern "C" {
11+
fn _start_ksymbol_elf();
12+
fn _end_ksymbol_elf();
13+
fn stext();
14+
fn etext();
15+
}
16+
17+
/// KernelFuncEntry describes a kernel func, which is especially useful
18+
/// for dumping kernel symbols when backtracing the kernel stack.
19+
pub struct KernelFuncEntry {
20+
func_name: &'static str,
21+
start_addr: usize,
22+
func_size: usize,
23+
}
24+
25+
impl KernelFuncEntry {
26+
/// Mangled func name of the kernel func.
27+
fn func_name(&self) -> &'static str {
28+
self.func_name
29+
}
30+
31+
/// Entry address of the kernel func.
32+
fn start_addr(&self) -> usize {
33+
self.start_addr
34+
}
35+
36+
/// Size in bytes of the kernel func.
37+
fn func_size(&self) -> usize {
38+
self.func_size
39+
}
40+
}
41+
42+
impl Debug for KernelFuncEntry {
43+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44+
write!(
45+
f,
46+
"KernelFuncEntry {{func_name: {}, entry_addr: {:#x}, func_size: {:#x} bytes}}",
47+
self.func_name(),
48+
self.start_addr(),
49+
self.func_size()
50+
)
51+
}
52+
}
53+
54+
/// Return the [KernelFuncEntry] of a kernel func by which the input addr is covered.
55+
///
56+
/// If such kernel func cannot be found, return **None**.
57+
pub fn kernel_func_by_addr(addr: usize) -> Option<KernelFuncEntry> {
58+
// SAFETY: The build process of os can guarantee that the kernel symbol elf
59+
// can be found between _start_ksymbol_elf and _end_ksymbol_elf. See os/src/build.rs
60+
// for more details.
61+
let elf_data = unsafe {
62+
core::slice::from_raw_parts(
63+
_start_ksymbol_elf as *const u8,
64+
_end_ksymbol_elf as usize - _start_ksymbol_elf as usize,
65+
)
66+
};
67+
let elf = xmas_elf::ElfFile::new(elf_data).unwrap();
68+
let symtab = elf.find_section_by_name(".symtab").unwrap();
69+
let strtab = elf.find_section_by_name(".strtab").unwrap();
70+
let strtab_offset = strtab.offset() as usize;
71+
let strtab_size = strtab.size() as usize;
72+
let strtab_data = &elf_data[strtab_offset..strtab_offset + strtab_size];
73+
if let SymbolTable64(symtab_data) = symtab.get_data(&elf).unwrap() {
74+
symtab_data
75+
.iter()
76+
.find(|&entry| {
77+
if entry.size() == 0 {
78+
return false;
79+
}
80+
if entry.value() < stext as u64 || entry.value() > etext as u64 {
81+
return false;
82+
}
83+
let addr = addr as u64;
84+
addr >= entry.value() && addr < entry.value() + entry.size()
85+
})
86+
.map(|entry| {
87+
let func_name_len = strtab_data[entry.name() as usize..]
88+
.iter()
89+
.enumerate()
90+
.find(|&pair| *pair.1 == 0)
91+
.map(|pair| pair.0)
92+
.unwrap();
93+
// SAFETY: We can guarantee that this is a valid str due to the correctness of
94+
// the ELF format.
95+
let func_name = unsafe {
96+
core::str::from_raw_parts(&strtab_data[entry.name() as usize], func_name_len)
97+
};
98+
KernelFuncEntry {
99+
func_name,
100+
start_addr: entry.value() as usize,
101+
func_size: entry.size() as usize,
102+
}
103+
})
104+
} else {
105+
None
106+
}
107+
}
108+
109+
/// Return demangled func name as a String of a mangled func name.
110+
pub fn demangled_func_name(func_name: &str) -> String {
111+
demangle(func_name).to_string()
112+
}

os/src/main.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616
//! userspace.
1717
1818
#![deny(missing_docs)]
19-
#![deny(warnings)]
19+
// #![deny(warnings)]
2020
#![no_std]
2121
#![no_main]
2222
#![feature(panic_info_message)]
2323
#![feature(alloc_error_handler)]
24+
#![feature(str_from_raw_parts)]
2425

2526
extern crate alloc;
2627

@@ -31,8 +32,9 @@ extern crate bitflags;
3132
mod board;
3233

3334
#[macro_use]
34-
mod console;
35+
pub mod console;
3536
mod config;
37+
pub mod ksymbol;
3638
mod lang_items;
3739
mod loader;
3840
mod mm;

0 commit comments

Comments
 (0)