diff --git a/.build_number b/.build_number index 522e1e95a..ba3c9c82a 100644 --- a/.build_number +++ b/.build_number @@ -1 +1 @@ -1517 +1521 diff --git a/CMakeLists.txt b/CMakeLists.txt index 810d0c4ae..a8bbe4730 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,8 @@ option(GCOV "Enable code coverage" OFF) option(LLVM_INTERFACE "Use LLVM for lifting" OFF) option(MSVC_STATIC "Use statically-linked runtime library" OFF) option(Z3_INTERFACE "Use Z3 as SMT solver" ON) +option(BUILD_EXAMPLES "Build the examples" ON) +option(ENABLE_TEST "Build test program" ON) # Define cmake dependent options cmake_dependent_option(PYTHON_BINDINGS "Enable Python bindings" ON BUILD_SHARED_LIBS OFF) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 679fa81cf..0292d291b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,12 +1,16 @@ add_subdirectory(libtriton) -if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") - # Disable exemples for windows as linkage doesn't work. Exported function should - # be marked as exported on windows. - add_subdirectory(examples) -else() - enable_testing() - add_test(DummyTest echo "Windows is awesome") +if (BUILD_EXAMPLES) + if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") + # Disable exemples for windows as linkage doesn't work. Exported function should + # be marked as exported on windows. + add_subdirectory(examples) + else() + enable_testing() + add_test(DummyTest echo "Windows is awesome") + endif() endif() -add_subdirectory(testers) +if (ENABLE_TEST) + add_subdirectory(testers) +endif() diff --git a/src/examples/python/proving_equivalence.py b/src/examples/python/proving_equivalence.py new file mode 100755 index 000000000..f6e1f9660 --- /dev/null +++ b/src/examples/python/proving_equivalence.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +## -*- coding: utf-8 -*- +## +## $ python ./proving equivalence.py +## True +## True +## True +## True +## True +## True +## True +## True +## True +## True +## True +## True +## True +## True +## + +import sys +from triton import * + + +def prove(ctx, n): + ast = ctx.getAstContext() + if ctx.isSat(ast.lnot(n)) == True: + return False + return True + +if __name__ == '__main__': + ctx = TritonContext(ARCH.X86_64) + ast = ctx.getAstContext() + + ctx.setAstRepresentationMode(AST_REPRESENTATION.PYTHON) + + x = ast.variable(ctx.newSymbolicVariable(8, 'x')) + y = ast.variable(ctx.newSymbolicVariable(8, 'y')) + + # MBA coming from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/ + # To detect their equivalence you can synthesize them (see synthesizing_obfuscated_expressions.py) + # Then you can confirm the synthesized output with this example + print(prove(ctx, x ^ y == (~(~(x) & ~(y)) & ~(~(~(x)) & ~(~(y)))))) + print(prove(ctx, x + y == ((~(~(x)) & ~(~(y))) + (~(~(x)) | ~(~(y)))))) + print(prove(ctx, x + y == ((~(~(y)) | ~(~(x))) + ~(~(x)) - (~(~(x)) & ~(~(~(y))))))) + print(prove(ctx, x + y == ((~(~(x)) | ~(~(y))) + (~(~(~(x))) | ~(~(y))) - (~(~(~(x))))))) + print(prove(ctx, x + y == ((~(~(x)) | ~(~(y))) + ~(~(y)) - (~(~(~(x))) & ~(~(y)))))) + print(prove(ctx, x + y == (~(~(y)) + (~(~(x)) & ~(~(~(y)))) + (~(~(x)) & ~(~(y)))))) + print(prove(ctx, x - y == (~(~(x) + y)))) + print(prove(ctx, ~((x | y) - x) == (~(((~(~(x)) | y) - (~(~(x)))))))) + print(prove(ctx, x - y == (~((~(x) & ~(x)) + y) & ~((~(x) & ~(x)) + y)))) + print(prove(ctx, x & y == ((~(~(x)) | y) - (~(~(~(x))) & y) - (~(~(x)) & ~y)))) + print(prove(ctx, x & y == ((~(~(~(x))) | y) - (~(~(~(x))))))) + print(prove(ctx, x | y == ((~(~(x)) & ~(y)) + y))) + print(prove(ctx, x | y == (((~(~(x)) & ~(y)) & y) + ((~(~(x)) & ~(y)) | y)))) + print(prove(ctx, x + y == ((~(~(x)) & ~(~(y))) + (~(~(x)) | ~(~(y)))))) + + sys.exit(0) diff --git a/src/examples/python/synthesizing_obfuscated_expressions.py b/src/examples/python/synthesizing_obfuscated_expressions.py index dd86958b7..71d08d5bc 100755 --- a/src/examples/python/synthesizing_obfuscated_expressions.py +++ b/src/examples/python/synthesizing_obfuscated_expressions.py @@ -3,7 +3,7 @@ ## ## Example of synthesizing obfuscated expressions. ## -## $ time python3 ./synthesizing_obfuscated_expressions.py +## $ python3 ./synthesizing_obfuscated_expressions.py ## In: (((((SymVar_0 | SymVar_1) + SymVar_1) & 0xff) - ((~(SymVar_0) & 0xff) & SymVar_1)) & 0xff) ## Out: ((SymVar_0 + SymVar_1) & 0xff) ## @@ -31,7 +31,7 @@ ## In: ((((((~(((((((((((z & 0xff) << 0x8) & 0xffffffff) | ((z >> 0x8) & 0xff)) << 0x8) & 0xffffffff) | ((z ... ## Out: (((bswap(z, 32) ^ 0x23746fbe) + 0xfffffffd) & 0xffffffff) ## -## python3 ./synthesizing_obfuscated_expressions.py 0.12s user 0.01s system 99% cpu 0.125 total +## [...] ## import sys @@ -84,20 +84,34 @@ def main(): # Some obfuscated expressions obf_exprs = [ - (x | y) + y - (~x & y), # x + y (from http://archive.bar/pdfs/bar2020-preprint9.pdf) - (x | y) - y + (~x & y), # x ^ y (from http://archive.bar/pdfs/bar2020-preprint9.pdf) - (x & ~y) | (~x & y), # x ^ y (from ?) - (x ^ y) + y - (~x & y), # x | y (from http://archive.bar/pdfs/bar2020-preprint9.pdf) - -(x | y) + y + x, # x & y (from http://archive.bar/pdfs/bar2020-preprint9.pdf) - ((z << 8) >> 16) << 8, # z & 0xffff00 (from https://blog.regehr.org/archives/1636) - (((x ^ y) + 2 * (x & y)) * 39 + 23) * 151 + 111, # x + y (from Ninon Eyrolle's thesis) - x_xor_92_obfuscated(x), # x ^ 92 (from imassage) - bswap32_xor_const(z), # ((bswap(z, 32) ^ 0x23746fbe) + 0xfffffffd) (from UnityPlayer.dll) + (x | y) + y - (~x & y), # x + y (from http://archive.bar/pdfs/bar2020-preprint9.pdf) + (x | y) - y + (~x & y), # x ^ y (from http://archive.bar/pdfs/bar2020-preprint9.pdf) + (x & ~y) | (~x & y), # x ^ y (from ?) + (x ^ y) + y - (~x & y), # x | y (from http://archive.bar/pdfs/bar2020-preprint9.pdf) + -(x | y) + y + x, # x & y (from http://archive.bar/pdfs/bar2020-preprint9.pdf) + ((z << 8) >> 16) << 8, # z & 0xffff00 (from https://blog.regehr.org/archives/1636) + (((x ^ y) + 2 * (x & y)) * 39 + 23) * 151 + 111, # x + y (from Ninon Eyrolle's thesis) + x_xor_92_obfuscated(x), # x ^ 92 (from iMassage) + bswap32_xor_const(z), # ((bswap(z, 32) ^ 0x23746fbe) + 0xfffffffd) (from UnityPlayer.dll) + (~(~(x) & ~(y)) & ~(~(~(x)) & ~(~(y)))), # x ^ y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + ((~(~(x)) & ~(~(y))) + (~(~(x)) | ~(~(y)))), # x + y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + ((~(~(y)) | ~(~(x))) + ~(~(x)) - (~(~(x)) & ~(~(~(y))))), # x + y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + ((~(~(x)) | ~(~(y))) + (~(~(~(x))) | ~(~(y))) - (~(~(~(x))))), # x + y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + ((~(~(x)) | ~(~(y))) + ~(~(y)) - (~(~(~(x))) & ~(~(y)))), # x + y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + (~(~(y)) + (~(~(x)) & ~(~(~(y)))) + (~(~(x)) & ~(~(y)))), # x + y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + (~(~(x) + y)), # x - y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + (~(((~(~(x)) | y) - (~(~(x)))))), # ~((x | y) - x) (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + (~((~(x) & ~(x)) + y) & ~((~(x) & ~(x)) + y)), # x - y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + ((~(~(x)) | y) - (~(~(~(x))) & y) - (~(~(x)) & ~y)), # x & y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + ((~(~(~(x))) | y) - (~(~(~(x))))), # x & y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + ((~(~(x)) & ~(y)) + y), # x | y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + (((~(~(x)) & ~(y)) & y) + ((~(~(x)) & ~(y)) | y)), # x | y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) + ((~(~(x)) & ~(~(y))) + (~(~(x)) | ~(~(y)))), # x + y (from VMProtect https://whereisr0da.github.io/blog/posts/2021-02-16-vmp-3/) ] for expr in obf_exprs: (print('In: %s' %(expr)) if len(str(expr)) < 100 else print('In: %s ...' %(str(expr)[0:100]))) - expr = ctx.synthesize(expr, constant=True, subexpr=True, opaque=False) + expr = ctx.synthesize(expr, constant=True, subexpr=True) print('Out: %s' %(expr)) print() diff --git a/src/libtriton/CMakeLists.txt b/src/libtriton/CMakeLists.txt index 7a62a926b..6770b0876 100644 --- a/src/libtriton/CMakeLists.txt +++ b/src/libtriton/CMakeLists.txt @@ -275,7 +275,7 @@ if(MSVC AND MSVC_STATIC) endif() if(WIN32 AND BUILD_SHARED_LIBS) - target_compile_definitions(triton PUBLIC TRITON_BUILDING_DLL) + target_compile_definitions(triton PRIVATE BUILDING_DLL) endif() # Install tritonTargets.cmake @@ -291,6 +291,7 @@ install( EXPORT tritonTargets PUBLIC_HEADER DESTINATION include/triton INCLUDES DESTINATION include + RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) diff --git a/src/libtriton/Config.cmake.in b/src/libtriton/Config.cmake.in index 0464166c9..683b5f251 100644 --- a/src/libtriton/Config.cmake.in +++ b/src/libtriton/Config.cmake.in @@ -8,6 +8,7 @@ set(TRITON_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@) set(TRITON_INCLUDE_DIRS "@CMAKE_INSTALL_PREFIX@/include") set(TRITON_INSTALL_PREFIX @CMAKE_INSTALL_PREFIX@) set(TRITON_LIBRARY "@CMAKE_INSTALL_PREFIX@/lib/@CMAKE_SHARED_LIBRARY_PREFIX@triton@CMAKE_SHARED_LIBRARY_SUFFIX@") +set(TRITON_LIBRARIES "${TRITON_LIBRARY};@PYTHON_LIBRARIES@;@Z3_LIBRARIES@;@LLVM_LIBRARIES@;@BITWUZLA_LIBRARIES@;@CAPSTONE_LIBRARIES@") set(TRITON_LLVM_INTERFACE @LLVM_INTERFACE@) set(TRITON_MSVC_STATIC @MSVC_STATIC@) set(TRITON_PYTHON_BINDINGS @PYTHON_BINDINGS@) @@ -18,3 +19,30 @@ message(STATUS "Found Triton: ${CMAKE_CURRENT_LIST_DIR}/tritonConfig.cmake (foun include(CMakeFindDependencyMacro) find_dependency(Boost) + +# Triton include +include_directories("@CMAKE_INSTALL_PREFIX@/include") + +# Capstone include +include_directories("@CAPSTONE_INCLUDE_DIRS@") + +# Python include directories +if (TRITON_PYTHON_BINDINGS) + include_directories("@PYTHON_INCLUDE_DIRS@") +endif() + +# LLVM include and lib directories +if (TRITON_LLVM_INTERFACE) + link_directories(BEFORE "@LLVM_LIBRARY_DIRS@") + include_directories("@LLVM_INCLUDE_DIRS@") +endif() + +# Z3 include directories +if (TRITON_Z3_INTERFACE) + include_directories("@Z3_INCLUDE_DIRS@") +endif() + +# Bitwuzla include directories +if (TRITON_BITWUZLA_INTERFACE) + include_directories("@BITWUZLA_INCLUDE_DIRS@") +endif() diff --git a/src/libtriton/api/api.cpp b/src/libtriton/api/api.cpp index 3337f3826..0b9d0c42e 100644 --- a/src/libtriton/api/api.cpp +++ b/src/libtriton/api/api.cpp @@ -881,13 +881,15 @@ namespace triton { } - triton::ast::SharedAbstractNode API::simplify(const triton::ast::SharedAbstractNode& node, bool usingSolver) const { - this->checkSymbolic(); - + triton::ast::SharedAbstractNode API::simplify(const triton::ast::SharedAbstractNode& node, bool usingSolver, bool usingLLVM) const { if (usingSolver) { return this->simplifyAstViaSolver(node); } + else if (usingLLVM) { + return this->simplifyAstViaLLVM(node); + } else { + this->checkSymbolic(); return this->symbolic->simplify(node); } } @@ -1133,7 +1135,7 @@ namespace triton { #endif #ifdef TRITON_BITWUZLA_INTERFACE if (this->getSolver() == triton::engines::solver::SOLVER_BITWUZLA) { - return reinterpret_cast(this->getSolverInstance())->evaluate(node); + return reinterpret_cast(this->getSolverInstance())->evaluate(node); } #endif throw triton::exceptions::API("API::evaluateAstViaZ3(): Solver instance must be a SOLVER_Z3 or SOLVER_BITWUZLA."); @@ -1373,17 +1375,17 @@ namespace triton { /* Lifters engine API ================================================================================= */ - std::ostream& API::liftToLLVM(std::ostream& stream, const triton::ast::SharedAbstractNode& node) { + std::ostream& API::liftToLLVM(std::ostream& stream, const triton::ast::SharedAbstractNode& node, const char* fname, bool optimize) { this->checkLifting(); #ifdef TRITON_LLVM_INTERFACE - return this->lifting->liftToLLVM(stream, node); + return this->lifting->liftToLLVM(stream, node, fname, optimize); #endif throw triton::exceptions::API("API::liftToLLVM(): Triton not built with LLVM"); } - std::ostream& API::liftToLLVM(std::ostream& stream, const triton::engines::symbolic::SharedSymbolicExpression& expr) { - return this->liftToLLVM(stream, expr->getAst()); + std::ostream& API::liftToLLVM(std::ostream& stream, const triton::engines::symbolic::SharedSymbolicExpression& expr, const char* fname, bool optimize) { + return this->liftToLLVM(stream, expr->getAst(), fname, optimize); } @@ -1398,4 +1400,13 @@ namespace triton { return this->lifting->liftToSMT(stream, expr, assert_); } + + triton::ast::SharedAbstractNode API::simplifyAstViaLLVM(const triton::ast::SharedAbstractNode& node) const { + this->checkLifting(); + #ifdef TRITON_LLVM_INTERFACE + return this->lifting->simplifyAstViaLLVM(node); + #endif + throw triton::exceptions::API("API::simplifyAstViaLLVM(): Triton not built with LLVM"); + } + }; /* triton namespace */ diff --git a/src/libtriton/arch/instruction.cpp b/src/libtriton/arch/instruction.cpp index 61492d53c..be1c8a60f 100644 --- a/src/libtriton/arch/instruction.cpp +++ b/src/libtriton/arch/instruction.cpp @@ -35,12 +35,14 @@ namespace triton { } - Instruction::Instruction(const triton::uint8* opcode, triton::uint32 opSize) : Instruction::Instruction() { + Instruction::Instruction(const triton::uint8* opcode, triton::uint32 opSize) + : Instruction::Instruction() { this->setOpcode(opcode, opSize); } - Instruction::Instruction(triton::uint64 addr, const triton::uint8* opcode, triton::uint32 opSize) : Instruction::Instruction(opcode, opSize) { + Instruction::Instruction(triton::uint64 addr, const triton::uint8* opcode, triton::uint32 opSize) + : Instruction::Instruction(opcode, opSize) { this->setAddress(addr); } @@ -132,7 +134,7 @@ namespace triton { void Instruction::setOpcode(const triton::uint8* opcode, triton::uint32 size) { - if (size >= sizeof(this->opcode)) + if (size > sizeof(this->opcode)) throw triton::exceptions::Instruction("Instruction::setOpcode(): Invalid size (too big)."); std::memcpy(this->opcode, opcode, size); this->size = size; @@ -340,11 +342,10 @@ namespace triton { } - const triton::engines::symbolic::SharedSymbolicExpression& Instruction::addSymbolicExpression(const triton::engines::symbolic::SharedSymbolicExpression& expr) { + void Instruction::addSymbolicExpression(const triton::engines::symbolic::SharedSymbolicExpression& expr) { if (expr == nullptr) throw triton::exceptions::Instruction("Instruction::addSymbolicExpression(): Cannot add a null expression."); this->symbolicExpressions.push_back(expr); - return this->symbolicExpressions.back(); } diff --git a/src/libtriton/ast/ast.cpp b/src/libtriton/ast/ast.cpp index f9086b3ec..cf79030ee 100644 --- a/src/libtriton/ast/ast.cpp +++ b/src/libtriton/ast/ast.cpp @@ -183,13 +183,13 @@ namespace triton { auto it = parents.find(p); if (it == parents.end()) { - auto A = p->shared_from_this(); + SharedAbstractNode A = p->shared_from_this(); this->parents.insert(std::make_pair(p, std::make_pair(1, WeakAbstractNode(A)))); } else { if (it->second.second.expired()) { parents.erase(it); - auto A = p->shared_from_this(); + SharedAbstractNode A = p->shared_from_this(); this->parents.insert(std::make_pair(p, std::make_pair(1, WeakAbstractNode(A)))); } // Ptr already in, add it for the counter @@ -213,8 +213,9 @@ namespace triton { void AbstractNode::setParent(std::unordered_set& p) { - for (auto ptr : p) + for (AbstractNode* ptr : p) { this->setParent(ptr); + } } @@ -3290,7 +3291,7 @@ namespace triton { /* If unroll is true, we unroll all references */ if (unroll && ast->getType() == REFERENCE_NODE) { - const auto& ref = reinterpret_cast(ast.get())->getSymbolicExpression()->getAst(); + const SharedAbstractNode& ref = reinterpret_cast(ast.get())->getSymbolicExpression()->getAst(); if (visited.find(ref.get()) == visited.end()) { worklist.push({ref, false}); } @@ -3323,7 +3324,7 @@ namespace triton { worklist.push(node.get()); while (!worklist.empty()) { - auto current = worklist.top(); + AbstractNode* current = worklist.top(); worklist.pop(); // This means that node is already visited and we will not need to visited it second time @@ -3339,7 +3340,7 @@ namespace triton { worklist.push(reinterpret_cast(current)->getSymbolicExpression()->getAst().get()); } else { - for (const auto& child : current->getChildren()) { + for (const SharedAbstractNode& child : current->getChildren()) { worklist.push(child.get()); } } diff --git a/src/libtriton/ast/astContext.cpp b/src/libtriton/ast/astContext.cpp index b0bb29766..310a9853d 100644 --- a/src/libtriton/ast/astContext.cpp +++ b/src/libtriton/ast/astContext.cpp @@ -760,7 +760,7 @@ namespace triton { if (this->modes->isModeEnabled(triton::modes::AST_OPTIMIZATIONS)) { /* Optimization: concatenate extractions in one if possible */ - auto n = this->simplify_concat(std::vector({expr1, expr2})); + SharedAbstractNode n = this->simplify_concat(std::vector({expr1, expr2})); if (n) { return n; } @@ -807,7 +807,7 @@ namespace triton { return expr; if (this->modes->isModeEnabled(triton::modes::AST_OPTIMIZATIONS)) { - auto n = this->simplify_extract(high, low, expr); + SharedAbstractNode n = this->simplify_extract(high, low, expr); if (n) { return n; } @@ -1099,7 +1099,7 @@ namespace triton { /* Try to join all extractions into one from the right to the left */ while (!exprs.empty()) { /* Get the right most node */ - auto n = exprs.back(); + SharedAbstractNode n = exprs.back(); exprs.pop_back(); /* Returns the first non referene node encountered */ @@ -1107,7 +1107,7 @@ namespace triton { if (n->getType() == CONCAT_NODE) { /* Append concatenation children to the right */ - for (const auto& part : n->getChildren()) { + for (const SharedAbstractNode& part : n->getChildren()) { exprs.push_back(part); } continue; @@ -1120,8 +1120,8 @@ namespace triton { /* Get extraction arguments */ const auto& childs = n->getChildren(); - auto hi = reinterpret_cast(childs[0].get())->getInteger().convert_to(); - auto lo = reinterpret_cast(childs[1].get())->getInteger().convert_to(); + triton::uint32 hi = reinterpret_cast(childs[0].get())->getInteger().convert_to(); + triton::uint32 lo = reinterpret_cast(childs[1].get())->getInteger().convert_to(); if (hi < lo) { return 0; } @@ -1160,16 +1160,16 @@ namespace triton { SharedAbstractNode AstContext::simplify_extract(triton::uint32 high, triton::uint32 low, const SharedAbstractNode& expr) { - auto size = expr->getBitvectorSize(); + triton::uint32 size = expr->getBitvectorSize(); if (high <= low || high >= size) { return 0; } - auto node = expr; + SharedAbstractNode node = expr; while (true) { /* Returns the first non referene node encountered */ - auto n = triton::ast::dereference(node); + SharedAbstractNode n = triton::ast::dereference(node); if (n->getType() == CONCAT_NODE) { /* @@ -1181,17 +1181,17 @@ namespace triton { * ((_ extract 11 9) (concat (_ bv1 8) (_ bv2 8) (_ bv3 8) (_ bv4 8))) => * ((_ extract 3 1) (_ bv3 8)) */ - auto hi = n->getBitvectorSize() - 1; + triton::uint32 hi = n->getBitvectorSize() - 1; bool found = false; /* Search for part of concatenation we can extract from. Iterate * from the left to the right. */ - for (const auto& part : n->getChildren()) { + for (const SharedAbstractNode& part : n->getChildren()) { if (hi < high) { /* Did not find a part we can extract from */ break; } - auto sz = part->getBitvectorSize(); - auto lo = hi + 1 - sz; + triton::uint32 sz = part->getBitvectorSize(); + triton::uint32 lo = hi + 1 - sz; if (hi == high && lo == low) { /* We are extracting the full part, just return it */ return part; @@ -1222,7 +1222,7 @@ namespace triton { * ((_ extract 7 0) (_ bv1 32)) **/ n = n->getChildren()[1]; - auto sz = n->getBitvectorSize(); + triton::uint32 sz = n->getBitvectorSize(); if (low == 0 && high + 1 == sz) { /* Just return the node being extended */ return n; @@ -1237,7 +1237,7 @@ namespace triton { } /* Returns the first non referene node encountered */ - auto n = triton::ast::dereference(node); + SharedAbstractNode n = triton::ast::dereference(node); /* * Optimization: extract from extract is one extract @@ -1247,8 +1247,8 @@ namespace triton { **/ if (n->getType() == EXTRACT_NODE) { const auto& childs = n->getChildren(); - auto hi = reinterpret_cast(childs[0].get())->getInteger().convert_to(); - auto lo = reinterpret_cast(childs[1].get())->getInteger().convert_to(); + triton::uint32 hi = reinterpret_cast(childs[0].get())->getInteger().convert_to(); + triton::uint32 lo = reinterpret_cast(childs[1].get())->getInteger().convert_to(); if (lo + high <= hi) { node = childs[2]; high += lo; diff --git a/src/libtriton/ast/llvm/tritonToLLVM.cpp b/src/libtriton/ast/llvm/tritonToLLVM.cpp index f9e8d0ae2..9ab350a33 100644 --- a/src/libtriton/ast/llvm/tritonToLLVM.cpp +++ b/src/libtriton/ast/llvm/tritonToLLVM.cpp @@ -35,6 +35,9 @@ namespace triton { // Collect used symbolic variables. auto vars = triton::ast::search(node, triton::ast::VARIABLE_NODE); + //! Sort symbolic variables + std::sort(vars.begin(), vars.end()); + // Each symbolic variable is a function argument std::vector argsType; argsType.resize(vars.size()); @@ -78,7 +81,7 @@ namespace triton { } - std::shared_ptr TritonToLLVM::convert(const triton::ast::SharedAbstractNode& node, const char* fname) { + std::shared_ptr TritonToLLVM::convert(const triton::ast::SharedAbstractNode& node, const char* fname, bool optimize) { std::unordered_map results; /* Create the LLVM function */ @@ -95,6 +98,16 @@ namespace triton { /* Create the return instruction */ this->llvmIR.CreateRet(results.at(node)); + /* Apply LLVM optimizations (-03 -Oz) if enabled */ + if (optimize) { + llvm::legacy::PassManager pm; + llvm::PassManagerBuilder pmb; + pmb.OptLevel = 3; + pmb.SizeLevel = 2; + pmb.populateModulePassManager(pm); + pm.run(*this->llvmModule); + } + return this->llvmModule; } diff --git a/src/libtriton/bindings/python/objects/pyTritonContext.cpp b/src/libtriton/bindings/python/objects/pyTritonContext.cpp index 5dfa40350..ac6867016 100644 --- a/src/libtriton/bindings/python/objects/pyTritonContext.cpp +++ b/src/libtriton/bindings/python/objects/pyTritonContext.cpp @@ -286,11 +286,11 @@ Returns true if the taint engine is enabled. - bool isThumb(void)
Returns true if execution mode is Thumb (only valid for ARM32). -- string liftToLLVM(\ref py_AstNode_page node)
-Lifts an AST node and all its references to LLVM IR. +- string liftToLLVM(\ref py_AstNode_page node, string fname="__triton", bool optimize=False)
+Lifts an AST node and all its references to LLVM IR. `fname` is the name of the LLVM function, by default it's `__triton`. If `optimize` is true, perform optimizations (-O3 -Oz). -- string liftToLLVM(\ref py_SymbolicExpression_page expr)
-Lifts a symbolic expression and all its references to LLVM IR. +- string liftToLLVM(\ref py_SymbolicExpression_page expr, string fname="__triton", bool optimize=False)
+Lifts a symbolic expression and all its references to LLVM IR. `fname` is the name of the LLVM function, by default it's `__triton`. If `optimize` is true, perform optimizations (-O3 -Oz). - string liftToPython(\ref py_SymbolicExpression_page expr)
Lifts a symbolic expression and all its references to Python format. @@ -369,9 +369,10 @@ Sets the targeted register as tainted or not. Returns true if the register is st - void setThumb(bool state)
Sets CPU state to Thumb mode (only valid for ARM32). -- \ref py_AstNode_page simplify(\ref py_AstNode_page node, bool solver=False)
+- \ref py_AstNode_page simplify(\ref py_AstNode_page node, bool solver=False, bool llvm=False)
Calls all simplification callbacks recorded and returns a new simplified node. If the `solver` flag is -set to True, Triton will use the current solver instance to simplify the given `node`. +set to True, Triton will use the current solver instance to simplify the given `node`. If `llvm` is true, +we use LLVM to simplify node. - dict sliceExpressions(\ref py_SymbolicExpression_page expr)
Slices expressions from a given one (backward slicing) and returns all symbolic expressions as a dictionary of {integer SymExprId : \ref py_SymbolicExpression_page expr}. @@ -1403,7 +1404,7 @@ namespace triton { } if (node == nullptr || !PyAstNode_Check(node)) { - return PyErr_Format(PyExc_TypeError, "TritonContext::getModel(): Expects a AstNode as argument."); + return PyErr_Format(PyExc_TypeError, "TritonContext::getModel(): Expects a AstNode as node argument."); } if (wb != nullptr && !PyBool_Check(wb)) { @@ -1469,11 +1470,11 @@ namespace triton { } if (node == nullptr || !PyAstNode_Check(node)) { - return PyErr_Format(PyExc_TypeError, "TritonContext::getModels(): Expects a AstNode as first argument."); + return PyErr_Format(PyExc_TypeError, "TritonContext::getModels(): Expects a AstNode as node argument."); } if (limit == nullptr || (!PyLong_Check(limit) && !PyInt_Check(limit))) { - return PyErr_Format(PyExc_TypeError, "TritonContext::getModels(): Expects an integer as second argument."); + return PyErr_Format(PyExc_TypeError, "TritonContext::getModels(): Expects an integer as limit argument."); } if (wb != nullptr && !PyBool_Check(wb)) { @@ -2231,17 +2232,45 @@ namespace triton { } - static PyObject* TritonContext_liftToLLVM(PyObject* self, PyObject* arg) { - if (!PySymbolicExpression_Check(arg) && !PyAstNode_Check(arg)) - return PyErr_Format(PyExc_TypeError, "TritonContext::liftToLLVM(): Expects a SymbolicExpression or a AstNode as first argument."); + static PyObject* TritonContext_liftToLLVM(PyObject* self, PyObject* args, PyObject* kwargs) { + PyObject* node = nullptr; + PyObject* fname = nullptr; + PyObject* optimize = nullptr; + + static char* keywords[] = { + (char*)"node", + (char*)"fname", + (char*)"optimize", + nullptr + }; + + /* Extract keywords */ + if (PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO", keywords, &node, &fname, &optimize) == false) { + return PyErr_Format(PyExc_TypeError, "TritonContext::liftToLLVM(): Invalid number of arguments"); + } + + if (node == nullptr || (!PySymbolicExpression_Check(node) && !PyAstNode_Check(node))) + return PyErr_Format(PyExc_TypeError, "TritonContext::liftToLLVM(): Expects a SymbolicExpression or a AstNode as node argument."); + + if (fname != nullptr && !PyStr_Check(fname)) + return PyErr_Format(PyExc_TypeError, "TritonContext::liftToLLVM(): Expects a string as fname argument."); + + if (optimize != nullptr && !PyBool_Check(optimize)) + return PyErr_Format(PyExc_TypeError, "TritonContext::liftToLLVM(): Expects a boolean as optimize argument."); + + if (fname == nullptr) + fname = PyStr_FromString("__triton"); + + if (optimize == nullptr) + optimize = PyLong_FromUint32(false); try { std::ostringstream stream; - if (PySymbolicExpression_Check(arg)) { - PyTritonContext_AsTritonContext(self)->liftToLLVM(stream, PySymbolicExpression_AsSymbolicExpression(arg)); + if (PySymbolicExpression_Check(node)) { + PyTritonContext_AsTritonContext(self)->liftToLLVM(stream, PySymbolicExpression_AsSymbolicExpression(node), PyStr_AsString(fname), PyLong_AsBool(optimize)); } else { - PyTritonContext_AsTritonContext(self)->liftToLLVM(stream, PyAstNode_AsAstNode(arg)); + PyTritonContext_AsTritonContext(self)->liftToLLVM(stream, PyAstNode_AsAstNode(node), PyStr_AsString(fname), PyLong_AsBool(optimize)); } return xPyString_FromString(stream.str().c_str()); } @@ -2899,29 +2928,37 @@ namespace triton { static PyObject* TritonContext_simplify(PyObject* self, PyObject* args, PyObject* kwargs) { PyObject* node = nullptr; PyObject* solver = nullptr; + PyObject* llvm = nullptr; static char* keywords[] = { (char*)"node", (char*)"solver", + (char*)"llvm", nullptr }; /* Extract keywords */ - if (PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", keywords, &node, &solver) == false) { + if (PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO", keywords, &node, &solver, &llvm) == false) { return PyErr_Format(PyExc_TypeError, "TritonContext::simplify(): Invalid number of arguments"); } if (node == nullptr || !PyAstNode_Check(node)) - return PyErr_Format(PyExc_TypeError, "TritonContext::simplify(): Expects a AstNode as first argument."); + return PyErr_Format(PyExc_TypeError, "TritonContext::simplify(): Expects a AstNode as node argument."); if (solver != nullptr && !PyBool_Check(solver)) - return PyErr_Format(PyExc_TypeError, "TritonContext::simplify(): Expects a boolean as second argument."); + return PyErr_Format(PyExc_TypeError, "TritonContext::simplify(): Expects a boolean as solver argument."); + + if (llvm != nullptr && !PyBool_Check(llvm)) + return PyErr_Format(PyExc_TypeError, "TritonContext::simplify(): Expects a boolean as llvm argument."); if (solver == nullptr) solver = PyLong_FromUint32(false); + if (llvm == nullptr) + llvm = PyLong_FromUint32(false); + try { - return PyAstNode(PyTritonContext_AsTritonContext(self)->simplify(PyAstNode_AsAstNode(node), PyLong_AsBool(solver))); + return PyAstNode(PyTritonContext_AsTritonContext(self)->simplify(PyAstNode_AsAstNode(node), PyLong_AsBool(solver), PyLong_AsBool(llvm))); } catch (const triton::exceptions::PyCallbacks&) { return nullptr; @@ -3073,16 +3110,16 @@ namespace triton { } if (node == nullptr || !PyAstNode_Check(node)) - return PyErr_Format(PyExc_TypeError, "TritonContext::synthesize(): Expects a AstNode as first argument."); + return PyErr_Format(PyExc_TypeError, "TritonContext::synthesize(): Expects a AstNode as node argument."); if (constant != nullptr && !PyBool_Check(constant)) - return PyErr_Format(PyExc_TypeError, "TritonContext::synthesize(): Expects a boolean as second argument."); + return PyErr_Format(PyExc_TypeError, "TritonContext::synthesize(): Expects a boolean as constant argument."); if (subexpr != nullptr && !PyBool_Check(subexpr)) - return PyErr_Format(PyExc_TypeError, "TritonContext::synthesize(): Expects a boolean as third argument."); + return PyErr_Format(PyExc_TypeError, "TritonContext::synthesize(): Expects a boolean as subexpr argument."); if (opaque != nullptr && !PyBool_Check(opaque)) - return PyErr_Format(PyExc_TypeError, "TritonContext::synthesize(): Expects a boolean as fourth argument."); + return PyErr_Format(PyExc_TypeError, "TritonContext::synthesize(): Expects a boolean as opaque argument."); if (constant == nullptr) constant = PyLong_FromUint32(true); @@ -3405,7 +3442,7 @@ namespace triton { {"isSymbolicExpressionExists", (PyCFunction)TritonContext_isSymbolicExpressionExists, METH_O, ""}, {"isTaintEngineEnabled", (PyCFunction)TritonContext_isTaintEngineEnabled, METH_NOARGS, ""}, {"isThumb", (PyCFunction)TritonContext_isThumb, METH_NOARGS, ""}, - {"liftToLLVM", (PyCFunction)TritonContext_liftToLLVM, METH_O, ""}, + {"liftToLLVM", (PyCFunction)(void*)(PyCFunctionWithKeywords)TritonContext_liftToLLVM, METH_VARARGS | METH_KEYWORDS, ""}, {"liftToPython", (PyCFunction)TritonContext_liftToPython, METH_O, ""}, {"liftToSMT", (PyCFunction)TritonContext_liftToSMT, METH_VARARGS, ""}, {"newSymbolicExpression", (PyCFunction)TritonContext_newSymbolicExpression, METH_VARARGS, ""}, diff --git a/src/libtriton/engines/lifters/liftingToLLVM.cpp b/src/libtriton/engines/lifters/liftingToLLVM.cpp index 998af444f..02ada388c 100644 --- a/src/libtriton/engines/lifters/liftingToLLVM.cpp +++ b/src/libtriton/engines/lifters/liftingToLLVM.cpp @@ -9,9 +9,14 @@ #include #include +#include #include +#include #include +#include +#include + namespace triton { @@ -22,13 +27,13 @@ namespace triton { } - std::ostream& LiftingToLLVM::liftToLLVM(std::ostream& stream, const triton::engines::symbolic::SharedSymbolicExpression& expr) { - this->liftToLLVM(stream, expr->getAst()); + std::ostream& LiftingToLLVM::liftToLLVM(std::ostream& stream, const triton::engines::symbolic::SharedSymbolicExpression& expr, const char* fname, bool optimize) { + this->liftToLLVM(stream, expr->getAst(), fname, optimize); return stream; } - std::ostream& LiftingToLLVM::liftToLLVM(std::ostream& stream, const triton::ast::SharedAbstractNode& node) { + std::ostream& LiftingToLLVM::liftToLLVM(std::ostream& stream, const triton::ast::SharedAbstractNode& node, const char* fname, bool optimize) { /* The LLVM context */ llvm::LLVMContext context; @@ -36,7 +41,7 @@ namespace triton { triton::ast::TritonToLLVM lifter(context); /* Lift AST to LLVM IR */ - auto llvmModule = lifter.convert(node); + auto llvmModule = lifter.convert(node, fname, optimize); /* Print the LLVM module into the stream */ std::string dump; @@ -47,6 +52,17 @@ namespace triton { return stream; } + + triton::ast::SharedAbstractNode LiftingToLLVM::simplifyAstViaLLVM(const triton::ast::SharedAbstractNode& node) const { + llvm::LLVMContext context; + + triton::ast::TritonToLLVM ttllvm(context); + triton::ast::LLVMToTriton llvmtt(node->getContext()); + + auto llvmModule = ttllvm.convert(node, "__tmp", true); /* from triton to llvm */ + return llvmtt.convert(llvmModule.get(), "__tmp"); /* from llvm to triton */ + } + }; /* lifters namespace */ }; /* engines namespace */ }; /* triton namespace */ diff --git a/src/libtriton/engines/symbolic/symbolicExpression.cpp b/src/libtriton/engines/symbolic/symbolicExpression.cpp index 14ae6f9a9..70ebe068d 100644 --- a/src/libtriton/engines/symbolic/symbolicExpression.cpp +++ b/src/libtriton/engines/symbolic/symbolicExpression.cpp @@ -122,20 +122,20 @@ namespace triton { else if (ast->getContext()->getRepresentationMode() == triton::ast::representations::SMT_REPRESENTATION) { stream << "(define-fun " << this->getFormattedId() << " () (_ BitVec " << std::dec << this->getAst()->getBitvectorSize() << ") " << this->getAst() << ")"; - if (!this->getComment().empty()) - stream << " " << this->getFormattedComment(); - return stream.str(); } else if (ast->getContext()->getRepresentationMode() == triton::ast::representations::PYTHON_REPRESENTATION) { stream << this->getFormattedId() << " = " << this->getAst(); - if (!this->getComment().empty()) - stream << " " << this->getFormattedComment(); - return stream.str(); } else throw triton::exceptions::SymbolicExpression("SymbolicExpression::getFormattedExpression(): Invalid AST representation mode."); + + if (!this->getComment().empty()) { + stream << " " << this->getFormattedComment(); + } + + return stream.str(); } diff --git a/src/libtriton/engines/symbolic/symbolicVariable.cpp b/src/libtriton/engines/symbolic/symbolicVariable.cpp index a6bb13ed3..0d29f9c12 100644 --- a/src/libtriton/engines/symbolic/symbolicVariable.cpp +++ b/src/libtriton/engines/symbolic/symbolicVariable.cpp @@ -118,6 +118,11 @@ namespace triton { return stream; } + + bool operator<(const SymbolicVariable& symvar1, const SymbolicVariable& symvar2) { + return symvar1.getId() < symvar2.getId(); + } + }; /* symbolic namespace */ }; /* engines namespace */ }; /*triton namespace */ diff --git a/src/libtriton/includes/triton/api.hpp b/src/libtriton/includes/triton/api.hpp index f1fa8067c..ede8f074d 100644 --- a/src/libtriton/includes/triton/api.hpp +++ b/src/libtriton/includes/triton/api.hpp @@ -407,8 +407,8 @@ namespace triton { //! [**symbolic api**] - Assigns a symbolic expression to a register. TRITON_EXPORT void assignSymbolicExpressionToRegister(const triton::engines::symbolic::SharedSymbolicExpression& se, const triton::arch::Register& reg); - //! [**symbolic api**] - Processes all recorded AST simplifications or uses solver's simplifications if `usingSolver` is true. Returns the simplified AST. - TRITON_EXPORT triton::ast::SharedAbstractNode simplify(const triton::ast::SharedAbstractNode& node, bool usingSolver = false) const; + //! [**symbolic api**] - Processes all recorded AST simplifications, uses solver's simplifications if `usingSolver` is true or LLVM is `usingLLVM` is true. Returns the simplified AST. + TRITON_EXPORT triton::ast::SharedAbstractNode simplify(const triton::ast::SharedAbstractNode& node, bool usingSolver=false, bool usingLLVM=false) const; //! [**symbolic api**] - Returns the shared symbolic expression corresponding to an id. TRITON_EXPORT triton::engines::symbolic::SharedSymbolicExpression getSymbolicExpression(triton::usize symExprId) const; @@ -672,17 +672,20 @@ namespace triton { /* Lifters engine API ================================================================================= */ - //! [**lifting api**] - Lifts an AST and all its references to LLVM format. - TRITON_EXPORT std::ostream& liftToLLVM(std::ostream& stream, const triton::ast::SharedAbstractNode& node); + //! [**lifting api**] - Lifts an AST and all its references to LLVM format. `fname` represents the name of the LLVM function. + TRITON_EXPORT std::ostream& liftToLLVM(std::ostream& stream, const triton::ast::SharedAbstractNode& node, const char* fname="__triton", bool optimize=false); - //! [**lifting api**] - Lifts a symbolic expression and all its references to LLVM format. - TRITON_EXPORT std::ostream& liftToLLVM(std::ostream& stream, const triton::engines::symbolic::SharedSymbolicExpression& expr); + //! [**lifting api**] - Lifts a symbolic expression and all its references to LLVM format. `fname` represents the name of the LLVM function. + TRITON_EXPORT std::ostream& liftToLLVM(std::ostream& stream, const triton::engines::symbolic::SharedSymbolicExpression& expr, const char* fname="__triton", bool optimize=false); //! [**lifting api**] - Lifts a symbolic expression and all its references to Python format. TRITON_EXPORT std::ostream& liftToPython(std::ostream& stream, const triton::engines::symbolic::SharedSymbolicExpression& expr); //! [**lifting api**] - Lifts a symbolic expression and all its references to SMT format. If `assert_` is true, then (assert ). TRITON_EXPORT std::ostream& liftToSMT(std::ostream& stream, const triton::engines::symbolic::SharedSymbolicExpression& expr, bool assert_); + + //! [**lifting api**] - Lifts and simplify an AST using LLVM + TRITON_EXPORT triton::ast::SharedAbstractNode simplifyAstViaLLVM(const triton::ast::SharedAbstractNode& node) const; }; /*! @} End of triton namespace */ diff --git a/src/libtriton/includes/triton/instruction.hpp b/src/libtriton/includes/triton/instruction.hpp index a213edc09..1aee2fd2d 100644 --- a/src/libtriton/includes/triton/instruction.hpp +++ b/src/libtriton/includes/triton/instruction.hpp @@ -57,7 +57,7 @@ namespace triton { std::stringstream disassembly; //! The opcode of the instruction. - triton::uint8 opcode[32]; + triton::uint8 opcode[16]; //! The size of the instruction. triton::uint32 size; @@ -260,7 +260,7 @@ namespace triton { TRITON_EXPORT void setThumb(bool state); //! Adds a symbolic expression - TRITON_EXPORT const triton::engines::symbolic::SharedSymbolicExpression& addSymbolicExpression(const triton::engines::symbolic::SharedSymbolicExpression& expr); + TRITON_EXPORT void addSymbolicExpression(const triton::engines::symbolic::SharedSymbolicExpression& expr); //! Returns true if this instruction is a branch TRITON_EXPORT bool isBranch(void) const; diff --git a/src/libtriton/includes/triton/liftingToLLVM.hpp b/src/libtriton/includes/triton/liftingToLLVM.hpp index 35162c95c..f3a1aedab 100644 --- a/src/libtriton/includes/triton/liftingToLLVM.hpp +++ b/src/libtriton/includes/triton/liftingToLLVM.hpp @@ -16,10 +16,6 @@ #include #include -#include -#include -#include - //! The Triton namespace @@ -52,11 +48,14 @@ namespace triton { //! Constructor. TRITON_EXPORT LiftingToLLVM(); - //! Lifts a symbolic expression and all its references to LLVM format. - TRITON_EXPORT std::ostream& liftToLLVM(std::ostream& stream, const triton::engines::symbolic::SharedSymbolicExpression& expr); + //! Lifts a symbolic expression and all its references to LLVM format. `fname` represents the name of the LLVM function. + TRITON_EXPORT std::ostream& liftToLLVM(std::ostream& stream, const triton::engines::symbolic::SharedSymbolicExpression& expr, const char* fname="__triton", bool optimize=false); + + //! Lifts a abstract node and all its references to LLVM format. `fname` represents the name of the LLVM function. + TRITON_EXPORT std::ostream& liftToLLVM(std::ostream& stream, const triton::ast::SharedAbstractNode& node, const char* fname="__triton", bool optimize=false); - //! Lifts a abstract node and all its references to LLVM format. - TRITON_EXPORT std::ostream& liftToLLVM(std::ostream& stream, const triton::ast::SharedAbstractNode& node); + //! Lifts and simplify an AST using LLVM + TRITON_EXPORT triton::ast::SharedAbstractNode simplifyAstViaLLVM(const triton::ast::SharedAbstractNode& node) const; }; /*! @} End of lifters namespace */ diff --git a/src/libtriton/includes/triton/symbolicVariable.hpp b/src/libtriton/includes/triton/symbolicVariable.hpp index 5cf4a3c3e..a8eb492e2 100644 --- a/src/libtriton/includes/triton/symbolicVariable.hpp +++ b/src/libtriton/includes/triton/symbolicVariable.hpp @@ -126,6 +126,9 @@ namespace triton { //! Displays a symbolic variable. TRITON_EXPORT std::ostream& operator<<(std::ostream& stream, const SymbolicVariable* symVar); + //! Compares two symbolic variables. + TRITON_EXPORT bool operator<(const SymbolicVariable& symvar1, const SymbolicVariable& symvar2); + /*! @} End of symbolic namespace */ }; /*! @} End of engines namespace */ diff --git a/src/libtriton/includes/triton/tritonToLLVM.hpp b/src/libtriton/includes/triton/tritonToLLVM.hpp index 551b27cb2..6a0344f21 100644 --- a/src/libtriton/includes/triton/tritonToLLVM.hpp +++ b/src/libtriton/includes/triton/tritonToLLVM.hpp @@ -19,7 +19,9 @@ #include #include +#include #include +#include @@ -42,30 +44,30 @@ namespace triton { /*! \brief Converts a Triton's AST to LVM IR. */ class TritonToLLVM { private: - //! The LLVM context + //! The LLVM context. llvm::LLVMContext& llvmContext; - //! The LLVM module + //! The LLVM module. std::shared_ptr llvmModule; - //! The LLVM IR builder + //! The LLVM IR builder. llvm::IRBuilder<> llvmIR; - //! Map Triton variables to LLVM ones + //! Map Triton variables to LLVM ones. std::map llvmVars; - //! Create a LLVM function + //! Create a LLVM function. `fname` represents the name of the LLVM function. void createFunction(const triton::ast::SharedAbstractNode& node, const char* fname); - //! Converts Triton AST to LLVM IR + //! Converts Triton AST to LLVM IR. llvm::Value* do_convert(const triton::ast::SharedAbstractNode& node, std::unordered_map* results); public: //! Constructor. TRITON_EXPORT TritonToLLVM(llvm::LLVMContext& llvmContext); - //! Lifts a symbolic expression and all its references to LLVM format. - TRITON_EXPORT std::shared_ptr convert(const triton::ast::SharedAbstractNode& node, const char* fname="__triton"); + //! Lifts a symbolic expression and all its references to LLVM format. `fname` represents the name of the LLVM function. + TRITON_EXPORT std::shared_ptr convert(const triton::ast::SharedAbstractNode& node, const char* fname="__triton", bool optimize=false); }; /*! @} End of ast namespace */ diff --git a/src/testers/unittests/test_ast_representation.py b/src/testers/unittests/test_ast_representation.py index 7c9642429..ebe827475 100644 --- a/src/testers/unittests/test_ast_representation.py +++ b/src/testers/unittests/test_ast_representation.py @@ -269,4 +269,4 @@ def test_lifting(self): ] for n in nodes: - self.assertNotEqual(len(self.ctx.liftToLLVM(n)), 0) + self.assertNotEqual(len(self.ctx.liftToLLVM(n, fname="test", optimize=True)), 0) diff --git a/src/testers/unittests/test_ast_simplification.py b/src/testers/unittests/test_ast_simplification.py index 533a8d7ae..f4dc6fc28 100644 --- a/src/testers/unittests/test_ast_simplification.py +++ b/src/testers/unittests/test_ast_simplification.py @@ -724,3 +724,19 @@ def test_issue_1002_2(self): "(define-fun ref!13 () (_ BitVec 1) ((_ extract 63 63) ref!8)) ; Sign flag - 0x0: sub qword ptr [rdx], rcx\n" "(define-fun ref!14 () (_ BitVec 1) (_ bv1 1)) ; Zero flag - 0x0: sub qword ptr [rdx], rcx\n" "(define-fun ref!15 () (_ BitVec 64) (_ bv3 64)) ; Program Counter - 0x0: sub qword ptr [rdx], rcx")) + + +class TestAstSimplificationLLVM(unittest.TestCase): + def setUp(self): + self.ctx = TritonContext(ARCH.X86_64) + self.ast = self.ctx.getAstContext() + + def test_1(self): + if VERSION.LLVM_INTERFACE is True: + x = self.ast.variable(self.ctx.newSymbolicVariable(8, 'x')) + y = self.ast.variable(self.ctx.newSymbolicVariable(8, 'y')) + n = (x & ~y) | (~x & y) + o = self.ctx.simplify(n, llvm=True) + r = str(o) == "(bvxor y x)" or str(o) == "(bvxor x y)" + self.assertTrue(r) + return diff --git a/src/testers/unittests/test_simulation.py b/src/testers/unittests/test_simulation.py index 25db1b29c..12583143a 100644 --- a/src/testers/unittests/test_simulation.py +++ b/src/testers/unittests/test_simulation.py @@ -346,7 +346,7 @@ def test_emulate(self, concretize=False): # run the code pc = self.Triton.getConcreteRegisterValue(self.Triton.registers.rip) while pc != 0x409A18: - opcode = self.Triton.getConcreteMemoryAreaValue(pc, 20) + opcode = self.Triton.getConcreteMemoryAreaValue(pc, 16) instruction = Instruction() instruction.setOpcode(opcode)