Infer default dynamic loader

This commit is contained in:
jianfengjiang 2021-09-22 19:32:56 +08:00 committed by Zongmin.Gu
parent 9a85361e35
commit 4a69b58479
2 changed files with 86 additions and 25 deletions

@ -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,