From acab23d1e1fc1779b40caff0e710b352857ca7e8 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Tue, 13 Jun 2017 21:43:37 -0600
Subject: [PATCH] Add symbol lookup (still very WIP)

---
 Cargo.toml             |  2 +-
 src/elf.rs             | 86 +++++++++++++++++++++++++++++++++++++++++-
 src/interrupt/trace.rs | 43 +++++++++++++++++++++
 src/start.rs           |  5 +++
 4 files changed, 133 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index a6b285a6..bcc7579b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,7 +16,7 @@ raw-cpuid = { git = "https://github.com/gz/rust-cpuid", branch = "master" }
 redox_syscall = "0.1"
 
 [dependencies.goblin]
-version = "0.0.8"
+version = "0.0.10"
 default-features = false
 features = ["elf32", "elf64"]
 
diff --git a/src/elf.rs b/src/elf.rs
index bf484fe9..240cf56e 100644
--- a/src/elf.rs
+++ b/src/elf.rs
@@ -4,11 +4,13 @@ use collections::String;
 
 use core::str;
 
+use goblin::elf::section_header::SHT_SYMTAB;
+
 #[cfg(target_arch = "x86")]
-pub use goblin::elf32::{header, program_header};
+pub use goblin::elf32::{header, program_header, section_header, sym};
 
 #[cfg(target_arch = "x86_64")]
-pub use goblin::elf64::{header, program_header};
+pub use goblin::elf64::{header, program_header, section_header, sym};
 
 /// An ELF executable
 pub struct Elf<'a> {
@@ -33,6 +35,14 @@ impl<'a> Elf<'a> {
         }
     }
 
+    pub fn sections(&'a self) -> ElfSections<'a> {
+        ElfSections {
+            data: self.data,
+            header: self.header,
+            i: 0
+        }
+    }
+
     pub fn segments(&'a self) -> ElfSegments<'a> {
         ElfSegments {
             data: self.data,
@@ -41,12 +51,58 @@ impl<'a> Elf<'a> {
         }
     }
 
+    pub fn symbols(&'a self) -> Option<ElfSymbols<'a>> {
+        let mut symtab_opt = None;
+        for section in self.sections() {
+            if section.sh_type == SHT_SYMTAB {
+                symtab_opt = Some(section);
+                break;
+            }
+        }
+
+        if let Some(symtab) = symtab_opt {
+            Some(ElfSymbols {
+                data: self.data,
+                header: self.header,
+                symtab: symtab,
+                i: 0
+            })
+        } else {
+            None
+        }
+    }
+
     /// Get the entry field of the header
     pub fn entry(&self) -> usize {
         self.header.e_entry as usize
     }
 }
 
+pub struct ElfSections<'a> {
+    data: &'a [u8],
+    header: &'a header::Header,
+    i: usize
+}
+
+impl<'a> Iterator for ElfSections<'a> {
+    type Item = &'a section_header::SectionHeader;
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.i < self.header.e_shnum as usize {
+            let item = unsafe {
+                &* ((
+                        self.data.as_ptr() as usize
+                        + self.header.e_shoff as usize
+                        + self.i * self.header.e_shentsize as usize
+                    ) as *const section_header::SectionHeader)
+            };
+            self.i += 1;
+            Some(item)
+        } else {
+            None
+        }
+    }
+}
+
 pub struct ElfSegments<'a> {
     data: &'a [u8],
     header: &'a header::Header,
@@ -71,3 +127,29 @@ impl<'a> Iterator for ElfSegments<'a> {
         }
     }
 }
+
+pub struct ElfSymbols<'a> {
+    data: &'a [u8],
+    header: &'a header::Header,
+    symtab: &'a section_header::SectionHeader,
+    i: usize
+}
+
+impl<'a> Iterator for ElfSymbols<'a> {
+    type Item = &'a sym::Sym;
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.i < (self.symtab.sh_size as usize) / sym::SIZEOF_SYM {
+            let item = unsafe {
+                &* ((
+                        self.data.as_ptr() as usize
+                        + self.symtab.sh_offset as usize
+                        + self.i * sym::SIZEOF_SYM
+                    ) as *const sym::Sym)
+            };
+            self.i += 1;
+            Some(item)
+        } else {
+            None
+        }
+    }
+}
diff --git a/src/interrupt/trace.rs b/src/interrupt/trace.rs
index 0778ac01..dcc1b443 100644
--- a/src/interrupt/trace.rs
+++ b/src/interrupt/trace.rs
@@ -22,6 +22,7 @@ pub unsafe fn stack_trace() {
                 }
                 println!("  {:>016X}: {:>016X}", rbp, rip);
                 rbp = *(rbp as *const usize);
+                symbol_trace(rip);
             } else {
                 println!("  {:>016X}: GUARD PAGE", rbp);
                 break;
@@ -31,3 +32,45 @@ pub unsafe fn stack_trace() {
         }
     }
 }
+
+
+pub unsafe fn symbol_trace(addr: usize) {
+    use core::slice;
+    use core::sync::atomic::Ordering;
+
+    use elf::Elf;
+    use start::{KERNEL_BASE, KERNEL_SIZE};
+
+    let kernel_ptr = (KERNEL_BASE.load(Ordering::SeqCst) + ::KERNEL_OFFSET) as *const u8;
+    let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst));
+    if let Ok(elf) = Elf::from(kernel_slice) {
+        let mut strtab_opt = None;
+        for section in elf.sections() {
+            if section.sh_type == ::goblin::elf::section_header::SHT_STRTAB {
+                strtab_opt = Some(section);
+                break;
+            }
+        }
+
+        if let Some(symbols) = elf.symbols() {
+            for sym in symbols {
+                if addr >= sym.st_value as usize && addr < (sym.st_value + sym.st_size) as usize {
+                    println!("    {:>016X}+{:>04X}", sym.st_value, addr - sym.st_value as usize);
+
+                    if let Some(strtab) = strtab_opt {
+                        print!("    ");
+                        
+                        for &b in elf.data[strtab.sh_offset as usize + sym.st_name as usize ..].iter() {
+                            if b == 0 {
+                                break;
+                            }
+                            print!("{}", b as char);
+                        }
+
+                        println!("");
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/start.rs b/src/start.rs
index f95a1c3f..bf9dedac 100644
--- a/src/start.rs
+++ b/src/start.rs
@@ -26,6 +26,8 @@ static mut TBSS_TEST_ZERO: usize = 0;
 #[thread_local]
 static mut TDATA_TEST_NONZERO: usize = 0xFFFFFFFFFFFFFFFF;
 
+pub static KERNEL_BASE: AtomicUsize = ATOMIC_USIZE_INIT;
+pub static KERNEL_SIZE: AtomicUsize = ATOMIC_USIZE_INIT;
 pub static CPU_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
 pub static AP_READY: AtomicBool = ATOMIC_BOOL_INIT;
 static BSP_READY: AtomicBool = ATOMIC_BOOL_INIT;
@@ -47,6 +49,9 @@ pub unsafe extern fn kstart(kernel_base: usize, kernel_size: usize, stack_base:
             assert_eq!(DATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF);
         }
 
+        KERNEL_BASE.store(kernel_base, Ordering::SeqCst);
+        KERNEL_SIZE.store(kernel_size, Ordering::SeqCst);
+
         println!("Kernel: {:X}:{:X}", kernel_base, kernel_base + kernel_size);
         println!("Stack: {:X}:{:X}", stack_base, stack_base + stack_size);
 
-- 
GitLab