fix last commit. improve process code.

master
WangRunji 6 years ago
parent e3fb47a03e
commit 6923efd250

@ -1,3 +1,10 @@
# Commands:
# make build Build
# make run Build and run in QEMU
# make justrun Run the last build
# 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
#

@ -3,7 +3,7 @@ use core::fmt;
use log::*;
use spin::{Mutex, RwLock};
use xmas_elf::{ElfFile, header, program::{Flags, Type}};
use xmas_elf::{ElfFile, header, program::{Flags, Type, SegmentData}};
use rcore_memory::PAGE_SIZE;
use rcore_thread::Tid;
use core::str;
@ -183,26 +183,22 @@ impl Thread {
pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box<Thread>
where Iter: Iterator<Item=&'a str>
{
// Parse elf
// Parse ELF
let elf = ElfFile::new(data).expect("failed to read elf");
let is32 = match elf.header.pt2 {
header::HeaderPt2::Header32(_) => true,
header::HeaderPt2::Header64(_) => false,
};
// Check ELF type
match elf.header.pt2.type_().as_type() {
header::Type::Executable => {
// panic!("ELF is not shared object");
},
header::Type::Executable => {},
header::Type::SharedObject => {},
_ => panic!("ELF is not executable or shared object"),
}
if let Some(interp) = elf.program_iter().filter(|ph| ph.get_type() == Ok(Type::Interp)).next() {
let offset = interp.offset() as usize;
let size = interp.file_size() as usize - 1; // skip last '\0'
if offset + size < data.len() {
if let Ok(loader_path) = str::from_utf8(&data[offset..(offset+size)]) {
// Check interpreter
if let Ok(loader_path) = elf.get_interpreter() {
// assuming absolute path
if let Ok(inode) = crate::fs::ROOT_INODE.lookup_follow(&loader_path[1..], FOLLOW_MAX_DEPTH) {
if let Ok(buf) = inode.read_as_vec() {
@ -218,16 +214,10 @@ impl Thread {
} else {
warn!("loader specified as {} but not found", &loader_path);
}
} else {
warn!("loader specified but not found");
}
} else {
warn!("loader specified but invalid");
}
}
// Make page table
let (mut vm, entry_addr) = memory_set_from(&elf);
let mut vm = elf.make_memory_set();
// User stack
use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER32_STACK_OFFSET};
@ -240,20 +230,14 @@ impl Thread {
ustack_top
};
// Make init info
let init_info = ProcInitInfo {
args: args.map(|s| String::from(s)).collect(),
envs: BTreeMap::new(),
auxv: {
let mut map = BTreeMap::new();
if let Some(phdr) = elf.program_iter()
.find(|ph| ph.get_type() == Ok(Type::Phdr)) {
// if phdr exists in program header, use it
map.insert(abi::AT_PHDR, phdr.virtual_addr() as usize);
} else if let Some(elf_addr) = elf.program_iter().find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) {
// otherwise, check if elf is loaded from the beginning, then phdr can be inferred.
map.insert(abi::AT_PHDR, elf_addr.virtual_addr() as usize + elf.header.pt2.ph_offset() as usize);
} else {
warn!("new_user: no phdr found, tls might not work");
if let Some(phdr_vaddr) = elf.get_phdr_vaddr() {
map.insert(abi::AT_PHDR, phdr_vaddr as usize);
}
map.insert(abi::AT_PHENT, elf.header.pt2.ph_entry_size() as usize);
map.insert(abi::AT_PHNUM, elf.header.pt2.ph_count() as usize);
@ -274,6 +258,8 @@ impl Thread {
files.insert(1, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false })));
files.insert(2, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false })));
let entry_addr = elf.header.pt2.entry_point() as usize;
Box::new(Thread {
context: unsafe {
Context::new_user_thread(
@ -299,9 +285,11 @@ impl Thread {
/// Fork a new process from current one
pub fn fork(&self, tf: &TrapFrame) -> Box<Thread> {
// Clone memory set, make a new page table
let vm = self.proc.lock().vm.clone();
let files = self.proc.lock().files.clone();
let cwd = self.proc.lock().cwd.clone();
let proc = self.proc.lock();
let vm = proc.vm.clone();
let files = proc.files.clone();
let cwd = proc.cwd.clone();
drop(proc);
let parent = Some(self.proc.clone());
debug!("fork: finish clone MemorySet");
@ -324,7 +312,6 @@ impl Thread {
}
}
Box::new(Thread {
context: unsafe { Context::new_fork(tf, kstack.top(), vm.token()) },
kstack,
@ -376,31 +363,46 @@ impl Process {
}
}
trait ToMemoryAttr {
fn to_attr(&self) -> MemoryAttr;
}
impl ToMemoryAttr for Flags {
fn to_attr(&self) -> MemoryAttr {
let mut flags = MemoryAttr::default().user();
// FIXME: handle readonly
if self.is_execute() { flags = flags.execute(); }
flags
}
}
/// Helper functions to process ELF file
trait ElfExt {
/// Generate a MemorySet according to the ELF file.
/// Also return the real entry point address.
fn memory_set_from(elf: &ElfFile<'_>) -> (MemorySet, usize) {
fn make_memory_set(&self) -> MemorySet;
/// Get interpreter string if it has.
fn get_interpreter(&self) -> Result<&str, &str>;
/// Get virtual address of PHDR section if it has.
fn get_phdr_vaddr(&self) -> Option<u64>;
}
impl ElfExt for ElfFile<'_> {
fn make_memory_set(&self) -> MemorySet {
debug!("creating MemorySet from ELF");
let mut ms = MemorySet::new();
let entry = elf.header.pt2.entry_point() as usize;
// [NoMMU] Get total memory size and alloc space
let va_begin = elf.program_iter()
.filter(|ph| ph.get_type() == Ok(Type::Load))
.map(|ph| ph.virtual_addr()).min().unwrap() as usize;
let va_end = elf.program_iter()
.filter(|ph| ph.get_type() == Ok(Type::Load))
.map(|ph| ph.virtual_addr() + ph.mem_size()).max().unwrap() as usize;
let va_size = va_end - va_begin;
for ph in elf.program_iter() {
for ph in self.program_iter() {
if ph.get_type() != Ok(Type::Load) {
continue;
}
let virt_addr = ph.virtual_addr() as usize;
let offset = ph.offset() as usize;
let file_size = ph.file_size() as usize;
let mem_size = ph.mem_size() as usize;
let data = match ph.get_data(self).unwrap() {
SegmentData::Undefined(data) => data,
_ => unreachable!(),
};
// Get target slice
let target = {
@ -410,25 +412,41 @@ fn memory_set_from(elf: &ElfFile<'_>) -> (MemorySet, usize) {
// Copy data
unsafe {
ms.with(|| {
if file_size != 0 {
target[..file_size].copy_from_slice(&elf.input[offset..offset + file_size]);
if data.len() != 0 {
target[..data.len()].copy_from_slice(data);
}
target[file_size..].iter_mut().for_each(|x| *x = 0);
target[data.len()..].iter_mut().for_each(|x| *x = 0);
});
}
}
(ms, entry)
ms
}
trait ToMemoryAttr {
fn to_attr(&self) -> MemoryAttr;
fn get_interpreter(&self) -> Result<&str, &str> {
let header = self.program_iter()
.filter(|ph| ph.get_type() == Ok(Type::Interp))
.next().ok_or("no interp header")?;
let data = match header.get_data(self)? {
SegmentData::Undefined(data) => data,
_ => unreachable!(),
};
let path = str::from_utf8(data)
.map_err(|_| "failed to convert to utf8")?;
Ok(path)
}
impl ToMemoryAttr for Flags {
fn to_attr(&self) -> MemoryAttr {
let mut flags = MemoryAttr::default().user();
// FIXME: handle readonly
if self.is_execute() { flags = flags.execute(); }
flags
fn get_phdr_vaddr(&self) -> Option<u64> {
if let Some(phdr) = self.program_iter()
.find(|ph| ph.get_type() == Ok(Type::Phdr)) {
// if phdr exists in program header, use it
Some(phdr.virtual_addr())
} else if let Some(elf_addr) = self.program_iter()
.find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) {
// otherwise, check if elf is loaded from the beginning, then phdr can be inferred.
Some(elf_addr.virtual_addr() + self.header.pt2.ph_offset())
} else {
warn!("elf: no phdr found, tls might not work");
None
}
}
}

Loading…
Cancel
Save