Infer default dynamic loader
This commit is contained in:
		
							parent
							
								
									9a85361e35
								
							
						
					
					
						commit
						4a69b58479
					
				@ -8,7 +8,8 @@
 | 
			
		||||
use crate::error::{FILE_NOT_EXISTS_ERROR, INVALID_BOM_FILE_ERROR};
 | 
			
		||||
use crate::util::{
 | 
			
		||||
    check_file_hash, copy_dir, copy_file, copy_shared_object, create_link, dest_in_root,
 | 
			
		||||
    find_dependent_shared_objects, find_included_bom_file, mkdir, resolve_envs,
 | 
			
		||||
    find_dependent_shared_objects, find_included_bom_file, infer_default_loader, mkdir,
 | 
			
		||||
    resolve_envs,
 | 
			
		||||
};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use serde_yaml;
 | 
			
		||||
@ -136,12 +137,14 @@ impl Bom {
 | 
			
		||||
    fn get_bom_management(self, root_dir: &str) -> BomManagement {
 | 
			
		||||
        let mut bom_management = BomManagement::default();
 | 
			
		||||
        bom_management.dirs_to_make.push(root_dir.to_string()); // init root dir
 | 
			
		||||
        let mut target_managements = Vec::new();
 | 
			
		||||
        if let Some(ref targets) = self.targets {
 | 
			
		||||
            for target in targets {
 | 
			
		||||
                let target_management = target.get_target_management(root_dir);
 | 
			
		||||
                bom_management.add_target_management(target_management, root_dir);
 | 
			
		||||
                target_managements.push(target_management);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        bom_management.add_target_managements(target_managements, root_dir);
 | 
			
		||||
        bom_management
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -353,7 +356,13 @@ impl NormalFile {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl BomManagement {
 | 
			
		||||
    fn add_target_management(&mut self, mut target_management: TargetManagement, root_dir: &str) {
 | 
			
		||||
    fn add_target_managements(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        target_managements: Vec<TargetManagement>,
 | 
			
		||||
        root_dir: &str,
 | 
			
		||||
    ) {
 | 
			
		||||
        let mut files_autodep_in_bom = Vec::new();
 | 
			
		||||
        for mut target_management in target_managements.into_iter() {
 | 
			
		||||
             // First, we need to resolve environmental variables
 | 
			
		||||
            target_management.resolve_environmental_variables();
 | 
			
		||||
            let TargetManagement {
 | 
			
		||||
@ -367,12 +376,17 @@ impl BomManagement {
 | 
			
		||||
            self.links_to_create.extend(links_to_create.into_iter());
 | 
			
		||||
            self.dirs_to_copy.extend(dirs_to_copy.into_iter());
 | 
			
		||||
            self.files_to_copy.extend(files_to_copy.into_iter());
 | 
			
		||||
        self.autodep(files_autodep, root_dir);
 | 
			
		||||
            files_autodep_in_bom.extend(files_autodep.into_iter());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.autodep(files_autodep_in_bom, root_dir);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn autodep(&mut self, files_autodep: Vec<String>, root_dir: &str) {
 | 
			
		||||
        let default_loader = infer_default_loader(&files_autodep);
 | 
			
		||||
        debug!("default loader in autodep: {:?}", default_loader);
 | 
			
		||||
        for file_autodep in files_autodep.iter() {
 | 
			
		||||
            let mut shared_objects = find_dependent_shared_objects(file_autodep);
 | 
			
		||||
            let mut shared_objects = find_dependent_shared_objects(file_autodep, &default_loader);
 | 
			
		||||
            for (src, dest) in shared_objects.drain() {
 | 
			
		||||
                let dest_path = dest_in_root(root_dir, &dest);
 | 
			
		||||
                // First, we create dir to store the dependency
 | 
			
		||||
 | 
			
		||||
@ -196,11 +196,14 @@ pub fn calculate_file_hash(filename: &str) -> String {
 | 
			
		||||
/// and analyze the stdout. We use regex to match the pattern of the loader output.
 | 
			
		||||
/// The loader will automatically find all dependencies recursively, i.e., it will also find dependencies
 | 
			
		||||
/// for each shared object, so we only need to analyze the top elf file.
 | 
			
		||||
pub fn find_dependent_shared_objects(file_path: &str) -> HashSet<(String, String)> {
 | 
			
		||||
pub fn find_dependent_shared_objects(
 | 
			
		||||
    file_path: &str,
 | 
			
		||||
    default_loader: &Option<(String, String)>,
 | 
			
		||||
) -> HashSet<(String, String)> {
 | 
			
		||||
    let mut shared_objects = HashSet::new();
 | 
			
		||||
    // find dependencies for the input file
 | 
			
		||||
    // first, we find the dynamic loader for the elf file, if we can't find the loader, return empty shared objects
 | 
			
		||||
    let dynamic_loader = auto_dynamic_loader(file_path);
 | 
			
		||||
    let dynamic_loader = auto_dynamic_loader(file_path, default_loader);
 | 
			
		||||
    if dynamic_loader.is_none() {
 | 
			
		||||
        return shared_objects;
 | 
			
		||||
    }
 | 
			
		||||
@ -260,11 +263,37 @@ fn command_output_of_executing_dynamic_loader(
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// This function will try to find a dynamic loader for a elf file automatically
 | 
			
		||||
/// If we find the loader, we will return Some((loader_src, loader_dest)).
 | 
			
		||||
/// This is because the loader_src and loader_dest may not be the same directory.
 | 
			
		||||
/// If we can't find the loader, this function will return None
 | 
			
		||||
fn auto_dynamic_loader(filename: &str) -> Option<(String, String)> {
 | 
			
		||||
/// This function will try to find a dynamic loader for a elf file automatically.
 | 
			
		||||
/// If will first try to read the interp section of elf file. If the file does not have interp section,
 | 
			
		||||
/// and the default loader is *NOT* None, it will return default loader.
 | 
			
		||||
/// It there is no interp section and default loader is None, it will return None.
 | 
			
		||||
/// If we find the loader, we will return Some((occlum_elf_loader, inlined_elf_loader)).
 | 
			
		||||
/// This is because the occlum_elf_loader and inlined_elf_loader may not be the same directory.
 | 
			
		||||
fn auto_dynamic_loader(
 | 
			
		||||
    filename: &str,
 | 
			
		||||
    default_loader: &Option<(String, String)>,
 | 
			
		||||
) -> Option<(String, String)> {
 | 
			
		||||
    let elf_file = match elf::File::open_path(filename) {
 | 
			
		||||
        Err(_) => return None,
 | 
			
		||||
        Ok(elf_file) => elf_file,
 | 
			
		||||
    };
 | 
			
		||||
    match elf_file.get_section(".interp") {
 | 
			
		||||
        None => {
 | 
			
		||||
            // When the elf file does not has interp section
 | 
			
		||||
            // 1. if we have default loader, we will return the default loader
 | 
			
		||||
            // 2. Otherwise we will return None and give warning.
 | 
			
		||||
            if let Some(default_loader) = default_loader {
 | 
			
		||||
                return Some(default_loader.clone());
 | 
			
		||||
            } else {
 | 
			
		||||
                warn!("cannot autodep for file {}. ", filename);
 | 
			
		||||
                return None;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Some(_) => read_loader_from_interp_section(filename),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn read_loader_from_interp_section(filename: &str) -> Option<(String, String)> {
 | 
			
		||||
    let elf_file = match elf::File::open_path(filename) {
 | 
			
		||||
        Err(_) => return None,
 | 
			
		||||
        Ok(elf_file) => elf_file,
 | 
			
		||||
@ -293,6 +322,24 @@ fn auto_dynamic_loader(filename: &str) -> Option<(String, String)> {
 | 
			
		||||
    ))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// try to infer default loader for all files to autodep
 | 
			
		||||
// If all files with .interp section points to the same loader,
 | 
			
		||||
// this loader will be viewed as the default loader
 | 
			
		||||
// Otherwise, no default loader can be found.
 | 
			
		||||
pub fn infer_default_loader(files_autodep: &Vec<String>) -> Option<(String, String)> {
 | 
			
		||||
    let mut loaders = HashSet::new();
 | 
			
		||||
    for filename in files_autodep.iter() {
 | 
			
		||||
        if let Some(loader) = read_loader_from_interp_section(filename) {
 | 
			
		||||
            loaders.insert(loader);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if loaders.len() == 1 {
 | 
			
		||||
        return loaders.into_iter().next();
 | 
			
		||||
    } else {
 | 
			
		||||
        return None;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// resolve the results of dynamic loader to extract dependencies
 | 
			
		||||
pub fn extract_dependencies_from_output(
 | 
			
		||||
    file_path: &str,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user