use crate::module::Module;
use crate::types::{Type, TypeKind};
use crate::value::ValueRef;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ModuleFlagBehavior {
Error = 1,
Warning = 2,
Require = 3,
Override = 4,
Append = 5,
AppendUnique = 6,
Max = 7,
Min = 8,
}
impl ModuleFlagBehavior {
pub fn from_id(id: u32) -> Self {
match id {
1 => ModuleFlagBehavior::Error,
2 => ModuleFlagBehavior::Warning,
3 => ModuleFlagBehavior::Require,
4 => ModuleFlagBehavior::Override,
5 => ModuleFlagBehavior::Append,
6 => ModuleFlagBehavior::AppendUnique,
7 => ModuleFlagBehavior::Max,
8 => ModuleFlagBehavior::Min,
_ => ModuleFlagBehavior::Error,
}
}
}
#[derive(Debug, Clone)]
pub struct ModuleFlag {
pub behavior: ModuleFlagBehavior,
pub key: String,
pub value: ModuleFlagValue,
}
#[derive(Debug, Clone)]
pub enum ModuleFlagValue {
Int1(bool),
Int8(u8),
Int32(u32),
Int64(u64),
String(String),
MDNode(u64),
}
#[derive(Debug, Clone, Default)]
pub struct ModuleFlags {
pub flags: Vec<ModuleFlag>,
}
impl ModuleFlags {
pub fn add_flag(&mut self, behavior: ModuleFlagBehavior, key: &str, value: ModuleFlagValue) {
self.flags.push(ModuleFlag {
behavior,
key: key.to_string(),
value,
});
}
pub fn get_flag(&self, key: &str) -> Option<&ModuleFlag> {
self.flags.iter().find(|f| f.key == key)
}
pub fn add_standard_flags(&mut self) {
self.add_flag(
ModuleFlagBehavior::Error,
"wchar_size",
ModuleFlagValue::Int32(4),
);
self.add_flag(
ModuleFlagBehavior::Max,
"PIC Level",
ModuleFlagValue::Int32(2),
);
self.add_flag(
ModuleFlagBehavior::Max,
"PIE Level",
ModuleFlagValue::Int32(2),
);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ComdatSelectionKind {
Any,
ExactMatch,
Largest,
NoDeduplicate,
SameSize,
}
impl ComdatSelectionKind {
pub fn from_str(s: &str) -> Self {
match s {
"any" => ComdatSelectionKind::Any,
"exactmatch" | "exact" => ComdatSelectionKind::ExactMatch,
"largest" => ComdatSelectionKind::Largest,
"nodeduplicate" => ComdatSelectionKind::NoDeduplicate,
"samesize" => ComdatSelectionKind::SameSize,
_ => ComdatSelectionKind::Any,
}
}
pub fn to_str(&self) -> &'static str {
match self {
ComdatSelectionKind::Any => "any",
ComdatSelectionKind::ExactMatch => "exactmatch",
ComdatSelectionKind::Largest => "largest",
ComdatSelectionKind::NoDeduplicate => "nodeduplicate",
ComdatSelectionKind::SameSize => "samesize",
}
}
}
#[derive(Debug, Clone)]
pub struct ComdatGroup {
pub name: String,
pub selection_kind: ComdatSelectionKind,
pub members: Vec<String>,
}
impl ComdatGroup {
pub fn new(name: String, kind: ComdatSelectionKind) -> Self {
ComdatGroup {
name,
selection_kind: kind,
members: Vec::new(),
}
}
pub fn add_member(&mut self, name: String) {
self.members.push(name);
}
}
#[derive(Debug, Clone)]
pub struct ModuleInfo {
pub module_id: Option<String>,
pub source_filename: Option<String>,
pub target_triple: Option<String>,
pub data_layout: Option<String>,
pub inline_asm: String,
pub flags: ModuleFlags,
pub comdats: HashMap<String, ComdatGroup>,
pub named_metadata: HashMap<String, Vec<u64>>,
}
impl Default for ModuleInfo {
fn default() -> Self {
ModuleInfo {
module_id: None,
source_filename: None,
target_triple: None,
data_layout: None,
inline_asm: String::new(),
flags: ModuleFlags::default(),
comdats: HashMap::new(),
named_metadata: HashMap::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct GlobalAlias {
pub name: String,
pub aliasee: String,
pub linkage: GlobalLinkageKind,
pub visibility: VisibilityKind,
pub dll_storage: DLLStorageKind,
pub thread_local: bool,
pub unnamed_addr: bool,
}
#[derive(Debug, Clone)]
pub struct IFunc {
pub name: String,
pub resolver: String,
pub linkage: GlobalLinkageKind,
pub visibility: VisibilityKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GlobalLinkageKind {
External,
Internal,
Private,
WeakAny,
WeakODR,
LinkOnceAny,
LinkOnceODR,
AvailableExternally,
Appending,
Common,
ExternalWeak,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VisibilityKind {
Default,
Hidden,
Protected,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DLLStorageKind {
Default,
DLLImport,
DLLExport,
}
#[derive(Debug, Clone)]
pub struct ModuleSummaryIndex {
pub module_path: String,
pub module_hash: u64,
pub global_value_summaries: Vec<GlobalValueSummary>,
pub type_id_summaries: Vec<TypeIdSummary>,
}
#[derive(Debug, Clone)]
pub struct GlobalValueSummary {
pub name: String,
pub guid: u64,
pub linkage: GlobalLinkageKind,
pub num_insts: u32,
pub callee_info_list: Vec<CalleeInfo>,
pub refs: Vec<u64>,
pub is_live: bool,
}
#[derive(Debug, Clone)]
pub struct CalleeInfo {
pub callee_guid: u64,
pub hotness: u32,
}
#[derive(Debug, Clone)]
pub struct TypeIdSummary {
pub id: String,
pub resolved: u64,
}
impl ModuleSummaryIndex {
pub fn empty() -> Self {
ModuleSummaryIndex {
module_path: String::new(),
module_hash: 0,
global_value_summaries: Vec::new(),
type_id_summaries: Vec::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct ModuleSymbolTable {
pub symbols: HashMap<String, SymbolInfo>,
}
#[derive(Debug, Clone)]
pub struct SymbolInfo {
pub name: String,
pub is_function: bool,
pub is_global: bool,
pub is_defined: bool,
pub linkage: GlobalLinkageKind,
pub visibility: VisibilityKind,
pub section: Option<String>,
}
impl ModuleSymbolTable {
pub fn new() -> Self {
ModuleSymbolTable {
symbols: HashMap::new(),
}
}
pub fn lookup(&self, name: &str) -> Option<&SymbolInfo> {
self.symbols.get(name)
}
}
impl Default for ModuleSymbolTable {
fn default() -> Self {
ModuleSymbolTable::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_module_flags() {
let mut flags = ModuleFlags::default();
flags.add_standard_flags();
assert!(flags.get_flag("wchar_size").is_some());
}
#[test]
fn test_comdat() {
let mut cg = ComdatGroup::new("mycomdat".to_string(), ComdatSelectionKind::Any);
cg.add_member("myfunc".to_string());
assert_eq!(cg.name, "mycomdat");
}
#[test]
fn test_comdat_selection_kind() {
assert_eq!(
ComdatSelectionKind::from_str("any"),
ComdatSelectionKind::Any
);
assert_eq!(ComdatSelectionKind::ExactMatch.to_str(), "exactmatch");
}
#[test]
fn test_module_info_default() {
let info = ModuleInfo::default();
assert!(info.source_filename.is_none());
assert!(info.target_triple.is_none());
}
#[test]
fn test_module_symbol_table() {
let mut table = ModuleSymbolTable::new();
table.symbols.insert(
"main".to_string(),
SymbolInfo {
name: "main".to_string(),
is_function: true,
is_global: true,
is_defined: true,
linkage: GlobalLinkageKind::External,
visibility: VisibilityKind::Default,
section: None,
},
);
assert!(table.lookup("main").is_some());
}
}