good entrypoint for async rust

This commit is contained in:
🪞👃🪞 2025-02-23 21:40:41 +02:00
parent 6660e28287
commit 0a1b74b2ae
6 changed files with 170 additions and 112 deletions

View file

@ -434,3 +434,88 @@ impl Default for AEffect {
}
Ok(())
}
/// Relink a VST.
//fn run (&mut self, path: impl AsRef<Path>) -> Usually<()> {
//let path = path.as_ref().to_str().expect("path must be unicode");
//let path = self.find(path)?.unwrap_or_else(||panic!("# not found: {path:?}"));
//let main = self.load(&path)?;
//Ok(())
//}
/// Load all dependencies recursively, starting from the given path.
//fn load_all (&mut self, path: &impl AsRef<Path>) -> Usually<Arc<Module>> {
//let name = to_dll_name(path);
//let path: Arc<PathBuf> = Arc::from(PathBuf::from(path.as_ref()));
//if self.modules.contains_key(&name) {
//let module = self.modules.get(&name).unwrap().clone();
//return Ok(module)
//}
//Log::load(self.verbose, &path);
//let module = Arc::new(Module::new(&path, self.verbose)?.load(self.verbose)?);
//self.modules.insert(module.name.clone(), module.clone());
//Ok(module)
//}
//fn resolve (&self, dll: &Module, addr: u32, link: &Arc<CallSite>) -> Usually<()> {
//let addr = (addr - dll.code_base) as usize;
//dll.show_call_site(addr, link.length, 1);
//link.show();
//Ok(())
//}
//fn resolve_recursively (&self, dll: &Module, addr: u32, link: &Arc<CallSite>) -> Usually<()> {
//self.resolve(dll, addr, link)?;
//let module = &link.target.name;
//let export = &link.method;
//if let Some((module, export)) = match self.modules
//.get(module)
//.map(|module|module.exports.get(export))
//{
//Some(Some(ThunkData::Function(rva))) => Some((module.clone(), export.clone())),
//Some(Some(ThunkData::ForwarderString(rva))) => dll.resolve_forward(&rva)?,
//Some(Some(thunk)) => panic!("# unsupported {thunk:?}"),
//Some(None) => panic!("# export not resolved: {export}"),
//None => panic!("# module not resolved: {module}"),
//} {
//let module = self.modules.get(&module).unwrap_or_else(||panic!("# no module {module}"));
//let method = module.exports.get(&export).unwrap_or_else(||panic!("# no method {export}"));
//println!("{module:?} {export} {method:?}");
//} else {
//panic!("# unresolved link at {:?} [{addr}]", &dll.name)
//}
//Ok(())
//}
/// Collect an imported dependency's descriptor thunks into a temporary [Vec].
///
/// Most of these are currently discarded, but may be needed in the future
/// to resolve some of the trickier linkings.
fn import_collect (pe: &VecPE, descriptor: &ImageImportDescriptor)
-> Usually<(Arc<str>, Vec<(usize, Arc<str>)>)>
{
let mut buffer = vec![];
let name = descriptor.get_name(pe)?.as_str()?.to_lowercase();
for (index, import) in descriptor.get_imports(pe)?.iter().enumerate() {
buffer.push((index, match import {
ImportData::Ordinal(x) => format!("___VESTAL_ORDINAL_{x}"),
ImportData::ImportByName(name) => format!("{name}"),
}.into()));
}
Ok((name.into(), buffer))
//let imp = descriptor.get_imports(pe)?;
//let iat = descriptor.get_first_thunk(pe)?;
//let ilt = descriptor.get_original_first_thunk(pe)?;
//let lut = descriptor.get_lookup_thunks(pe)?;
//for (index, (import, thunk, orig, lookup)) in izip!(
//imp,
//iat.iter().map(|thunk|format!("0x{:08x}", Self::thunk_unwrap(thunk, "IAT thunk"))),
//ilt.iter().map(|thunk|format!("0x{:08x}", Self::thunk_unwrap(thunk, "ILT (orig) thunk"))),
//lut.iter().map(|thunk|format!("0x{:08x}", Self::thunk_unwrap(thunk, "lookup thunk"))),
//).enumerate() {
//buffer.push((index, import));//, thunk, orig, lookup));
//}
}
//fn thunk_unwrap (thunk: &Thunk, name: impl AsRef<str>) -> u64 {
//match thunk {
//Thunk::Thunk32(t) => panic!("32 bit {}", name.as_ref()),
//Thunk::Thunk64(t) => t.0
//}
//}

View file

