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,26 +356,37 @@ impl NormalFile { | ||||
| } | ||||
| 
 | ||||
| impl BomManagement { | ||||
|     fn add_target_management(&mut self, mut target_management: TargetManagement, root_dir: &str) { | ||||
|         // First, we need to resolve environmental variables
 | ||||
|         target_management.resolve_environmental_variables(); | ||||
|         let TargetManagement { | ||||
|             dirs_to_make, | ||||
|             links_to_create, | ||||
|             dirs_to_copy, | ||||
|             files_to_copy, | ||||
|             files_autodep, | ||||
|         } = target_management; | ||||
|         self.dirs_to_make.extend(dirs_to_make.into_iter()); | ||||
|         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); | ||||
|     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 { | ||||
|                 dirs_to_make, | ||||
|                 links_to_create, | ||||
|                 dirs_to_copy, | ||||
|                 files_to_copy, | ||||
|                 files_autodep, | ||||
|             } = target_management; | ||||
|             self.dirs_to_make.extend(dirs_to_make.into_iter()); | ||||
|             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()); | ||||
|             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