由于基于惰性计算的域敏感指针分析系统的兼容性不高,请务必确保正确安装LLVM-14、Clang-14、CMake和Ninja。
python3 setup.py build
python3 runtests.py
(1) 官方文档使用的是Visual Studio进行编译,如果未安装Visual Studio而直接运行python setup.py build会报错;解决方法是改用CMake作为项目管理器,Ninja作为代码生成器,改用clang作为编译器,那么就需要对llvmlite/ffi/build.py进行如下修改:
第76行:注释掉原先的编译器
('Ninja', None, None)
第104行:clang编译的文件名和目录结构与msvc不一样
shutil.copy(os.path.join(build_dir, 'libllvmlite.dll'), os.path.join(target_dir, 'llvmlite.dll'))
第110行:在Linux平台改为默认使用Ninja作为代码生成器
generator = 'Ninja'
第120行:在Linux平台改为默认使用CMake作为项目管理器
if os.environ.get("LLVMLITE_USE_CMAKE", "1") == "1":
(2) 如需更换LLVM-Lite项目的说明文档以及其编码,对setup.py进行如下修改:
第184行:更换说明文档的文件名和编码
with open('README.md', encoding='UTF-8') as f:
(3) 在Windows平台编译的dll文件有可能无法加载进内存,主要原因是dll文件的依赖不在系统目录,于是python的dll加载器找不到依赖文件而报错;解决方法是把依赖文件(例如libc++.dll和libunwind.dll等)拷贝到llvmlite\binding目录下即可。
(4) 二次开发需要在FFI/Value.cpp中额外引入头文件llvm/IR/DebugInfoMetadata.h。
(5) LLVM-14的预编译工程可能存在漏洞,因此需要参考llvmlite官网打补丁,而手动下载的llvm-project文件目录和patch文件里的目录不一致,因此补丁命令需要改为patch -p2 -i {patch-file}。
首先,需要在FFI/Value.cpp中开放LLVMGetDebugLocLine相关API;
API_EXPORT(unsigned)
LLVMPY_GetDebugLocLine(LLVMValueRef Val) { return LLVMGetDebugLocLine(Val); }接着,需要在llvmlite/binding/value.py中调用相关API;
def get_location(self):
# 形式参数的情况
if self.is_argument:
return ffi.lib.LLVMPY_GetDebugLocLine(self.function)
# 基本块的情况
if self.is_block:
return ffi.lib.LLVMPY_GetDebugLocLine(self.function)
# 操作数的情况
if self.is_operand:
return ffi.lib.LLVMPY_GetDebugLocLine(self.instruction)
# 全局变量、函数和指令的情况
return ffi.lib.LLVMPY_GetDebugLocLine(self)最后,在llvmlite/binding/Value.py文件的最后,添加API调用的类型声明:
ffi.lib.LLVMPY_GetDebugLocLine.argtypes = [ffi.LLVMValueRef]
ffi.lib.LLVMPY_GetDebugLocLine.restype = c_uint首先,需要在FFI/Value.cpp中开放LLVMGetDebugLocFilename相关API:
API_EXPORT(const char *)
LLVMPY_GetDebugLocFilename(LLVMValueRef Val)
{
unsigned int Length = 0;
if (const char *str = LLVMGetDebugLocFilename(Val, &Length)) {
return LLVMPY_CreateString(str);
}
return LLVMPY_CreateString("");
}接着,需要在llvmlite/binding/value.py中调用相关API:
def get_filename(self):
# 形式参数的情况
if self.is_argument:
return ffi.ret_string(ffi.lib.LLVMPY_GetDebugLocFilename(self.function))
# 基本块的情况
if self.is_block:
return ffi.ret_string(ffi.lib.LLVMPY_GetDebugLocFilename(self.function))
# 操作数的情况
if self.is_operand:
return ffi.ret_string(ffi.lib.LLVMPY_GetDebugLocFilename(self.instruction))
# 全局变量、函数和指令的情况
return ffi.ret_string(ffi.lib.LLVMPY_GetDebugLocFilename(self))最后,在llvmlite/binding/Value.py文件的最后,添加API调用的类型声明:
ffi.lib.LLVMPY_GetDebugLocFilename.argtypes = [ffi.LLVMValueRef]
ffi.lib.LLVMPY_GetDebugLocFilename.restype = c_void_p首先,需要在FFI/Value.cpp中创建相关API:
API_EXPORT(LLVMValueRef)
LLVMPY_GetConstInstruction(LLVMValueRef Val, LLVMValueRef Ins)
{
llvm::ConstantExpr *CE = llvm::unwrap<llvm::ConstantExpr>(Val);
llvm::Instruction *IB = llvm::unwrap<llvm::Instruction>(Ins);
return llvm::wrap(CE->getAsInstruction(IB));
}接着,需要在llvmlite/binding/Value.py中调用相关API:
def get_constant_instruction(self):
if self.value_kind != ValueKind.constant_expr:
raise ValueError('expected constant expression, got %s'
% (self._kind,))
it = ffi.lib.LLVMPY_GetConstInstruction(self, self.instruction)
parents = self.instruction._parents.copy()
return ValueRef(it, 'instruction', parents)最后,在llvmlite/binding/Value.py文件的最后,添加API调用的类型声明:
ffi.lib.LLVMPY_GetConstInstruction.argtypes = [ffi.LLVMValueRef, ffi.LLVMValueRef]
ffi.lib.LLVMPY_GetConstInstruction.restype = ffi.LLVMValueRef首先,需要在FFI/Value.cpp中创建相关API:
API_EXPORT(const char *)
LLVMPY_GetVariableName(LLVMValueRef Val)
{
LLVMMetadataRef md = LLVMValueAsMetadata(Val);
if (const llvm::DILocalVariable *DLV = llvm::unwrap<llvm::DILocalVariable>(md)) {
return LLVMPY_CreateString(DLV->getName().str().c_str());
}
return LLVMPY_CreateString("");
}然后,需要在llvmlite/binding/Value.py中调用相关API:
def get_variable_name(self):
if self.value_kind != ValueKind.metadata_as_value:
raise ValueError('expected DIVariable metadata, got %s'
% (self._kind,))
return ffi.ret_string(ffi.lib.LLVMPY_GetVariableName(self))最后,在llvmlite/binding/Value.py文件的最后,添加API调用的类型声明:
ffi.lib.LLVMPY_GetVariableName.argtypes = [ffi.LLVMValueRef]
ffi.lib.LLVMPY_GetVariableName.restype = c_void_p首先,需要在FFI/Value.cpp中创建相关API:
API_EXPORT(LLVMValueRef)
LLVMPY_GetValueFromMetadata(LLVMValueRef Val)
{
LLVMMetadataRef md = LLVMValueAsMetadata(Val);
if (const llvm::ValueAsMetadata *VAM = llvm::unwrap<llvm::ValueAsMetadata>(md)) {
return llvm::wrap(VAM->getValue());
}
return nullptr;
}然后,需要在llvmlite/binding/Value.py中调用相关API:
def get_value_from_metadata(self):
if self.value_kind != ValueKind.metadata_as_value:
raise ValueError('expected value as metadata, got %s'
% (self._kind,))
it = ffi.lib.LLVMPY_GetValueFromMetadata(self)
parents = self._parents.copy()
return ValueRef(it, 'instruction', parents)最后,在llvmlite/binding/Value.py文件的最后,添加API调用的类型声明:
ffi.lib.LLVMPY_GetValueFromMetadata.argtypes = [ffi.LLVMValueRef]
ffi.lib.LLVMPY_GetValueFromMetadata.restype = ffi.LLVMValueRef