@ -1,4 +1,5 @@
use crate::*;
impl Module {
/// Collect all calls that point to imports.
pub fn load_call_sites (self: Arc<Self>) -> Usually<Arc<Self>> {
@ -14,28 +15,6 @@ impl Module {
}
Ok(self)
}
fn target (opcodes: &[u8], offset_rva: u32) -> Option<u32> {
let rip = offset_rva + opcodes.len() as u32;
match opcodes[0] {
0xff => match opcodes[1] {
0x15 | 0x25 => return Some(rip + u32::from_le_bytes([
opcodes[2], opcodes[3], opcodes[4], opcodes[5]
])),
_ => {}
},
0x48 => match opcodes[1] {
0xff => match opcodes[2] {
0x15 | 0x25 => return Some(rip + u32::from_le_bytes([
opcodes[3], opcodes[4], opcodes[5], opcodes[6]
])),
_ => {}
},
_ => {}
}
_ => {}
}
None
}
fn parse_link (&self, link: &Arc<CallSite>) -> Option<u32> {
None
@ -60,3 +39,54 @@ impl Module {
.map(|(x, y)|(x.into(), y.into())))
}
}
impl CallSite {
pub fn matches (instruction: &Instruction) -> bool {
instruction.op0_kind() == OpKind::Memory && (
instruction.flow_control() == FlowControl::IndirectBranch ||
instruction.flow_control() == FlowControl::IndirectCall
)
}
pub fn skip (opcodes: &[u8]) -> bool {
match opcodes[0] {
0x41 | 0x42 | 0x43 | 0x49 => match opcodes[1] {
0xff => return true,
_ => {}
},
0x48 => match opcodes[2] {
0x20 | 0x60 | 0x62 | 0xa0 | 0xa2 => return true,
_ => {}
},
0xff => match opcodes[1] {
0x10 | 0x12 | 0x13 |
0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x56 | 0x57 |
0x60 | 0x90 | 0x92 | 0x93 | 0x94 | 0x97 => return true,
_ => {}
},
_ => {}
}
false
}
pub fn target (opcodes: &[u8], offset_rva: u32) -> Option<u32> {
let rip = offset_rva + opcodes.len() as u32;
match opcodes[0] {
0xff => match opcodes[1] {
0x15 | 0x25 => return Some(rip + u32::from_le_bytes([
opcodes[2], opcodes[3], opcodes[4], opcodes[5]
])),
_ => {}
},
0x48 => match opcodes[1] {
0xff => match opcodes[2] {
0x15 | 0x25 => return Some(rip + u32::from_le_bytes([
opcodes[3], opcodes[4], opcodes[5], opcodes[6]
])),
_ => {}
},
_ => {}
}
_ => {}
}
None
}
}

View file

@ -2,9 +2,10 @@ use crate::*;
impl Module {
/// Collect all exported methods.
pub fn load_exports (self: Arc<Self>) -> Usually<Arc<Self>> {
let directory = ExportDirectory::parse(self.pe.as_ref())?;
let directory = ExportDirectory::parse(self.pe.as_ref())?;
let export_map = directory.get_export_map(self.pe.as_ref())?;
*self.exports.write().unwrap() = export_map.into_iter().map(|(k, v)|(k.into(), v)).collect();
let exports = export_map.into_iter().map(|(k, v)|(k.into(), v)).collect();
*self.exports.write().unwrap() = exports;
Ok(self)
}
}

View file

