use crate::constant::Constant;
use crate::debugloc::*;
use crate::function::{Function, FunctionAttribute, GroupID};
use crate::name::Name;
use crate::types::{Type, Typed};
use std::collections::HashMap;
use std::path::Path;
use std::sync::{Arc, RwLock};
#[derive(Clone, Debug)]
pub struct Module {
pub name: String,
pub source_file_name: String,
pub data_layout: String,
pub target_triple: Option<String>,
pub functions: Vec<Function>,
pub global_vars: Vec<GlobalVariable>,
pub global_aliases: Vec<GlobalAlias>,
pub named_struct_types: HashMap<String, Option<Arc<RwLock<Type>>>>,
pub inline_assembly: String,
}
impl Module {
pub fn get_func_by_name(&self, name: &str) -> Option<&Function> {
self.functions.iter().find(|func| func.name == name)
}
pub fn from_bc_path(path: impl AsRef<Path>) -> Result<Self, String> {
use std::ffi::{CStr, CString};
use std::mem;
let path = CString::new(
path.as_ref()
.to_str()
.expect("Did not find a valid Unicode path string"),
)
.expect("Failed to convert to CString");
debug!("Creating a Module from path {:?}", path);
let memory_buffer = unsafe {
let mut memory_buffer = std::ptr::null_mut();
let mut err_string = std::mem::zeroed();
let return_code = LLVMCreateMemoryBufferWithContentsOfFile(
path.as_ptr() as *const _,
&mut memory_buffer,
&mut err_string,
);
if return_code != 0 {
return Err(CStr::from_ptr(err_string)
.to_str()
.expect("Failed to convert CStr")
.to_owned());
}
memory_buffer
};
debug!("Created a MemoryBuffer");
let context = crate::from_llvm::Context::new();
use llvm_sys::bit_reader::LLVMParseBitcodeInContext2;
let module = unsafe {
let mut module: mem::MaybeUninit<LLVMModuleRef> = mem::MaybeUninit::uninit();
let return_code =
LLVMParseBitcodeInContext2(context.ctx, memory_buffer, module.as_mut_ptr());
LLVMDisposeMemoryBuffer(memory_buffer);
if return_code != 0 {
return Err("Failed to parse bitcode".to_string());
}
module.assume_init()
};
debug!("Parsed bitcode to llvm_sys module");
Ok(Self::from_llvm_ref(module))
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct GlobalVariable {
pub name: Name,
pub linkage: Linkage,
pub visibility: Visibility,
pub is_constant: bool,
pub ty: Type,
pub addr_space: AddrSpace,
pub dll_storage_class: DLLStorageClass,
pub thread_local_mode: ThreadLocalMode,
pub unnamed_addr: Option<UnnamedAddr>,
pub initializer: Option<Constant>,
pub section: Option<String>,
pub comdat: Option<Comdat>,
pub alignment: u32,
pub debugloc: Option<DebugLoc>,
}
impl Typed for GlobalVariable {
fn get_type(&self) -> Type {
self.ty.clone()
}
}
impl HasDebugLoc for GlobalVariable {
fn get_debug_loc(&self) -> &Option<DebugLoc> {
&self.debugloc
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct GlobalAlias {
pub name: Name,
pub aliasee: Constant,
pub linkage: Linkage,
pub visibility: Visibility,
pub ty: Type,
pub addr_space: AddrSpace,
pub dll_storage_class: DLLStorageClass,
pub thread_local_mode: ThreadLocalMode,
pub unnamed_addr: Option<UnnamedAddr>,
}
impl Typed for GlobalAlias {
fn get_type(&self) -> Type {
self.ty.clone()
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum UnnamedAddr {
Local,
Global,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum Linkage {
Private,
Internal,
External,
ExternalWeak,
AvailableExternally,
LinkOnceAny,
LinkOnceODR,
LinkOnceODRAutoHide,
WeakAny,
WeakODR,
Common,
Appending,
DLLImport,
DLLExport,
Ghost,
LinkerPrivate,
LinkerPrivateWeak,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum Visibility {
Default,
Hidden,
Protected,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum DLLStorageClass {
Default,
Import,
Export,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum ThreadLocalMode {
NotThreadLocal,
GeneralDynamic,
LocalDynamic,
InitialExec,
LocalExec,
}
pub type AddrSpace = u32;
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct FunctionAttributeGroup {
pub group_id: GroupID,
pub attrs: Vec<FunctionAttribute>,
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Comdat {
pub name: String,
pub selection_kind: SelectionKind,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum SelectionKind {
Any,
ExactMatch,
Largest,
NoDuplicates,
SameSize,
}
use crate::constant::GlobalNameMap;
use crate::from_llvm::*;
use crate::types::TyNameMap;
use llvm_sys::{LLVMDLLStorageClass, LLVMLinkage, LLVMThreadLocalMode, LLVMUnnamedAddr, LLVMVisibility};
use llvm_sys::comdat::*;
impl Module {
pub(crate) fn from_llvm_ref(module: LLVMModuleRef) -> Self {
debug!("Creating a Module from an LLVMModuleRef");
let mut global_ctr = 0;
let gnmap: GlobalNameMap = get_defined_functions(module)
.chain(get_declared_functions(module))
.chain(get_globals(module))
.chain(get_global_aliases(module))
.map(|g| {
(
g,
Name::name_or_num(unsafe { get_value_name(g) }, &mut global_ctr),
)
})
.collect();
global_ctr = 0;
let mut tynamemap = TyNameMap::new();
Self {
name: unsafe { get_module_identifier(module) },
source_file_name: unsafe { get_source_file_name(module) },
data_layout: unsafe { get_data_layout_str(module) },
target_triple: unsafe { get_target(module) },
functions: get_defined_functions(module)
.map(|f| Function::from_llvm_ref(f, &gnmap, &mut tynamemap))
.collect(),
global_vars: get_globals(module)
.map(|g| GlobalVariable::from_llvm_ref(g, &mut global_ctr, &gnmap, &mut tynamemap))
.collect(),
global_aliases: get_global_aliases(module)
.map(|g| GlobalAlias::from_llvm_ref(g, &mut global_ctr, &gnmap, &mut tynamemap))
.collect(),
named_struct_types: tynamemap,
inline_assembly: unsafe { get_module_inline_asm(module) },
}
}
}
impl GlobalVariable {
pub(crate) fn from_llvm_ref(
global: LLVMValueRef,
ctr: &mut usize,
gnmap: &GlobalNameMap,
tnmap: &mut TyNameMap,
) -> Self {
let ty = Type::from_llvm_ref(unsafe { LLVMTypeOf(global) }, tnmap);
debug!("Processing a GlobalVariable with type {:?}", ty);
Self {
name: Name::name_or_num(unsafe { get_value_name(global) }, ctr),
linkage: Linkage::from_llvm(unsafe { LLVMGetLinkage(global) }),
visibility: Visibility::from_llvm(unsafe { LLVMGetVisibility(global) }),
is_constant: unsafe { LLVMIsGlobalConstant(global) } != 0,
ty: ty.clone(),
addr_space: match ty {
Type::PointerType { addr_space, .. } => addr_space,
_ => panic!("GlobalVariable has a non-pointer type, {:?}", ty),
},
dll_storage_class: DLLStorageClass::from_llvm(unsafe { LLVMGetDLLStorageClass(global) }),
thread_local_mode: ThreadLocalMode::from_llvm(unsafe { LLVMGetThreadLocalMode(global) }),
unnamed_addr: UnnamedAddr::from_llvm(unsafe { LLVMGetUnnamedAddress(global) }),
initializer: {
let it = unsafe { LLVMGetInitializer(global) };
if it.is_null() {
None
} else {
Some(Constant::from_llvm_ref(it, gnmap, tnmap))
}
},
section: unsafe { get_section(global) },
comdat: {
let comdat = unsafe { LLVMGetComdat(global) };
if comdat.is_null() {
None
} else {
Some(Comdat::from_llvm_ref(unsafe { LLVMGetComdat(global) }))
}
},
alignment: unsafe { LLVMGetAlignment(global) },
debugloc: DebugLoc::from_llvm_no_col(global),
}
}
}
impl GlobalAlias {
pub(crate) fn from_llvm_ref(
alias: LLVMValueRef,
ctr: &mut usize,
gnmap: &GlobalNameMap,
tnmap: &mut TyNameMap,
) -> Self {
let ty = Type::from_llvm_ref(unsafe { LLVMTypeOf(alias) }, tnmap);
Self {
name: Name::name_or_num(unsafe { get_value_name(alias) }, ctr),
aliasee: Constant::from_llvm_ref(unsafe { LLVMAliasGetAliasee(alias) }, gnmap, tnmap),
linkage: Linkage::from_llvm(unsafe { LLVMGetLinkage(alias) }),
visibility: Visibility::from_llvm(unsafe { LLVMGetVisibility(alias) }),
ty: ty.clone(),
addr_space: match ty {
Type::PointerType { addr_space, .. } => addr_space,
_ => panic!("GlobalAlias has a non-pointer type, {:?}", ty),
},
dll_storage_class: DLLStorageClass::from_llvm(unsafe { LLVMGetDLLStorageClass(alias) }),
thread_local_mode: ThreadLocalMode::from_llvm(unsafe { LLVMGetThreadLocalMode(alias) }),
unnamed_addr: UnnamedAddr::from_llvm(unsafe { LLVMGetUnnamedAddress(alias) }),
}
}
}
impl UnnamedAddr {
pub(crate) fn from_llvm(ua: LLVMUnnamedAddr) -> Option<Self> {
match ua {
LLVMUnnamedAddr::LLVMNoUnnamedAddr => None,
LLVMUnnamedAddr::LLVMLocalUnnamedAddr => Some(UnnamedAddr::Local),
LLVMUnnamedAddr::LLVMGlobalUnnamedAddr => Some(UnnamedAddr::Global),
}
}
}
impl Linkage {
pub(crate) fn from_llvm(linkage: LLVMLinkage) -> Self {
match linkage {
LLVMLinkage::LLVMExternalLinkage => Linkage::External,
LLVMLinkage::LLVMAvailableExternallyLinkage => Linkage::AvailableExternally,
LLVMLinkage::LLVMLinkOnceAnyLinkage => Linkage::LinkOnceAny,
LLVMLinkage::LLVMLinkOnceODRLinkage => Linkage::LinkOnceODR,
LLVMLinkage::LLVMLinkOnceODRAutoHideLinkage => Linkage::LinkOnceODRAutoHide,
LLVMLinkage::LLVMWeakAnyLinkage => Linkage::WeakAny,
LLVMLinkage::LLVMWeakODRLinkage => Linkage::WeakODR,
LLVMLinkage::LLVMAppendingLinkage => Linkage::Appending,
LLVMLinkage::LLVMInternalLinkage => Linkage::Internal,
LLVMLinkage::LLVMPrivateLinkage => Linkage::Private,
LLVMLinkage::LLVMDLLImportLinkage => Linkage::DLLImport,
LLVMLinkage::LLVMDLLExportLinkage => Linkage::DLLExport,
LLVMLinkage::LLVMExternalWeakLinkage => Linkage::ExternalWeak,
LLVMLinkage::LLVMGhostLinkage => Linkage::Ghost,
LLVMLinkage::LLVMCommonLinkage => Linkage::Common,
LLVMLinkage::LLVMLinkerPrivateLinkage => Linkage::LinkerPrivate,
LLVMLinkage::LLVMLinkerPrivateWeakLinkage => Linkage::LinkerPrivateWeak,
}
}
}
impl Visibility {
pub(crate) fn from_llvm(visibility: LLVMVisibility) -> Self {
match visibility {
LLVMVisibility::LLVMDefaultVisibility => Visibility::Default,
LLVMVisibility::LLVMHiddenVisibility => Visibility::Hidden,
LLVMVisibility::LLVMProtectedVisibility => Visibility::Protected,
}
}
}
impl DLLStorageClass {
pub(crate) fn from_llvm(dllsc: LLVMDLLStorageClass) -> Self {
match dllsc {
LLVMDLLStorageClass::LLVMDefaultStorageClass => DLLStorageClass::Default,
LLVMDLLStorageClass::LLVMDLLImportStorageClass => DLLStorageClass::Import,
LLVMDLLStorageClass::LLVMDLLExportStorageClass => DLLStorageClass::Export,
}
}
}
impl ThreadLocalMode {
pub(crate) fn from_llvm(tlm: LLVMThreadLocalMode) -> Self {
match tlm {
LLVMThreadLocalMode::LLVMNotThreadLocal => ThreadLocalMode::NotThreadLocal,
LLVMThreadLocalMode::LLVMGeneralDynamicTLSModel => ThreadLocalMode::GeneralDynamic,
LLVMThreadLocalMode::LLVMLocalDynamicTLSModel => ThreadLocalMode::LocalDynamic,
LLVMThreadLocalMode::LLVMInitialExecTLSModel => ThreadLocalMode::InitialExec,
LLVMThreadLocalMode::LLVMLocalExecTLSModel => ThreadLocalMode::LocalExec,
}
}
}
impl Comdat {
pub(crate) fn from_llvm_ref(comdat: LLVMComdatRef) -> Self {
Self {
name: "error: not yet implemented: Comdat.name".to_owned(),
selection_kind: SelectionKind::from_llvm(unsafe { LLVMGetComdatSelectionKind(comdat) }),
}
}
}
impl SelectionKind {
pub(crate) fn from_llvm(sk: LLVMComdatSelectionKind) -> Self {
match sk {
LLVMComdatSelectionKind::LLVMAnyComdatSelectionKind => SelectionKind::Any,
LLVMComdatSelectionKind::LLVMExactMatchComdatSelectionKind => SelectionKind::ExactMatch,
LLVMComdatSelectionKind::LLVMLargestComdatSelectionKind => SelectionKind::Largest,
LLVMComdatSelectionKind::LLVMNoDuplicatesComdatSelectionKind => SelectionKind::NoDuplicates,
LLVMComdatSelectionKind::LLVMSameSizeComdatSelectionKind => SelectionKind::SameSize,
}
}
}