use crate::constant::ConstantRef;
#[cfg(LLVM_VERSION_9_OR_GREATER)]
use crate::debugloc::*;
use crate::function::{Function, FunctionAttribute, GroupID};
use crate::llvm_sys::*;
use crate::name::Name;
use crate::types::{Type, TypeRef, Typed, Types, TypesBuilder};
use std::path::Path;
#[derive(Clone)]
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 inline_assembly: String,
pub types: Types,
}
impl Module {
pub fn type_of<T: Typed + ?Sized>(&self, t: &T) -> TypeRef {
self.types.type_of(t)
}
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: TypeRef,
pub addr_space: AddrSpace,
pub dll_storage_class: DLLStorageClass,
pub thread_local_mode: ThreadLocalMode,
pub unnamed_addr: Option<UnnamedAddr>,
pub initializer: Option<ConstantRef>,
pub section: Option<String>,
pub comdat: Option<Comdat>,
pub alignment: u32,
#[cfg(LLVM_VERSION_9_OR_GREATER)]
pub debugloc: Option<DebugLoc>,
}
impl Typed for GlobalVariable {
fn get_type(&self, _types: &Types) -> TypeRef {
self.ty.clone()
}
}
#[cfg(LLVM_VERSION_9_OR_GREATER)]
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: ConstantRef,
pub linkage: Linkage,
pub visibility: Visibility,
pub ty: TypeRef,
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, _types: &Types) -> TypeRef {
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::Constant;
use crate::from_llvm::*;
use crate::function::AttributesData;
use llvm_sys::comdat::*;
use llvm_sys::{
LLVMDLLStorageClass,
LLVMLinkage,
LLVMThreadLocalMode,
LLVMUnnamedAddr,
LLVMVisibility,
};
use std::collections::HashMap;
pub(crate) struct ModuleContext<'a> {
pub types: TypesBuilder,
pub attrsdata: AttributesData,
#[allow(clippy::mutable_key_type)]
pub constants: HashMap<LLVMValueRef, ConstantRef>,
#[allow(clippy::mutable_key_type)]
pub global_names: &'a HashMap<LLVMValueRef, Name>,
}
impl<'a> ModuleContext<'a> {
#[allow(clippy::mutable_key_type)]
fn new(global_names: &'a HashMap<LLVMValueRef, Name>) -> Self {
Self {
types: TypesBuilder::new(),
attrsdata: AttributesData::create(),
constants: HashMap::new(),
global_names,
}
}
}
impl Module {
pub(crate) fn from_llvm_ref(module: LLVMModuleRef) -> Self {
debug!("Creating a Module from an LLVMModuleRef");
let mut global_ctr = 0;
#[allow(clippy::mutable_key_type)]
let global_names: HashMap<LLVMValueRef, Name> = 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 ctx = ModuleContext::new(&global_names);
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, &mut ctx))
.collect(),
global_vars: get_globals(module)
.map(|g| GlobalVariable::from_llvm_ref(g, &mut global_ctr, &mut ctx))
.collect(),
global_aliases: get_global_aliases(module)
.map(|g| GlobalAlias::from_llvm_ref(g, &mut global_ctr, &mut ctx))
.collect(),
inline_assembly: unsafe { get_module_inline_asm(module) },
types: ctx.types.build(),
}
}
}
impl GlobalVariable {
pub(crate) fn from_llvm_ref(
global: LLVMValueRef,
ctr: &mut usize,
ctx: &mut ModuleContext,
) -> Self {
let ty = ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(global) });
let addr_space = match ty.as_ref() {
Type::PointerType { addr_space, .. } => *addr_space,
_ => panic!("GlobalVariable has a non-pointer type, {:?}", ty),
};
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,
addr_space,
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, ctx))
}
},
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) },
#[cfg(LLVM_VERSION_9_OR_GREATER)]
debugloc: DebugLoc::from_llvm_no_col(global),
}
}
}
impl GlobalAlias {
pub(crate) fn from_llvm_ref(
alias: LLVMValueRef,
ctr: &mut usize,
ctx: &mut ModuleContext,
) -> Self {
let ty = ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(alias) });
let addr_space = match ty.as_ref() {
Type::PointerType { addr_space, .. } => *addr_space,
_ => panic!("GlobalAlias has a non-pointer type, {:?}", ty),
};
Self {
name: Name::name_or_num(unsafe { get_value_name(alias) }, ctr),
aliasee: Constant::from_llvm_ref(unsafe { LLVMAliasGetAliasee(alias) }, ctx),
linkage: Linkage::from_llvm(unsafe { LLVMGetLinkage(alias) }),
visibility: Visibility::from_llvm(unsafe { LLVMGetVisibility(alias) }),
ty,
addr_space,
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> {
use LLVMUnnamedAddr::*;
match ua {
LLVMNoUnnamedAddr => None,
LLVMLocalUnnamedAddr => Some(UnnamedAddr::Local),
LLVMGlobalUnnamedAddr => Some(UnnamedAddr::Global),
}
}
}
impl Linkage {
pub(crate) fn from_llvm(linkage: LLVMLinkage) -> Self {
use LLVMLinkage::*;
match linkage {
LLVMExternalLinkage => Linkage::External,
LLVMAvailableExternallyLinkage => Linkage::AvailableExternally,
LLVMLinkOnceAnyLinkage => Linkage::LinkOnceAny,
LLVMLinkOnceODRLinkage => Linkage::LinkOnceODR,
LLVMLinkOnceODRAutoHideLinkage => Linkage::LinkOnceODRAutoHide,
LLVMWeakAnyLinkage => Linkage::WeakAny,
LLVMWeakODRLinkage => Linkage::WeakODR,
LLVMAppendingLinkage => Linkage::Appending,
LLVMInternalLinkage => Linkage::Internal,
LLVMPrivateLinkage => Linkage::Private,
LLVMDLLImportLinkage => Linkage::DLLImport,
LLVMDLLExportLinkage => Linkage::DLLExport,
LLVMExternalWeakLinkage => Linkage::ExternalWeak,
LLVMGhostLinkage => Linkage::Ghost,
LLVMCommonLinkage => Linkage::Common,
LLVMLinkerPrivateLinkage => Linkage::LinkerPrivate,
LLVMLinkerPrivateWeakLinkage => Linkage::LinkerPrivateWeak,
}
}
}
impl Visibility {
pub(crate) fn from_llvm(visibility: LLVMVisibility) -> Self {
use LLVMVisibility::*;
match visibility {
LLVMDefaultVisibility => Visibility::Default,
LLVMHiddenVisibility => Visibility::Hidden,
LLVMProtectedVisibility => Visibility::Protected,
}
}
}
impl DLLStorageClass {
pub(crate) fn from_llvm(dllsc: LLVMDLLStorageClass) -> Self {
use LLVMDLLStorageClass::*;
match dllsc {
LLVMDefaultStorageClass => DLLStorageClass::Default,
LLVMDLLImportStorageClass => DLLStorageClass::Import,
LLVMDLLExportStorageClass => DLLStorageClass::Export,
}
}
}
impl ThreadLocalMode {
pub(crate) fn from_llvm(tlm: LLVMThreadLocalMode) -> Self {
use LLVMThreadLocalMode::*;
match tlm {
LLVMNotThreadLocal => ThreadLocalMode::NotThreadLocal,
LLVMGeneralDynamicTLSModel => ThreadLocalMode::GeneralDynamic,
LLVMLocalDynamicTLSModel => ThreadLocalMode::LocalDynamic,
LLVMInitialExecTLSModel => ThreadLocalMode::InitialExec,
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 {
use LLVMComdatSelectionKind::*;
match sk {
LLVMAnyComdatSelectionKind => SelectionKind::Any,
LLVMExactMatchComdatSelectionKind => SelectionKind::ExactMatch,
LLVMLargestComdatSelectionKind => SelectionKind::Largest,
LLVMNoDuplicatesComdatSelectionKind => SelectionKind::NoDuplicates,
LLVMSameSizeComdatSelectionKind => SelectionKind::SameSize,
}
}
}