@ -4,12 +4,12 @@ impl Module {
pub fn load_imports (self: Arc<Self>, recurse: bool) -> Usually<Arc<Self>> {
let pe = self.pe.clone();
let directory = ImportDirectory::parse(pe.as_ref())?;
let mut new_modules = vec![];
for descriptor in directory.descriptors.iter() {
let (name, imports) = Self::parse_import(pe.as_ref(), descriptor)?;
Log::dep(self.verbose, &name, &imports);
let exists = self.namespace.read().unwrap().contains_key(&name);
println!("{exists} {name} {:?}", self.namespace.read().unwrap().keys().collect::<Vec<_>>());
if !exists {
Log::dep(false, &name, &imports);
let path = self.find(&name)?.expect("not found");
let module = Arc::new(Self {
namespace: self.namespace.clone(),
@ -17,7 +17,12 @@ impl Module {
..Self::from_path(&path, self.verbose)?
});
self.namespace.write().unwrap().insert(module.name.clone(), module.clone());
module.load(recurse);
new_modules.push(module);
}
}
if recurse {
for module in new_modules {
module.load(recurse)?;
}
}
if self.verbose {

View file

@ -119,10 +119,14 @@ impl Module {
}
/// Load the dependency tree, starting from this module.
fn load (self: Arc<Self>, recurse: bool) -> Usually<Arc<Self>> {
Ok(self
.load_imports(recurse)?
let module = self
.load_exports()?
.load_call_sites()?)
.load_imports(recurse)?
.load_call_sites()?;
if module.verbose {
println!("{:?}", &module);
}
Ok(module)
}
/// Search for DLL by name in search paths.
fn find (&self, name: &impl AsRef<str>) -> Usually<Option<PathBuf>> {
@ -130,13 +134,9 @@ impl Module {
for base in self.search_paths.read().unwrap().iter() {
let mut path = base.as_ref().clone();
path.push(name.to_lowercase());
if self.verbose {
println!("(find? {name} {path:?})");
}
Log::find(false, &name, &path);
if std::fs::exists(&path)? {
if self.verbose {
println!("(found {name} {path:?})");
}
Log::found(false, &name, &path);
return Ok(Some(canonicalize(&path)?))
}
}
@ -172,69 +172,3 @@ fn base_of_code (pe: &VecPE) -> Usually<u32> {
NTHeaders::NTHeaders64(h64) => h64.optional_header.base_of_code.0,
})
}
/// Collect an imported dependency's descriptor thunks into a temporary [Vec].
///
/// Most of these are currently discarded, but may be needed in the future
/// to resolve some of the trickier linkings.
fn import_collect (pe: &VecPE, descriptor: &ImageImportDescriptor)
-> Usually<(Arc<str>, Vec<(usize, Arc<str>)>)>
{
let mut buffer = vec![];
let name = descriptor.get_name(pe)?.as_str()?.to_lowercase();
for (index, import) in descriptor.get_imports(pe)?.iter().enumerate() {
buffer.push((index, match import {
ImportData::Ordinal(x) => format!("___VESTAL_ORDINAL_{x}"),
ImportData::ImportByName(name) => format!("{name}"),
}.into()));
}
Ok((name.into(), buffer))
//let imp = descriptor.get_imports(pe)?;
//let iat = descriptor.get_first_thunk(pe)?;
//let ilt = descriptor.get_original_first_thunk(pe)?;
//let lut = descriptor.get_lookup_thunks(pe)?;
//for (index, (import, thunk, orig, lookup)) in izip!(
//imp,
//iat.iter().map(|thunk|format!("0x{:08x}", Self::thunk_unwrap(thunk, "IAT thunk"))),
//ilt.iter().map(|thunk|format!("0x{:08x}", Self::thunk_unwrap(thunk, "ILT (orig) thunk"))),
//lut.iter().map(|thunk|format!("0x{:08x}", Self::thunk_unwrap(thunk, "lookup thunk"))),
//).enumerate() {
//buffer.push((index, import));//, thunk, orig, lookup));
//}
}
//fn thunk_unwrap (thunk: &Thunk, name: impl AsRef<str>) -> u64 {
//match thunk {
//Thunk::Thunk32(t) => panic!("32 bit {}", name.as_ref()),
//Thunk::Thunk64(t) => t.0
//}
//}
impl CallSite {
fn matches (instruction: &Instruction) -> bool {
instruction.op0_kind() == OpKind::Memory && (
instruction.flow_control() == FlowControl::IndirectBranch ||
instruction.flow_control() == FlowControl::IndirectCall
)
}
fn skip (opcodes: &[u8]) -> bool {
match opcodes[0] {
0x41 | 0x42 | 0x43 | 0x49 => match opcodes[1] {
0xff => return true,
_ => {}
},
0x48 => match opcodes[2] {
0x20 | 0x60 | 0x62 | 0xa0 | 0xa2 => return true,
_ => {}
},
0xff => match opcodes[1] {
0x10 | 0x12 | 0x13 |
0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x56 | 0x57 |
0x60 | 0x90 | 0x92 | 0x93 | 0x94 | 0x97 => return true,
_ => {}
},
_ => {}
}
false
}
}

View file

@ -21,7 +21,7 @@ impl Log {
}
pub fn load (show: bool, path: &impl AsRef<Path>) {
if show {
println!("(load {:?})", path.as_ref());
println!("{DIM}(load {:?}){RESET}", path.as_ref());
}
}
pub fn dep (show: bool, name: &impl AsRef<str>, exports: &[(usize, Arc<str>)]) {
@ -29,6 +29,16 @@ impl Log {
println!("(dep {:?} {})", name.as_ref(), exports.len());
}
}
pub fn find (show: bool, name: &impl AsRef<str>, path: &impl AsRef<Path>) {
if show {
println!("(find? {} {:?})", name.as_ref(), path.as_ref());
}
}
pub fn found (show: bool, name: &impl AsRef<str>, path: &impl AsRef<Path>) {
if show {
println!("(found {} {:?})", name.as_ref(), path.as_ref());
}
}
}
impl Show {
@ -52,17 +62,10 @@ impl Show {
impl std::fmt::Debug for Module {
fn fmt (&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
let deps = "";// format!("(deps lib {:>4} addr {:>4})",
//self.dependencies.len(),
//self.deps_by_address.len());
let links = "";// format!("(links src {:>4} tgt {:>4})",
//self.links_by_source.len(),
//self.links_by_target.len());
let exports = format!("(exp {:>5})",
self.exports.read().unwrap().len());
write!(f, "(dll {BOLD}{UNDERLINE}{:15}{RESET} [0x{:>08x}] (img 0x{:>08x} -> mem 0x{:>08x}) {deps} {links} {exports})",
write!(f, "(dll {BOLD}{UNDERLINE}{:15}{RESET} [0x{:>08x}] {} (img 0x{:>08x} -> mem 0x{:>08x}))",
&self.name,
self.code_size,
format!("({:>5})", self.exports.read().unwrap().len()),
self.code_start,
self.code_base)
}