clamav/libclamav/c++/detect.cpp
Micah Snyder da23b1ceab CMake: Fix support for external LLVM (3.6)
Have to manually link libtinfo (`-ltinfo`) because our FindLLVM
didn't add it to the LLVM_LIBRARIES variable for us. See:
- https://stackoverflow.com/questions/21477407/llvm-3-5-fails-to-link

Have to remove the CXX_STANDARD setting at the top of CMakeLists.txt
because of c++90 / c++11 ABI compatibility issues w/ LLVM. See:
- https://maleadt.github.io/LLVM.jl/dev/man/troubleshooting/

Rename "llvm/Config/config.h" "llvm/Config/llvm-config.h" because
LLVM renamed it in 2.8.

Have to link LLVM manually with the test binaries that use the
clamav object library instead of libclamav shared library.
CMake does not propagate library dependencies from object files.

I tested on ubuntu:16.04 with LLVM 3.6 built from source using:
```
/usr/local/bin/cmake .. -D CMAKE_INSTALL_PREFIX=/opt/llvm/3.6 \
  -D LLVM_ENABLE_RTTI=ON
```
Then built clamav w/:
```
/usr/local/bin/cmake .. -D CMAKE_INSTALL_PREFIX=`pwd`/install \
  -D BYTECODE_RUNTIME="llvm" \
  -D LLVM_ROOT_DIR="/opt/llvm/3.6" \
  -D LLVM_FIND_VERSION="3.6.0" && make && make install
```
2021-05-19 14:20:59 -07:00

188 lines
5.3 KiB
C++

/*
* JIT detection for ClamAV bytecode.
*
* Copyright (C) 2013-2021 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2010-2013 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/Config/llvm-config.h"
#include "llvm/Support/raw_ostream.h"
#if LLVM_VERSION < 29
#include "llvm/System/DataTypes.h"
#include "llvm/System/Host.h"
#include "llvm/System/Memory.h"
#else
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Memory.h"
#endif
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 https://bugzilla.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)
{
#if LLVM_VERSION < 31
std::string host_triple = sys::getHostTriple();
#else
std::string host_triple = sys::getDefaultTargetTriple();
#endif
INIT_STRFIELD(env->triple, host_triple.c_str());
std::string cpu = sys::getHostCPUName();
INIT_STRFIELD(env->cpu, cpu.c_str());
#if LLVM_VERSION < 33
if (env->big_endian != (int)sys::isBigEndianHost()) {
warn_assumptions("host endianness", env->big_endian, sys::isBigEndianHost());
env->big_endian = sys::isBigEndianHost();
}
#else
if (env->big_endian != (int)sys::IsBigEndianHost) {
warn_assumptions("host endianness", env->big_endian, sys::IsBigEndianHost);
env->big_endian = sys::IsBigEndianHost;
}
#endif
#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;
#if LLVM_VERSION < 36
CASE_OS(AuroraUX, os_solaris);
CASE_OS(Cygwin, os_win32);
CASE_OS(MinGW32, os_win32);
#endif
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);
#if LLVM_VERSION < 29
CASE_OS(MinGW64, os_win64);
#endif
CASE_OS(NetBSD, os_bsd);
CASE_OS(OpenBSD, os_bsd);
#if LLVM_VERSION < 31
CASE_OS(Psp, os_unknown);
#endif
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);
}
}