/* * JIT detection for ClamAV bytecode. * * Copyright (C) 2010 Sourcefire, Inc. * * Authors: Török Edvin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include "llvm/ADT/Triple.h" #include "llvm/Support/raw_ostream.h" #ifdef LLVM29 #include "llvm/Support/Host.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Memory.h" #else #include "llvm/System/Host.h" #include "llvm/System/DataTypes.h" #include "llvm/System/Memory.h" #endif #include "llvm/Config/config.h" extern "C" { #include "bytecode_detect.h" } using namespace llvm; static void warn_assumptions(const char *msg, int a, int b) { errs() << "LibClamAV Warning: libclamav and llvm make inconsistent " << "assumptions about " << msg << ": " << a << " and " << b << "." << "Please report to http://bugs.clamav.net\n"; } #define CASE_OS(theos, compat) case Triple::theos:\ env->os = llvm_os_##theos;\ if (env->os_category != compat)\ warn_assumptions("Operating System", env->os_category, Triple::theos);\ break void cli_detect_env_jit(struct cli_environment *env) { std::string host_triple = sys::getHostTriple(); INIT_STRFIELD(env->triple, host_triple.c_str()); std::string cpu = sys::getHostCPUName(); INIT_STRFIELD(env->cpu, cpu.c_str()); if (env->big_endian != (int)sys::isBigEndianHost()) { warn_assumptions("host endianness", env->big_endian, sys::isBigEndianHost()); env->big_endian = sys::isBigEndianHost(); } #ifdef __GNUC__ env->cpp_version = MAKE_VERSION(0, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); #elif defined (__INTEL_COMPILER) env->cpp_version = __INTEL_COMPILER; #elif defined (_MSC_VER) env->cpp_version = _MSC_VER; #endif Triple triple(host_triple); // CPU architecture enum Triple::ArchType arch = triple.getArch(); enum arch_list earch; bool conflicts = false; switch (arch) { case Triple::arm: earch = arch_arm; if (env->arch != earch) conflicts = true; break; case Triple::ppc: earch = arch_ppc32; if (env->arch != earch && env->arch != arch_ppc64) conflicts = true; break; case Triple::ppc64: earch = arch_ppc64; // ppc64 is fixed up by llvm if (env->arch != arch_ppc32 && env->arch != arch_ppc64) conflicts = true; break; case Triple::x86: earch = arch_i386; if (env->arch != earch) { /* bb #2153 */ if (env->arch != arch_x86_64) conflicts = true; } break; case Triple::x86_64: earch = arch_x86_64; if (env->arch != earch) { /* bb #2153, bb #2214 */ /* configure can't detect -m32, so it thinks we are x86_64, when * in fact we are i386 only. * LLVM correctly detects which one it is using preprocessor * macros, so don't warn here, startup.cbc will just have to * rely on the LLVM provided info, and not the configure * provided one! */ if (env->arch != arch_i386) conflicts = true; } break; default: earch = arch_unknown; break; } #ifndef AC_APPLE_UNIVERSAL_BUILD if (conflicts) warn_assumptions("CPU architecture", env->arch, earch); #endif if (earch != arch_unknown) env->arch = earch; // OS Triple::OSType os = triple.getOS(); switch (os) { case Triple::UnknownOS: env->os = llvm_os_UnknownOS; break; CASE_OS(AuroraUX, os_solaris); CASE_OS(Cygwin, os_win32); CASE_OS(Darwin, os_darwin); CASE_OS(DragonFly, os_bsd); CASE_OS(FreeBSD, os_bsd); CASE_OS(Linux, os_linux); CASE_OS(Lv2, os_unknown); CASE_OS(MinGW32, os_win32); #ifndef LLVM29 CASE_OS(MinGW64, os_win64); #endif CASE_OS(NetBSD, os_bsd); CASE_OS(OpenBSD, os_bsd); CASE_OS(Psp, os_unknown); CASE_OS(Solaris, os_solaris); case Triple::Win32: env->os = llvm_os_Win32; if (env->os_category != os_win32 && env->os_category != os_win64) warn_assumptions("Operating System", env->os_category, Triple::Win32); break; CASE_OS(Haiku, os_unknown); CASE_OS(Minix, os_unknown); } // mmap RWX std::string ErrMsg; sys::MemoryBlock B = sys::Memory::AllocateRWX(4096, NULL, &ErrMsg); if (B.base() == 0) { errs() << "LibClamAV Warning: RWX mapping denied: " << ErrMsg << "\n"; } else { env->os_features |= 1 << feature_map_rwx; sys::Memory::ReleaseRWX(B); } }