use crate::{
container::Container,
demangle::modpath::{self, ModulePath},
};
use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum InitKind {
Init,
DatInit,
HcrInit,
}
impl fmt::Display for InitKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::Init => "Init",
Self::DatInit => "DatInit",
Self::HcrInit => "HcrInit",
})
}
}
#[derive(Debug, Clone)]
pub struct InitFunction {
pub kind: InitKind,
pub symbol_name: String,
pub address: u64,
pub module_path: ModulePath,
}
const INIT_SUFFIXES: &[(&str, InitKind)] = &[
("HcrInit000", InitKind::HcrInit),
("DatInit000", InitKind::DatInit),
("Init000", InitKind::Init),
];
pub fn scan(container: &Container<'_>) -> Vec<InitFunction> {
let mut result = Vec::new();
for sym in container.symbols() {
let name = sym.name.as_ref();
if name.contains(".cold.") || name.contains(".TM_") || name.contains(".part.") {
continue;
}
for &(suffix, kind) in INIT_SUFFIXES {
if let Some(module_part) = name.strip_suffix(suffix) {
if module_part.is_empty() || module_part.ends_with("NimMain") {
continue;
}
let module_path = modpath::decode(module_part);
result.push(InitFunction {
kind,
symbol_name: name.to_string(),
address: sym.vm_addr,
module_path,
});
break;
}
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn init_kind_eq() {
assert_eq!(InitKind::Init, InitKind::Init);
assert_ne!(InitKind::Init, InitKind::DatInit);
}
}