packages feed

crucible-llvm-0.10: src/Lang/Crucible/LLVM/Intrinsics.hs

-- |
-- Module           : Lang.Crucible.LLVM.Intrinsics
-- Description      : Override definitions for LLVM intrinsic and basic
--                    library functions
-- Copyright        : (c) Galois, Inc 2015-2016
-- License          : BSD3
-- Maintainer       : Rob Dockins <rdockins@galois.com>
-- Stability        : provisional
------------------------------------------------------------------------

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}

module Lang.Crucible.LLVM.Intrinsics
( LLVM
, llvmIntrinsicTypes
, LLVMOverride(..)

, register_llvm_overrides
, register_specific_llvm_overrides
, register_llvm_overrides_
, llvmDeclToFunHandleRepr
, declare_overrides

, module Lang.Crucible.LLVM.Intrinsics.Common
, module Lang.Crucible.LLVM.Intrinsics.Options
, module Lang.Crucible.LLVM.Intrinsics.Match
) where

import           Control.Monad (forM)
import           Data.Maybe (catMaybes)
import           Lens.Micro ((^.))
import qualified Text.LLVM.AST as L

import qualified ABI.Itanium as ABI
import qualified Data.Parameterized.Map as MapF

import           Lang.Crucible.Backend
import           Lang.Crucible.Types
import           Lang.Crucible.Simulator.Intrinsics
import           Lang.Crucible.Simulator.OverrideSim

import           Lang.Crucible.LLVM.Extension (ArchWidth, LLVM)
import           Lang.Crucible.LLVM.MemModel
import           Lang.Crucible.LLVM.Translation.Monad
import           Lang.Crucible.LLVM.Translation.Types
import           Lang.Crucible.LLVM.TypeContext (TypeContext)

import           Lang.Crucible.LLVM.Intrinsics.Common
import qualified Lang.Crucible.LLVM.Intrinsics.Cast as Cast
import qualified Lang.Crucible.LLVM.Intrinsics.Declare as Decl
import qualified Lang.Crucible.LLVM.Intrinsics.LLVM as LLVM
import qualified Lang.Crucible.LLVM.Intrinsics.Libc as Libc
import qualified Lang.Crucible.LLVM.Intrinsics.Libcxx as Libcxx
import           Lang.Crucible.LLVM.Intrinsics.Match
import           Lang.Crucible.LLVM.Intrinsics.Options

llvmIntrinsicTypes :: IsSymInterface sym => IntrinsicTypes sym
llvmIntrinsicTypes =
   MapF.insert (knownSymbol :: SymbolRepr "LLVM_memory") IntrinsicMuxFn $
   MapF.insert (knownSymbol :: SymbolRepr "LLVM_pointer") IntrinsicMuxFn $
   MapF.empty

