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::error::{FILE_NOT_EXISTS_ERROR, INVALID_BOM_FILE_ERROR};
|
||||||
use crate::util::{
|
use crate::util::{
|
||||||
check_file_hash, copy_dir, copy_file, copy_shared_object, create_link, dest_in_root,
|
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::{Deserialize, Serialize};
|
||||||
use serde_yaml;
|
use serde_yaml;
|
||||||
@ -136,12 +137,14 @@ impl Bom {
|
|||||||
fn get_bom_management(self, root_dir: &str) -> BomManagement {
|
fn get_bom_management(self, root_dir: &str) -> BomManagement {
|
||||||
let mut bom_management = BomManagement::default();
|
let mut bom_management = BomManagement::default();
|
||||||
bom_management.dirs_to_make.push(root_dir.to_string()); // init root dir
|
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 {
|
if let Some(ref targets) = self.targets {
|
||||||
for target in targets {
|
for target in targets {
|
||||||
let target_management = target.get_target_management(root_dir);
|
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
|
bom_management
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,26 +356,37 @@ impl NormalFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BomManagement {
|
impl BomManagement {
|
||||||
fn add_target_management(&mut self, mut target_management: TargetManagement, root_dir: &str) {
|
fn add_target_managements(
|
||||||
// First, we need to resolve environmental variables
|
&mut self,
|
||||||
target_management.resolve_environmental_variables();
|
target_managements: Vec<TargetManagement>,
|
||||||
let TargetManagement {
|
root_dir: &str,
|
||||||
dirs_to_make,
|
) {
|
||||||
links_to_create,
|
let mut files_autodep_in_bom = Vec::new();
|
||||||
dirs_to_copy,
|
for mut target_management in target_managements.into_iter() {
|
||||||
files_to_copy,
|
// First, we need to resolve environmental variables
|
||||||
files_autodep,
|
target_management.resolve_environmental_variables();
|
||||||
} = target_management;
|
let TargetManagement {
|
||||||
self.dirs_to_make.extend(dirs_to_make.into_iter());
|
dirs_to_make,
|
||||||
self.links_to_create.extend(links_to_create.into_iter());
|
links_to_create,
|
||||||
self.dirs_to_copy.extend(dirs_to_copy.into_iter());
|
dirs_to_copy,
|
||||||
self.files_to_copy.extend(files_to_copy.into_iter());
|
files_to_copy,
|
||||||
self.autodep(files_autodep, root_dir);
|
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) {
|
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() {
|
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() {
|
for (src, dest) in shared_objects.drain() {
|
||||||
let dest_path = dest_in_root(root_dir, &dest);
|
let dest_path = dest_in_root(root_dir, &dest);
|
||||||
// First, we create dir to store the dependency
|
// 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.
|
/// 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
|
/// 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.
|
/// 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();
|
let mut shared_objects = HashSet::new();
|
||||||
// find dependencies for the input file
|
// 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
|
// 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() {
|
if dynamic_loader.is_none() {
|
||||||
return shared_objects;
|
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
|
/// 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)).
|
/// If will first try to read the interp section of elf file. If the file does not have interp section,
|
||||||
/// This is because the loader_src and loader_dest may not be the same directory.
|
/// and the default loader is *NOT* None, it will return default loader.
|
||||||
/// If we can't find the loader, this function will return None
|
/// It there is no interp section and default loader is None, it will return None.
|
||||||
fn auto_dynamic_loader(filename: &str) -> Option<(String, String)> {
|
/// 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) {
|
let elf_file = match elf::File::open_path(filename) {
|
||||||
Err(_) => return None,
|
Err(_) => return None,
|
||||||
Ok(elf_file) => elf_file,
|
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
|
/// resolve the results of dynamic loader to extract dependencies
|
||||||
pub fn extract_dependencies_from_output(
|
pub fn extract_dependencies_from_output(
|
||||||
file_path: &str,
|
file_path: &str,
|
||||||
|
Loading…
Reference in New Issue
Block a user