-- | Match two sets of 'OverrideTemplate's against the @Declare@s and @Define@s
-- in a 'L.Module', registering all the overrides that apply and returning them
-- as a list.  There are internal pre-determined overrides that will be applied,
-- as well as any additional overrides supplied by the user (internal overrides
-- will supercede user overrides).
--
-- The "define" overrides are applied to *both* the @Define@s and @Declare@s
-- elements found within a module.
--
-- The "declare" overrides are applied only to the @Declare@s found within a
-- module.  The intent is that these overrides should only apply to @Declare@s,
-- whereas the "define" overrides should apply to any matching symbol in the LLVM
-- @Module@.
--
-- If both lists specify an override that matches a declare, the declare override
-- takes precedence over the define override.
register_llvm_overrides ::
  ( IsSymInterface sym, HasLLVMAnn sym, HasPtrWidth wptr, wptr ~ ArchWidth arch
  , ?intrinsicsOpts :: IntrinsicsOptions, ?memOpts :: MemOptions ) =>
  L.Module ->
  [OverrideTemplate p sym LLVM arch] {- ^ Additional \"define\" overrides -} ->
  [OverrideTemplate p sym LLVM arch] {- ^ Additional \"declare\" overrides -} ->
  LLVMContext arch ->
  -- | Applied (@define@ overrides, @declare@ overrides)
  OverrideSim p sym LLVM rtp l a ([SomeLLVMOverride p sym LLVM], [SomeLLVMOverride p sym LLVM])
register_llvm_overrides llvmModule defineOvrs declareOvrs llvmctx =
  do defOvs <- register_llvm_define_overrides llvmModule defineOvrs llvmctx
     declOvs <- register_llvm_declare_overrides llvmModule declareOvrs llvmctx
     pure (defOvs, declOvs)


-- | Match a set of 'OverrideTemplate's against a provided set of definitions and
-- declarations, registering all the overrides that apply and returning them as a
-- pair of lists: the registered definition overrides and the registered
-- declaration overrides.
--
-- This is an alternative entrypoint for registering overrides.  The
-- functionality here is largely the same as 'register_llvm_overrides' except the
-- list of declares and defines are provided manually by the caller instead of
-- being extracted from the LLVM @Module@.
register_specific_llvm_overrides ::
  IsSymInterface sym =>
  HasLLVMAnn sym =>
  HasPtrWidth wptr =>
  wptr ~ ArchWidth arch =>
  (?intrinsicsOpts :: IntrinsicsOptions) =>
  (?memOpts :: MemOptions) =>
  [L.Define] ->
  [L.Declare] ->
  [OverrideTemplate p sym LLVM arch] {- ^ Additional \"define\" overrides -} ->
  [OverrideTemplate p sym LLVM arch] {- ^ Additional \"declare\" overrides -} ->
  LLVMContext arch ->
  OverrideSim p sym LLVM rtp l a ( [SomeLLVMOverride p sym LLVM] -- ^ def overrides
                                 , [SomeLLVMOverride p sym LLVM] -- ^ decl overrides
                                 )
register_specific_llvm_overrides defs decls addlDefOvrs addlDeclOvrs llvmctx =
  (,)
  <$> register_overrides (declareFromDefine <$> defs) addlDefOvrs llvmctx
  <*> register_overrides decls addlDeclOvrs llvmctx

-- | Filter the initial list of templates to only those that could
-- possibly match the given declaration based on straightforward,
-- relatively cheap string tests on the name of the declaration.
--
-- Any remaining templates will then examine the declaration in
-- more detail, including examining function arguments
-- and the structure of C++ demangled names to extract more information.
filterTemplates ::
  [OverrideTemplate p sym ext arch] ->
  Decl.SomeDeclare ->
  [OverrideTemplate p sym ext arch]
filterTemplates ts (Decl.SomeDeclare decl) =
  filter (matches nm . overrideTemplateMatcher) ts
  where L.Symbol nm = Decl.decName decl

-- | Match a set of 'OverrideTemplate's against a single 'L.Declare',
-- registering all the overrides that apply and returning them as a list.
match_llvm_overrides ::
  (IsSymInterface sym, HasLLVMAnn sym) =>
  LLVMContext arch ->
  -- | Overrides to attempt to match against this declaration
  [OverrideTemplate p sym ext arch] ->
  -- | Declaration of the function that might get overridden
  Decl.SomeDeclare ->
  OverrideSim p sym ext rtp l a [SomeLLVMOverride p sym ext]
match_llvm_overrides llvmctx acts someDecl =
  llvmPtrWidth llvmctx $ \wptr -> withPtrWidth wptr $ do
    let acts' = filterTemplates acts someDecl
    Decl.SomeDeclare decl <- pure someDecl
    let L.Symbol nm = Decl.decName decl
    let declnm = either (const Nothing) Just $ ABI.demangleName nm
    mbOvs <-
      forM (map overrideTemplateAction acts') $ \(MakeOverride act) ->
        case act someDecl declnm llvmctx of
          Nothing -> pure Nothing
          Just sov@(SomeLLVMOverride ov) -> do
            register_llvm_override ov decl llvmctx
            pure (Just sov)
    pure (catMaybes mbOvs)

-- | Match a set of 'OverrideTemplate's against a set of 'L.Declare's,
-- registering all the overrides that apply and returning them as a list.
register_llvm_overrides_ ::
  (IsSymInterface sym, HasLLVMAnn sym) =>
  LLVMContext arch ->
  -- | Overrides to attempt to match against these declarations
  [OverrideTemplate p sym ext arch] ->
  -- | Declarations of the functions that might get overridden
  [Decl.SomeDeclare] ->
  OverrideSim p sym ext rtp l a [SomeLLVMOverride p sym ext]
register_llvm_overrides_ llvmctx acts decls =
  concat <$> forM decls (\decl -> match_llvm_overrides llvmctx acts decl)

-- | Match a set of 'OverrideTemplate's against all the @declare@s and @define@s
-- in a 'L.Module', registering all the overrides that apply and returning them
-- as a list.  This should apply the override regardless of whether the override
-- applies to a @Define@ or a @Declare@.
--
-- Registers a default set of overrides, in addition to the ones passed as an
-- argument.
register_llvm_define_overrides ::
  (IsSymInterface sym, HasLLVMAnn sym, HasPtrWidth wptr, wptr ~ ArchWidth arch
  , ?intrinsicsOpts :: IntrinsicsOptions, ?memOpts :: MemOptions ) =>
  L.Module ->
  -- | Additional (non-default) @define@ overrides
  [OverrideTemplate p sym LLVM arch] ->
  LLVMContext arch ->
  OverrideSim p sym LLVM rtp l a [SomeLLVMOverride p sym LLVM]
register_llvm_define_overrides llvmModule addlOvrs llvmctx =
  let ?lc = llvmctx^.llvmTypeCtx
  in register_overrides (allModuleDeclares llvmModule) (addlOvrs ++ define_overrides)
     llvmctx

-- | Match a set of 'OverrideTemplate's against all the @Declare@s in a
-- 'L.Module', registering all the overrides that apply and returning them as
-- a list.
--
-- Registers a default set of overrides, in addition to the ones passed as an
-- argument.
register_llvm_declare_overrides ::
  ( IsSymInterface sym, HasLLVMAnn sym, HasPtrWidth wptr, wptr ~ ArchWidth arch
  , ?intrinsicsOpts :: IntrinsicsOptions, ?memOpts :: MemOptions ) =>
  L.Module ->
  -- | Additional (non-default) @declare@ overrides
  [OverrideTemplate p sym LLVM arch] ->
  LLVMContext arch ->
  OverrideSim p sym LLVM rtp l a [SomeLLVMOverride p sym LLVM]
register_llvm_declare_overrides llvmModule addlOvrs llvmctx =
  let ?lc = llvmctx^.llvmTypeCtx
  in register_overrides (L.modDeclares llvmModule) (addlOvrs ++ declare_overrides)
     llvmctx

register_overrides ::
  ( IsSymInterface sym, HasLLVMAnn sym, HasPtrWidth wptr, wptr ~ ArchWidth arch
  , ?intrinsicsOpts :: IntrinsicsOptions, ?memOpts :: MemOptions ) =>
  [L.Declare] ->
  -- | Additional (non-default) @declare@ overrides
  [OverrideTemplate p sym LLVM arch] ->
  LLVMContext arch ->
  OverrideSim p sym LLVM rtp l a [SomeLLVMOverride p sym LLVM]
register_overrides llvmDecls ovrs llvmctx = do
  let ?lc = llvmctx^.llvmTypeCtx
  decls <- Decl.fromLLVMWithWarnings llvmDecls
  let ovs = map Cast.lowerOverrideTemplate ovrs
  register_llvm_overrides_ llvmctx ovs decls

-- | Register overrides for declared-but-not-defined functions
declare_overrides ::
  ( IsSymInterface sym, HasLLVMAnn sym, HasPtrWidth wptr, wptr ~ ArchWidth arch
  , ?lc :: TypeContext, ?intrinsicsOpts :: IntrinsicsOptions, ?memOpts :: MemOptions ) =>
  [OverrideTemplate p sym LLVM arch]
declare_overrides =
  concat
  [ map (\(SomeLLVMOverride ov) -> basic_llvm_override ov) Libc.libc_overrides
  , map (\(SomeLLVMOverride ov) -> basic_llvm_override ov) LLVM.basic_llvm_overrides
  , map (\(pfx, LLVM.Poly1LLVMOverride ov) -> polymorphic1_llvm_override pfx ov) LLVM.poly1_llvm_overrides
  , map (\(pfx, LLVM.Poly1VecLLVMOverride ov) -> polymorphic1_vec_llvm_override pfx ov) LLVM.poly1_vec_llvm_overrides
  , map (\(pfx, LLVM.PolyCmpLLVMOverride ov) -> polymorphic_cmp_llvm_override pfx ov) LLVM.poly_cmp_llvm_overrides

  -- C++ standard library functions
  , [ Libcxx.register_cpp_override Libcxx.endlOverride ]
  ]


-- | Register those overrides that should apply even when the corresponding
-- function has a definition
define_overrides ::
  (IsSymInterface sym, HasLLVMAnn sym, HasPtrWidth wptr, wptr ~ ArchWidth arch, ?lc :: TypeContext) =>
  [OverrideTemplate p sym LLVM arch]
define_overrides =
  [ Libcxx.register_cpp_override Libcxx.putToOverride12
  , Libcxx.register_cpp_override Libcxx.putToOverride9
  , Libcxx.register_cpp_override Libcxx.endlOverride
  , Libcxx.register_cpp_override Libcxx.sentryOverride
  , Libcxx.register_cpp_override Libcxx.sentryBoolOverride
  ]

{-
Note [Overrides involving (unsigned) long]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Registering overrides for functions with `long` argument or result types is
tricky, as the size of a `long` varies wildly between different operating
systems and architectures. On Linux and macOS, `long` is 32 or 64 bits on
32- or 64-bit architectures, respectively. On Windows, however, `long` is
always 32 bits, regardless of architecture. There is a similar story for the
`unsigned long` type as well.

To ensure that overrides for functions involving `long` are (at least to some
degree) portable, we register each override for `long`-using function twice:
once where `long` is assumed to be 32 bits, and once again where `long` is
assumed to be 64 bits. This is a somewhat heavy-handed solution, but it avoids
the need to predict what size `long` will be on a given target ahead of time.
-}