Add x86 specific code.

This commit is contained in:
Joe Hendrix 2017-09-27 15:54:43 -07:00
parent 0242a88fa6
commit 4dcb26ebee
No known key found for this signature in database
GPG Key ID: 8DFA5FF784098C4F
51 changed files with 64835 additions and 0 deletions

30
LICENSE Normal file
View File

@ -0,0 +1,30 @@
Copyright (c) 2014-2017 Galois Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Galois, Inc. nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

1
x86/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.stack-work

64
x86/macaw-x86.cabal Normal file
View File

@ -0,0 +1,64 @@
name: macaw-x86
version: 0.0.1
author: Galois, Inc.
maintainer: jhendrix@galois.com
build-type: Simple
cabal-version: >= 1.9.2
library
build-depends:
base >= 4,
ansi-wl-pprint,
bytestring,
containers,
flexdis86 >= 0.1.1,
lens >= 4.7,
macaw-base,
mtl,
parameterized-utils,
text,
vector
hs-source-dirs: src
exposed-modules:
Data.Macaw.X86
Data.Macaw.X86.ArchTypes
Data.Macaw.X86.Conditions
Data.Macaw.X86.Flexdis
Data.Macaw.X86.Getters
Data.Macaw.X86.InstructionDef
Data.Macaw.X86.Monad
Data.Macaw.X86.Semantics
Data.Macaw.X86.SyscallInfo.FreeBSD
Data.Macaw.X86.SyscallInfo.Linux
Data.Macaw.X86.X86Flag
Data.Macaw.X86.X86Reg
Data.Macaw.X86.X87ControlReg
ghc-options: -Wall -Werror
ghc-options: -fno-warn-unticked-promoted-constructors
ghc-prof-options: -O2 -fprof-auto-top
test-suite macaw-x86-tests
type: exitcode-stdio-1.0
default-language: Haskell2010
ghc-options: -Wall
main-is: Main.hs
other-modules: ElfX64Linux
hs-source-dirs: tests
build-depends:
base,
bytestring,
containers,
elf-edit,
exceptions,
filemanip,
filepath,
lens,
macaw,
parameterized-utils,
macaw-x86,
temporary,
tasty,
tasty-hunit

1510
x86/src/Data/Macaw/X86.hs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,404 @@
{-
Copyright : (c) Galois, Inc 2015-2017
Maintainer : Joe Hendrix <jhendrix@galois.com>, Simon Winwood <sjw@galois.com>
This defines the X86_64 architecture type and the supporting definitions.
-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Data.Macaw.X86.ArchTypes
( -- * Architecture
X86_64
, X86PrimFn(..)
, valuesInX86Fn
, rewriteX86PrimFn
, x86PrimFnHasSideEffects
, X86Stmt(..)
, valuesInX86Stmt
, rewriteX86Stmt
, X86TermStmt(..)
, rewriteX86TermStmt
, X86PrimLoc(..)
) where
import Data.Bits
import Data.Foldable
import Data.Parameterized.NatRepr
import Data.Parameterized.Some
import Data.Parameterized.TraversableFC
import Data.Set (Set)
import qualified Data.Set as Set
import qualified Flexdis86 as F
import Text.PrettyPrint.ANSI.Leijen as PP hiding ((<$>))
import Data.Macaw.CFG
import Data.Macaw.CFG.Rewriter
import Data.Macaw.Types
import Data.Macaw.X86.Monad (SIMDWidth(..), RepValSize(..), repValSizeMemRepr)
import Data.Macaw.X86.X86Reg
import Data.Macaw.X86.X87ControlReg
assignIdSetFromValues :: [Some (Value arch ids)] -> Set (Some (AssignId ids))
assignIdSetFromValues = foldl' f Set.empty
where f s (Some v) = Set.union s (refsInValue v)
------------------------------------------------------------------------
-- X86TermStmt
data X86TermStmt ids = X86Syscall
instance PrettyF X86TermStmt where
prettyF X86Syscall = text "x86_syscall"
rewriteX86TermStmt :: X86TermStmt src -> Rewriter X86_64 src tgt (X86TermStmt tgt)
rewriteX86TermStmt f =
case f of
X86Syscall -> pure X86Syscall
------------------------------------------------------------------------
-- X86_64 specific declarations
data X86_64
type instance ArchReg X86_64 = X86Reg
type instance ArchFn X86_64 = X86PrimFn
type instance ArchStmt X86_64 = X86Stmt
type instance ArchTermStmt X86_64 = X86TermStmt
------------------------------------------------------------------------
-- X86PrimLoc
-- | This describes a primitive location that can be read or written to in the
-- X86 architecture model.
-- Primitive locations are not modeled as registers, but rather as implicit state.
data X86PrimLoc tp
= (tp ~ BVType 64) => ControlLoc !F.ControlReg
| (tp ~ BVType 64) => DebugLoc !F.DebugReg
| (tp ~ BVType 16) => FS
-- ^ This refers to the selector of the 'FS' register.
| (tp ~ BVType 16) => GS
-- ^ This refers to the se lector of the 'GS' register.
| forall w . (tp ~ BVType w) => X87_ControlLoc !(X87_ControlReg w)
-- ^ One of the x87 control registers
instance HasRepr X86PrimLoc TypeRepr where
typeRepr ControlLoc{} = knownType
typeRepr DebugLoc{} = knownType
typeRepr FS = knownType
typeRepr GS = knownType
typeRepr (X87_ControlLoc r) =
case x87ControlRegWidthIsPos r of
LeqProof -> BVTypeRepr (typeRepr r)
instance Pretty (X86PrimLoc tp) where
pretty (ControlLoc r) = text (show r)
pretty (DebugLoc r) = text (show r)
pretty FS = text "fs"
pretty GS = text "gs"
pretty (X87_ControlLoc r) = text (show r)
------------------------------------------------------------------------
-- X86PrimFn
-- | Defines primitive functions in the X86 format.
data X86PrimFn f tp
= ReadLoc !(X86PrimLoc tp)
-- ^ Read from a primitive X86 location
| (tp ~ BVType 64) => ReadFSBase
-- ^ Read the 'FS' base address
| (tp ~ BVType 64) => ReadGSBase
-- ^ Read the 'GS' base address
| (tp ~ BVType 128) => CPUID (f (BVType 32))
-- ^ The CPUID instruction
--
-- Given value in eax register, this returns the concatenation of eax:ebx:ecx:edx.
| (tp ~ BVType 64) => RDTSC
-- ^ The RDTSC instruction
--
-- This returns the current time stamp counter a 64-bit value that will
-- be stored in edx:eax
| (tp ~ BVType 64) => XGetBV (f (BVType 32))
-- ^ The XGetBV instruction primitive
--
-- This returns the extended control register defined in the given value
-- as a 64-bit value that will be stored in edx:eax
| forall w
. (tp ~ BVType w, 1 <= w)
=> PShufb !(SIMDWidth w) !(f (BVType w)) !(f (BVType w))
-- ^ @PShufb w x s@ returns a value @res@ generated from the bytes of @x@
-- based on indices defined in the corresponding bytes of @s@.
--
-- Let @n@ be the number of bytes in the width @w@, and let @l = log2(n)@.
-- Given a byte index @i@, the value of byte @res[i]@, is defined by
-- @res[i] = 0 if msb(s[i]) == 1@
-- @res[i] = x[j] where j = s[i](0..l)
-- where @msb(y)@ returns the most-significant bit in byte @y@.
| (tp ~ BVType 64)
=> MemCmp !Integer
-- /\ Number of bytes per value.
!(f (BVType 64))
-- /\ Number of values to compare
!(f (BVType 64))
-- /\ Pointer to first buffer.
!(f (BVType 64))
-- /\ Pointer to second buffer.
!(f BoolType)
-- /\ Direction flag, False means increasing
-- ^ Compares to memory regions
| forall n
. (tp ~ BVType 64)
=> RepnzScas !(RepValSize n)
!(f (BVType n))
!(f (BVType 64))
!(f (BVType 64))
-- ^ `RepnzScas sz val base cnt` searchs through a buffer starting at
-- `base` to find an element `i` such that base[i] = val.
-- Each step it increments `i` by 1 and decrements `cnt` by `1`. It returns
-- the final value of `cnt`.
| (tp ~ BVType 80)
=> MMXExtend !(f (BVType 64))
-- ^ This returns a 80-bit value where the high 16-bits are all
-- 1s, and the low 64-bits are the given register.
| forall w
. (tp ~ BVType w)
=> X86IDiv !(RepValSize w)
!(f (BVType (w+w)))
!(f (BVType w))
-- ^ This performs a signed quotient for idiv.
-- The dividend is rounded to zero.
-- It raises a #DE exception if the divisor is 0 or the result overflows.
| forall w
. (tp ~ BVType w)
=> X86IRem !(RepValSize w)
!(f (BVType (w+w)))
!(f (BVType w))
-- ^ This performs a signed remainder for idiv.
-- The dividend is rounded to zero.
-- It raises a #DE exception if the divisor is 0 or the result overflows.
instance HasRepr (X86PrimFn f) TypeRepr where
typeRepr f =
case f of
ReadLoc loc -> typeRepr loc
ReadFSBase -> knownType
ReadGSBase -> knownType
CPUID{} -> knownType
RDTSC{} -> knownType
XGetBV{} -> knownType
PShufb w _ _ -> BVTypeRepr (typeRepr w)
MemCmp{} -> knownType
RepnzScas{} -> knownType
MMXExtend{} -> knownType
X86IDiv w _ _ -> typeRepr (repValSizeMemRepr w)
X86IRem w _ _ -> typeRepr (repValSizeMemRepr w)
-- | An operation for pretty printing a 'X86PrimFn' using a pretty printer
-- for values that is implemented as a 'Applicative' action to allow side
-- effects.
ppX86PrimFn :: Applicative m
=> (forall u . f u -> m Doc)
-- ^ Function for pretty printing vlaue.
-> X86PrimFn f tp
-> m Doc
ppX86PrimFn pp f =
case f of
ReadLoc loc -> pure $ pretty loc
ReadFSBase -> pure $ text "fs.base"
ReadGSBase -> pure $ text "gs.base"
CPUID code -> sexprA "cpuid" [ pp code ]
RDTSC -> pure $ text "rdtsc"
XGetBV code -> sexprA "xgetbv" [ pp code ]
PShufb _ x s -> sexprA "pshufb" [ pp x, pp s ]
MemCmp sz cnt src dest rev -> sexprA "memcmp" args
where args = [pure (pretty sz), pp cnt, pp dest, pp src, pp rev]
RepnzScas _ val buf cnt -> sexprA "first_byte_offset" args
where args = [pp val, pp buf, pp cnt]
MMXExtend e -> sexprA "mmx_extend" [ pp e ]
X86IDiv w n d -> sexprA "idiv" [ pure (text $ show $ typeWidth $ repValSizeMemRepr w), pp n, pp d ]
X86IRem w n d -> sexprA "irem" [ pure (text $ show $ typeWidth $ repValSizeMemRepr w), pp n, pp d ]
rewriteX86PrimFn :: X86PrimFn (Value X86_64 src) tp
-> Rewriter X86_64 src tgt (Value X86_64 tgt tp)
rewriteX86PrimFn f =
case f of
ReadLoc loc -> evalRewrittenArchFn $ ReadLoc loc
ReadFSBase -> evalRewrittenArchFn ReadFSBase
ReadGSBase -> evalRewrittenArchFn ReadGSBase
CPUID code -> do
tgtFn <- CPUID <$> rewriteValue code
evalRewrittenArchFn tgtFn
RDTSC -> evalRewrittenArchFn RDTSC
XGetBV code -> do
tgtFn <- XGetBV <$> rewriteValue code
evalRewrittenArchFn tgtFn
PShufb w x s -> do
tgtFn <- PShufb w <$> rewriteValue x
<*> rewriteValue s
evalRewrittenArchFn tgtFn
MemCmp sz cnt src dest rev -> do
tgtFn <- MemCmp sz <$> rewriteValue cnt
<*> rewriteValue src
<*> rewriteValue dest
<*> rewriteValue rev
evalRewrittenArchFn tgtFn
RepnzScas sz val buf cnt -> do
tgtFn <- RepnzScas sz <$> rewriteValue val
<*> rewriteValue buf
<*> rewriteValue cnt
evalRewrittenArchFn tgtFn
MMXExtend e -> do
tgtExpr <- rewriteValue e
case tgtExpr of
BVValue _ i -> do
pure $ BVValue (knownNat :: NatRepr 80) $ 0xffff `shiftL` 64 .|. i
_ ->
evalRewrittenArchFn (MMXExtend tgtExpr)
X86IDiv w n d -> do
tgtFn <- X86IDiv w <$> rewriteValue n
<*> rewriteValue d
evalRewrittenArchFn tgtFn
X86IRem w n d -> do
tgtFn <- X86IRem w <$> rewriteValue n
<*> rewriteValue d
evalRewrittenArchFn tgtFn
-- | This returns true if evaluating the primitive function implicitly
-- changes the processor state in some way.
x86PrimFnHasSideEffects :: X86PrimFn f tp -> Bool
x86PrimFnHasSideEffects f =
case f of
ReadLoc{} -> False
ReadFSBase -> False
ReadGSBase -> False
CPUID{} -> False
RDTSC -> False
XGetBV{} -> False
PShufb{} -> False
MemCmp{} -> False
RepnzScas{} -> True
MMXExtend{} -> False
X86IDiv{} -> True -- To be conservative we treat the floating point exceptions as side effects.
X86IRem{} -> True -- To be conservative we treat the floating point exceptions as side effects.
instance FunctorFC X86PrimFn where
fmapFC = fmapFCDefault
instance FoldableFC X86PrimFn where
foldMapFC = foldMapFCDefault
instance TraversableFC X86PrimFn where
traverseFC go f =
case f of
ReadLoc l -> pure (ReadLoc l)
ReadFSBase -> pure ReadFSBase
ReadGSBase -> pure ReadGSBase
CPUID v -> CPUID <$> go v
RDTSC -> pure RDTSC
XGetBV v -> XGetBV <$> go v
PShufb w x y -> PShufb w <$> go x <*> go y
MemCmp sz cnt src dest rev ->
MemCmp sz <$> go cnt <*> go src <*> go dest <*> go rev
RepnzScas sz val buf cnt ->
RepnzScas sz <$> go val <*> go buf <*> go cnt
MMXExtend v -> MMXExtend <$> go v
X86IDiv w n d -> X86IDiv w <$> go n <*> go d
X86IRem w n d -> X86IRem w <$> go n <*> go d
instance IsArchFn X86PrimFn where
ppArchFn = ppX86PrimFn
valuesInX86Fn :: X86PrimFn v tp -> [Some v]
valuesInX86Fn = foldMapFC (\v -> [Some v])
------------------------------------------------------------------------
-- X86Stmt
-- | An X86 specific statement.
data X86Stmt ids
= forall tp .
WriteLoc !(X86PrimLoc tp) !(Value X86_64 ids tp)
| StoreX87Control !(BVValue X86_64 ids 64)
-- ^ Store the X87 control register in the given location.
| MemCopy !Integer
!(Value X86_64 ids (BVType 64))
!(Value X86_64 ids (BVType 64))
!(Value X86_64 ids (BVType 64))
!(Value X86_64 ids BoolType)
-- ^ Copy a region of memory from a source buffer to a destination buffer.
--
-- In an expression @MemCopy bc v src dest dir@
-- * @bc@ is the number of bytes to copy at a time (1,2,4,8)
-- * @v@ is the number of values to move.
-- * @src@ is the start of source buffer.
-- * @dest@ is the start of destination buffer.
-- * @dir@ is a flag that indicates whether direction of move:
-- * 'True' means we should decrement buffer pointers after each copy.
-- * 'False' means we should increment the buffer pointers after each copy.
| forall n .
MemSet !(Value X86_64 ids (BVType 64))
-- /\ Number of values to assign
!(Value X86_64 ids (BVType n))
-- /\ Value to assign
!(Value X86_64 ids (BVType 64))
-- /\ Address to start assigning from.
!(Value X86_64 ids BoolType)
-- /\ Direction flag
instance PrettyF X86Stmt where
prettyF (WriteLoc loc rhs) = pretty loc <+> text ":=" <+> ppValue 0 rhs
prettyF (StoreX87Control addr) = pretty addr <+> text ":= x87_control"
prettyF (MemCopy sz cnt src dest rev) =
text "memcopy" <+> parens (hcat $ punctuate comma args)
where args = [pretty sz, pretty cnt, pretty src, pretty dest, pretty rev]
prettyF (MemSet cnt val dest d) =
text "memset" <+> parens (hcat $ punctuate comma args)
where args = [pretty cnt, pretty val, pretty dest, pretty d]
rewriteX86Stmt :: X86Stmt src -> Rewriter X86_64 src tgt ()
rewriteX86Stmt f =
case f of
WriteLoc loc rhs -> do
tgtStmt <-
WriteLoc loc
<$> rewriteValue rhs
appendRewrittenArchStmt tgtStmt
StoreX87Control addr -> do
tgtStmt <-
StoreX87Control
<$> rewriteValue addr
appendRewrittenArchStmt tgtStmt
MemCopy bc cnt src dest dir -> do
tgtStmt <-
MemCopy bc
<$> rewriteValue cnt
<*> rewriteValue src
<*> rewriteValue dest
<*> rewriteValue dir
appendRewrittenArchStmt tgtStmt
MemSet cnt val dest dir -> do
tgtStmt <-
MemSet
<$> rewriteValue cnt
<*> rewriteValue val
<*> rewriteValue dest
<*> rewriteValue dir
appendRewrittenArchStmt tgtStmt
valuesInX86Stmt :: X86Stmt ids -> [Some (Value X86_64 ids)]
valuesInX86Stmt (WriteLoc _ rhs) = [Some rhs]
valuesInX86Stmt (StoreX87Control addr) = [Some addr]
valuesInX86Stmt (MemCopy _ cnt src dest d) = [ Some cnt, Some src, Some dest, Some d ]
valuesInX86Stmt (MemSet cnt val dest d) = [ Some cnt, Some val, Some dest, Some d ]
refsInX86Stmt :: X86Stmt ids -> Set (Some (AssignId ids))
refsInX86Stmt = assignIdSetFromValues . valuesInX86Stmt
instance StmtHasRefs X86Stmt where
refsInStmt = refsInX86Stmt

View File

@ -0,0 +1,64 @@
{-|
Copyright : (c) Galois, Inc 2015-2017
Maintainer : Joe Hendrix <jhendrix@galois.com>
This defines the semantics of the different condition code.
-}
{-# LANGUAGE RankNTypes #-}
module Data.Macaw.X86.Conditions
( ConditionalDef(..)
, conditionalDefs
) where
import Data.Macaw.Types (BoolType)
import Data.Macaw.X86.Monad
-- Constants for defining semantics of different condition flags.
cond_a, cond_ae, cond_b, cond_be, cond_g, cond_ge, cond_l, cond_le, cond_o, cond_p, cond_s, cond_z,
cond_no, cond_np, cond_ns, cond_nz :: Semantics m => m (Value m BoolType)
cond_a = (\c z -> boolAnd (boolNot c) (boolNot z)) <$> get cf_loc <*> get zf_loc
cond_ae = boolNot <$> get cf_loc
cond_b = get cf_loc
cond_be = boolOr <$> get cf_loc <*> get zf_loc
cond_g = (\z s o -> boolAnd (boolNot z) (boolEq s o)) <$> get zf_loc <*> get sf_loc <*> get of_loc
cond_le = (\z s o -> boolOr z (boolXor s o)) <$> get zf_loc <*> get sf_loc <*> get of_loc
cond_ge = (\s o -> boolEq s o) <$> get sf_loc <*> get of_loc
cond_l = (\s o -> boolXor s o) <$> get sf_loc <*> get of_loc
cond_o = get of_loc
cond_p = get pf_loc
cond_s = get sf_loc
cond_z = get zf_loc
cond_no = boolNot <$> cond_o
cond_np = boolNot <$> cond_p
cond_ns = boolNot <$> cond_s
cond_nz = boolNot <$> cond_z
newtype ConditionalDef = ConditionalDef (forall m . Semantics m => m (Value m BoolType))
-- conditional instruction support (cmovcc, jcc)
conditionalDefs :: [(String, ConditionalDef)]
conditionalDefs = [ mk "a" cond_a
, mk "ae" cond_ae
, mk "b" cond_b
, mk "be" cond_be
, mk "g" cond_g
, mk "ge" cond_ge
, mk "l" cond_l
, mk "le" cond_le
, mk "o" cond_o
, mk "p" cond_p
, mk "s" cond_s
, mk "z" cond_z
, mk "e" cond_z
, mk "ne" cond_nz
, mk "no" cond_no
, mk "np" cond_np
, mk "ns" cond_ns
, mk "nz" cond_nz
]
where mk :: String
-> (forall m . Semantics m => m (Value m BoolType))
-> (String, ConditionalDef)
mk k v = (k, ConditionalDef v)

View File

@ -0,0 +1,143 @@
{-
Copyright : (c) Galois, Inc 2017
Maintainer : Joe Hendrix <jhendrix@galois.com>
This provides a facility for disassembling x86 instructions from a
Macaw memory objec.t
-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Macaw.X86.Flexdis
( MemoryByteReader
, runMemoryByteReader
, readInstruction
) where
import Control.Monad.Except
import Control.Monad.State.Strict
import qualified Data.ByteString as BS
import Data.Word
import Data.Macaw.Memory
import qualified Data.Macaw.Memory.Permissions as Perm
import qualified Flexdis86 as Flexdis
import Flexdis86.ByteReader
------------------------------------------------------------------------
-- MemStream
data PrevData w = PrevData { prevBytes :: [Word8]
, prevRanges :: [SegmentRange w]
}
emptyPrevData :: PrevData w
emptyPrevData = PrevData { prevBytes = [], prevRanges = [] }
consByte :: Word8 -> PrevData w -> PrevData w
consByte w pd = pd { prevBytes = w:prevBytes pd
}
prevSegments :: PrevData w -> [SegmentRange w]
prevSegments pd | null (prevBytes pd) = reverse (prevRanges pd)
| otherwise = reverse (prevRanges pd) ++ [ByteRegion (BS.pack (prevBytes pd))]
-- | A stream of memory
data MemStream w = MS { msSegment :: !(MemSegment w)
-- ^ The current segment
, msStart :: !(MemWord w)
-- ^ The initial offset for the stream.
, msPrev :: !(PrevData w)
-- ^ The values read so far.
, msOffset :: !(MemWord w)
-- ^ The current address
, msNext :: ![SegmentRange w]
-- ^ The next bytes to read.
}
msStartAddr :: MemWidth w => MemStream w -> MemAddr w
msStartAddr ms = relativeSegmentAddr segOff
where Just segOff = resolveSegmentOff (msSegment ms) (msStart ms)
msAddr :: MemWidth w => MemStream w -> MemAddr w
msAddr ms = relativeSegmentAddr segOff
where Just segOff = resolveSegmentOff (msSegment ms) (msOffset ms)
------------------------------------------------------------------------
-- MemoryByteReader
newtype MemoryByteReader w a = MBR { unMBR :: ExceptT (MemoryError w) (State (MemStream w)) a }
deriving (Functor, Applicative, MonadError (MemoryError w))
instance MemWidth w => Monad (MemoryByteReader w) where
return = MBR . return
MBR m >>= f = MBR $ m >>= unMBR . f
fail msg = do
addr <- MBR $ gets msAddr
throwError $ UserMemoryError addr msg
-- | Create a memory stream pointing to given address, and return pair whose
-- first element is the value read or an error, and whose second element is
-- the address of the next value to read.
runMemoryByteReader :: Memory w
-> Perm.Flags
-- ^ Permissions that memory accesses are expected to
-- satisfy.
-- Added so we can check for read and/or execute permission.
-> MemSegmentOff w -- ^ Starting segment
-> MemoryByteReader w a -- ^ Byte reader to read values from.
-> Either (MemoryError w) (a, MemWord w)
runMemoryByteReader mem reqPerm addr (MBR m) = do
addrWidthClass (memAddrWidth mem) $ do
let seg = msegSegment addr
if not (segmentFlags seg `Perm.hasPerm` reqPerm) then
Left $ PermissionsError (relativeSegmentAddr addr)
else do
contents <- addrContentsAfter mem (relativeSegmentAddr addr)
let ms0 = MS { msSegment = seg
, msStart = msegOffset addr
, msPrev = emptyPrevData
, msOffset = msegOffset addr
, msNext = contents
}
case runState (runExceptT m) ms0 of
(Left e, _) -> Left e
(Right v, ms) -> Right (v, msOffset ms)
instance MemWidth w => ByteReader (MemoryByteReader w) where
readByte = do
ms <- MBR get
-- If remaining bytes are empty
case msNext ms of
[] ->
MBR $ throwError $ AccessViolation (msAddr ms)
-- Throw error if we try to read a relocation as a symbolic reference
SymbolicRef{}:_ -> do
MBR $ throwError $ UnexpectedRelocation (msAddr ms)
ByteRegion bs:rest -> do
if BS.null bs then do
throwError $ AccessViolation (msAddr ms)
else do
let v = BS.head bs
let ms' = ms { msPrev = consByte v (msPrev ms)
, msOffset = msOffset ms + 1
, msNext = ByteRegion (BS.tail bs) : rest
}
MBR $ v <$ put ms'
invalidInstruction = do
ms <- MBR $ get
throwError $ InvalidInstruction (msStartAddr ms) (prevSegments (msPrev ms))
------------------------------------------------------------------------
-- readInstruction
-- | Read instruction at a given memory address.
readInstruction :: Memory 64
-> MemSegmentOff 64
-- ^ Address to read from.
-> Either (MemoryError 64)
(Flexdis.InstructionInstance, MemWord 64)
readInstruction mem addr = runMemoryByteReader mem Perm.execute addr m
where m = Flexdis.disassembleInstruction

View File

@ -0,0 +1,357 @@
{-|
Copyright : (c) Galois, Inc 2015-2017
Maintainer : Joe Hendrix <jhendrix@galois.com>
This defines operations for mapping flexdis values to Macaw values.
-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Data.Macaw.X86.Getters
( SomeBV(..)
, getBVAddress
, readBVAddress
, getSomeBVLocation
, getBVLocation
, getSomeBVValue
, getBVValue
, getSignExtendedValue
, truncateBVValue
, getJumpTarget
, FPLocation(..)
, getFPLocation
, FPValue(..)
, getFPValue
, HasRepSize(..)
, getAddrRegOrSegment
, getAddrRegSegmentOrImm
, readXMMValue
-- * Reprs
, byteMemRepr
, wordMemRepr
, dwordMemRepr
, qwordMemRepr
, xmmMemRepr
, floatMemRepr
, doubleMemRepr
) where
import Data.Parameterized.NatRepr
import Data.Parameterized.Some
import qualified Flexdis86 as F
import GHC.TypeLits (KnownNat)
import Data.Macaw.CFG (MemRepr(..))
import Data.Macaw.Memory (Endianness(..))
import Data.Macaw.Types (FloatType, BVType, n8, n16, n32, n64, typeWidth)
import Data.Macaw.X86.Monad
import Data.Macaw.X86.X86Reg (X86Reg(..))
byteMemRepr :: MemRepr (BVType 8)
byteMemRepr = BVMemRepr (knownNat :: NatRepr 1) LittleEndian
wordMemRepr :: MemRepr (BVType 16)
wordMemRepr = BVMemRepr (knownNat :: NatRepr 2) LittleEndian
dwordMemRepr :: MemRepr (BVType 32)
dwordMemRepr = BVMemRepr (knownNat :: NatRepr 4) LittleEndian
qwordMemRepr :: MemRepr (BVType 64)
qwordMemRepr = BVMemRepr (knownNat :: NatRepr 8) LittleEndian
floatMemRepr :: MemRepr (BVType 32)
floatMemRepr = BVMemRepr (knownNat :: NatRepr 4) LittleEndian
doubleMemRepr :: MemRepr (BVType 64)
doubleMemRepr = BVMemRepr (knownNat :: NatRepr 8) LittleEndian
x87MemRepr :: MemRepr (BVType 80)
x87MemRepr = BVMemRepr (knownNat :: NatRepr 10) LittleEndian
xmmMemRepr :: MemRepr (BVType 128)
xmmMemRepr = BVMemRepr (knownNat :: NatRepr 16) LittleEndian
------------------------------------------------------------------------
-- Getters
-- | Calculates the address corresponding to an AddrRef
getBVAddress :: forall m. Semantics m => F.AddrRef -> m (Value m (BVType 64))
getBVAddress ar =
case ar of
-- FIXME: It seems that there is no sign extension here ...
F.Addr_32 seg m_r32 m_int_r32 i32 -> do
base <- case m_r32 of
Nothing -> return $! bvKLit 0
Just r -> get (reg_low32 (X86_GP $ F.reg32_reg r))
scale <- case m_int_r32 of
Nothing -> return $! bvKLit 0
Just (i, r) -> bvTrunc n32 . bvMul (bvLit n32 (toInteger i))
<$> get (reg_low32 (X86_GP $ F.reg32_reg r))
let offset = uext n64 (base `bvAdd` scale `bvAdd` bvLit n32 (toInteger (F.displacementInt i32)))
mk_absolute seg offset
F.IP_Offset_32 _seg _i32 -> fail "IP_Offset_32"
F.Offset_32 _seg _w32 -> fail "Offset_32"
F.Offset_64 seg w64 -> do
mk_absolute seg (bvLit n64 (toInteger w64))
F.Addr_64 seg m_r64 m_int_r64 i32 -> do
base <- case m_r64 of
Nothing -> return v0_64
Just r -> get (fullRegister $ X86_GP r)
scale <- case m_int_r64 of
Nothing -> return v0_64
Just (i, r) -> bvTrunc n64 . bvMul (bvLit n64 (toInteger i))
<$> get (fullRegister $ X86_GP r)
let offset = base `bvAdd` scale `bvAdd` bvLit n64 (toInteger i32)
mk_absolute seg offset
F.IP_Offset_64 seg i32 -> do
ip_val <- get rip
mk_absolute seg (bvAdd (bvLit n64 (toInteger i32)) ip_val)
where
v0_64 = bvLit n64 0
-- | Add the segment base to compute an absolute address.
mk_absolute :: F.Segment -> Value m (BVType 64) -> m (Value m (BVType 64))
mk_absolute seg offset
-- In 64-bit mode the CS, DS, ES, and SS segment registers
-- are forced to zero, and so segmentation is a nop.
--
-- We could nevertheless call 'getSegmentBase' in all cases
-- here, but that adds a lot of noise to the AST in the common
-- case of segments other than FS or GS.
| seg == F.CS || seg == F.DS || seg == F.ES || seg == F.SS = return offset
-- The FS and GS segments can be non-zero based in 64-bit mode.
| otherwise = do
base <- getSegmentBase seg
return $ base `bvAdd` offset
readBVAddress :: Semantics m => F.AddrRef -> MemRepr tp -> m (Value m tp)
readBVAddress ar repr =
get . (`MemoryAddr` repr) =<< getBVAddress ar
-- | A bitvector value with a width that satisfies `SupportedBVWidth`.
data SomeBV v where
SomeBV :: SupportedBVWidth n => v (BVType n) -> SomeBV v
-- | Extract the location of a bitvector value.
getSomeBVLocation :: Semantics m => F.Value -> m (SomeBV (MLocation m))
getSomeBVLocation v =
case v of
F.ControlReg cr -> pure $ SomeBV $ ControlReg cr
F.DebugReg dr -> pure $ SomeBV $ DebugReg dr
F.MMXReg mmx -> pure $ SomeBV $ x87reg_mmx $ X87_FPUReg mmx
F.XMMReg xmm -> pure $ SomeBV $ fullRegister $ X86_XMMReg xmm
F.SegmentValue s -> pure $ SomeBV $ SegmentReg s
F.X87Register i -> mk (X87StackRegister i)
F.FarPointer _ -> fail "FarPointer"
-- SomeBV . (`MemoryAddr` byteMemRepr) <$> getBVAddress ar -- FIXME: what size here?
F.VoidMem _ -> fail "VoidMem"
F.Mem8 ar -> SomeBV . (`MemoryAddr` byteMemRepr) <$> getBVAddress ar
F.Mem16 ar -> SomeBV . (`MemoryAddr` wordMemRepr) <$> getBVAddress ar
F.Mem32 ar -> SomeBV . (`MemoryAddr` dwordMemRepr) <$> getBVAddress ar
F.Mem64 ar -> SomeBV . (`MemoryAddr` qwordMemRepr) <$> getBVAddress ar
F.Mem128 ar -> SomeBV . (`MemoryAddr` xmmMemRepr) <$> getBVAddress ar
F.FPMem32 ar -> getBVAddress ar >>= mk . (`MemoryAddr` floatMemRepr)
F.FPMem64 ar -> getBVAddress ar >>= mk . (`MemoryAddr` doubleMemRepr)
F.FPMem80 ar -> getBVAddress ar >>= mk . (`MemoryAddr` x87MemRepr)
F.ByteReg r
| Just r64 <- F.is_low_reg r -> mk (reg_low8 $ X86_GP r64)
| Just r64 <- F.is_high_reg r -> mk (reg_high8 $ X86_GP r64)
| otherwise -> fail "unknown r8"
F.WordReg r -> mk (reg_low16 (X86_GP $ F.reg16_reg r))
F.DWordReg r -> mk (reg_low32 (X86_GP $ F.reg32_reg r))
F.QWordReg r -> mk (fullRegister $ X86_GP r)
F.ByteImm _ -> noImm
F.WordImm _ -> noImm
F.DWordImm _ -> noImm
F.QWordImm _ -> noImm
F.JumpOffset{} -> fail "Jump Offset is not a location."
where
noImm :: Monad m => m a
noImm = fail "Immediate is not a location"
mk :: (Applicative m, SupportedBVWidth n) => f (BVType n) -> m (SomeBV f)
mk = pure . SomeBV
-- | Translate a flexdis value to a location with a particular width.
getBVLocation :: Semantics m => F.Value -> NatRepr n -> m (MLocation m (BVType n))
getBVLocation l expected = do
SomeBV v <- getSomeBVLocation l
case testEquality (typeWidth v) expected of
Just Refl ->
return v
Nothing ->
fail $ "Widths aren't equal: " ++ show (typeWidth v) ++ " and " ++ show expected
-- | Return a bitvector value.
getSomeBVValue :: Semantics m => F.Value -> m (SomeBV (Value m))
getSomeBVValue v =
case v of
F.ByteImm w -> return $ SomeBV $ bvLit n8 $ toInteger w
F.WordImm w -> return $ SomeBV $ bvLit n16 $ toInteger w
F.DWordImm w -> return $ SomeBV $ bvLit n32 $ toInteger w
F.QWordImm w -> return $ SomeBV $ bvLit n64 $ toInteger w
F.JumpOffset _ off -> return $ SomeBV $ bvLit n64 $ toInteger off
_ -> do
SomeBV l <- getSomeBVLocation v
SomeBV <$> get l
-- | Translate a flexdis value to a value with a particular width.
getBVValue :: Semantics m
=> F.Value
-> NatRepr n
-> m (Value m (BVType n))
getBVValue val expected = do
SomeBV v <- getSomeBVValue val
case testEquality (bv_width v) expected of
Just Refl -> return v
Nothing ->
fail $ "Widths aren't equal: " ++ show (bv_width v) ++ " and " ++ show expected
-- | Get a value with the given width, sign extending as necessary.
getSignExtendedValue :: forall m w
. (Semantics m, 1 <= w)
=> F.Value
-> NatRepr w
-> m (Value m (BVType w))
getSignExtendedValue v out_w =
case v of
-- If an instruction can take a VoidMem, it needs to get it explicitly
F.VoidMem _ar -> fail "VoidMem"
F.Mem8 ar -> mk . (`MemoryAddr` byteMemRepr) =<< getBVAddress ar
F.Mem16 ar -> mk . (`MemoryAddr` wordMemRepr) =<< getBVAddress ar
F.Mem32 ar -> mk . (`MemoryAddr` dwordMemRepr) =<< getBVAddress ar
F.Mem64 ar -> mk . (`MemoryAddr` qwordMemRepr) =<< getBVAddress ar
F.Mem128 ar -> mk . (`MemoryAddr` xmmMemRepr) =<< getBVAddress ar
F.ByteReg r
| Just r64 <- F.is_low_reg r -> mk (reg_low8 $ X86_GP r64)
| Just r64 <- F.is_high_reg r -> mk (reg_high8 $ X86_GP r64)
| otherwise -> fail "unknown r8"
F.WordReg r -> mk (reg_low16 (X86_GP $ F.reg16_reg r))
F.DWordReg r -> mk (reg_low32 (X86_GP $ F.reg32_reg r))
F.QWordReg r -> mk (fullRegister $ X86_GP r)
F.XMMReg r -> mk (fullRegister $ X86_XMMReg r)
F.ByteImm i -> return $! bvLit out_w (toInteger i)
F.WordImm i -> return $! bvLit out_w (toInteger i)
F.DWordImm i -> return $! bvLit out_w (toInteger i)
F.QWordImm i -> return $! bvLit out_w (toInteger i)
_ -> fail $ "getSignExtendedValue given unexpected width: " ++ show v
where
-- FIXME: what happens with signs etc?
mk :: forall u
. (1 <= u, KnownNat u)
=> Location (Value m (BVType 64)) (BVType u)
-> m (Value m (BVType w))
mk l
| Just LeqProof <- testLeq (knownNat :: NatRepr u) out_w =
sext out_w <$> get l
| otherwise =
fail $ "getSignExtendedValue given bad value."
truncateBVValue :: (Monad m, IsValue v, 1 <= n)
=> NatRepr n
-> SomeBV v
-> m (v (BVType n))
truncateBVValue n (SomeBV v)
| Just LeqProof <- testLeq n (bv_width v) = do
return (bvTrunc n v)
| otherwise =
fail $ "Widths isn't >=: " ++ show (bv_width v) ++ " and " ++ show n
-- | Return the target of a call or jump instruction.
getJumpTarget :: Semantics m
=> F.Value
-> m (Value m (BVType 64))
getJumpTarget v =
case v of
F.Mem64 ar -> do
a <- getBVAddress ar
get (MemoryAddr a qwordMemRepr)
F.QWordReg r -> get (fullRegister $ X86_GP r)
F.JumpOffset _ off -> bvAdd (bvLit n64 (toInteger off)) <$> get rip
_ -> fail "Unexpected argument"
------------------------------------------------------------------------
-- Floating point
-- | This describes a floating point value including the type.
data FPLocation m flt = FPLocation (FloatInfoRepr flt) (MLocation m (FloatType flt))
-- | This describes a floating point value including the type.
data FPValue m flt = FPValue (FloatInfoRepr flt) (Value m (FloatType flt))
readFPLocation :: Semantics m => FPLocation m flt -> m (FPValue m flt)
readFPLocation (FPLocation repr l) = FPValue repr <$> get l
-- | Read an address as a floating point vlaue
getFPAddrLoc :: Semantics m => FloatInfoRepr flt -> F.AddrRef -> m (FPLocation m flt)
getFPAddrLoc repr f_addr = do
addr <- getBVAddress f_addr
pure $ FPLocation repr (mkFPAddr repr addr)
-- | Get a floating point value from the argument.
getFPLocation :: Semantics m => F.Value -> m (Some (FPLocation m))
getFPLocation v =
case v of
F.FPMem32 ar -> Some <$> getFPAddrLoc SingleFloatRepr ar
F.FPMem64 ar -> Some <$> getFPAddrLoc DoubleFloatRepr ar
F.FPMem80 ar -> Some <$> getFPAddrLoc X86_80FloatRepr ar
F.X87Register n -> pure $ Some $ FPLocation X86_80FloatRepr (X87StackRegister n)
_ -> fail $ "Bad floating point argument."
-- | Get a floating point value from the argument.
getFPValue :: Semantics m => F.Value -> m (Some (FPValue m))
getFPValue v = getFPLocation v >>= \(Some l) -> Some <$> readFPLocation l
------------------------------------------------------------------------
-- Standard memory values
data HasRepSize f w = HasRepSize { _ppvWidth :: !(RepValSize w)
, _ppvValue :: !(f (BVType w))
}
-- | Gets the location to store the value poped from.
-- These functions only support general purpose registers/addresses and segments.
getAddrRegOrSegment :: forall m . Semantics m => F.Value -> m (Some (HasRepSize (MLocation m)))
getAddrRegOrSegment v =
case v of
F.SegmentValue s -> pure $ Some $ HasRepSize WordRepVal (SegmentReg s)
F.Mem8 ar -> Some . HasRepSize ByteRepVal . (`MemoryAddr` byteMemRepr) <$> getBVAddress ar
F.Mem16 ar -> Some . HasRepSize WordRepVal . (`MemoryAddr` wordMemRepr) <$> getBVAddress ar
F.Mem32 ar -> Some . HasRepSize DWordRepVal . (`MemoryAddr` dwordMemRepr) <$> getBVAddress ar
F.Mem64 ar -> Some . HasRepSize QWordRepVal . (`MemoryAddr` qwordMemRepr) <$> getBVAddress ar
F.ByteReg r
| Just r64 <- F.is_low_reg r -> pure $ Some $ HasRepSize ByteRepVal (reg_low8 $ X86_GP r64)
| Just r64 <- F.is_high_reg r -> pure $ Some $ HasRepSize ByteRepVal (reg_high8 $ X86_GP r64)
| otherwise -> fail "unknown r8"
F.WordReg r -> pure $ Some $ HasRepSize WordRepVal (reg_low16 (X86_GP $ F.reg16_reg r))
F.DWordReg r -> pure $ Some $ HasRepSize DWordRepVal (reg_low32 (X86_GP $ F.reg32_reg r))
F.QWordReg r -> pure $ Some $ HasRepSize QWordRepVal (fullRegister $ X86_GP r)
_ -> fail $ "Argument " ++ show v ++ " not supported."
-- | Gets a value that can be pushed.
-- These functions only support general purpose registers/addresses and segments.
getAddrRegSegmentOrImm :: forall m . Semantics m => F.Value -> m (Some (HasRepSize (Value m)))
getAddrRegSegmentOrImm v =
case v of
F.ByteImm w -> return $ Some $ HasRepSize ByteRepVal $ bvLit n8 (toInteger w)
F.WordImm w -> return $ Some $ HasRepSize WordRepVal $ bvLit n16 (toInteger w)
F.DWordImm w -> return $ Some $ HasRepSize DWordRepVal $ bvLit n32 (toInteger w)
F.QWordImm w -> return $ Some $ HasRepSize QWordRepVal $ bvLit n64 (toInteger w)
_ -> do
Some (HasRepSize rep l) <- getAddrRegOrSegment v
Some . HasRepSize rep <$> get l
------------------------------------------------------------------------
-- SSE
-- | Get a XMM value
readXMMValue :: Semantics m => F.Value -> m (Value m (BVType 128))
readXMMValue (F.XMMReg r) = get $ fullRegister $ X86_XMMReg r
readXMMValue (F.Mem128 a) = readBVAddress a xmmMemRepr
readXMMValue _ = fail "XMM Instruction given unexpected value."

View File

@ -0,0 +1,261 @@
{-|
Copyright : (c) Galois, Inc 2015-2017
Maintainer : Joe Hendrix <jhendrix@galois.com>
This defines the instruction def type, which contains the
semantic definition of a function.
-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
module Data.Macaw.X86.InstructionDef
( InstructionDef
, InstructionSemantics(..)
, defVariadic
, defConditionals
-- * Nullary function helper
, defNullary
, defNullaryPrefix
-- * Unary instruction helpers
, defUnary
, defUnaryLoc
, defUnaryKnown
, defUnaryV
, defUnaryFPL
, defUnaryFPV
-- * Binary instruction helpers
, defBinary
, defBinaryLV
, defBinaryLVpoly
, defBinaryLVge
, defBinaryKnown
, defBinaryXMMV
, defBinaryLL
, defFPBinaryImplicit
-- * Ternary instruction helpers
, defTernary
, defTernaryLVV
) where
import qualified Flexdis86 as F
import Data.Macaw.Types
import Data.Parameterized.NatRepr
import Data.Parameterized.Some
import GHC.TypeLits (KnownNat)
import Data.Macaw.X86.Conditions
import Data.Macaw.X86.Getters
import Data.Macaw.X86.Monad
-- This is a wrapper around the semantics of an instruction.
newtype InstructionSemantics
= InstructionSemantics { _unInstructionSemantics
:: forall m. Semantics m
=> F.InstructionInstance
-> m ()
}
-- | The information needed to define an instruction semantics.
type InstructionDef = (String, InstructionSemantics)
-- | Create a instruction that potentially takes any number of arguments.
defVariadic :: String
-> (forall m. Semantics m => F.LockPrefix -> [F.Value] -> m ())
-> InstructionDef
defVariadic mnemonic f =
(mnemonic, InstructionSemantics (\ii -> f (F.iiLockPrefix ii) (fst <$> F.iiArgs ii)))
-- | Define an instruction that expects no arguments.
defNullary :: String
-> (forall m . Semantics m => m ())
-> InstructionDef
defNullary mnem f = defVariadic mnem (\_ _ -> f)
-- | Define an instruction that expects no arguments other than a prefix
defNullaryPrefix :: String
-> (forall m. Semantics m => F.LockPrefix -> m ())
-> InstructionDef
defNullaryPrefix mnem f = defVariadic mnem (\pfx _ -> f pfx)
-- | Define an instruction that expects a single argument
defUnary :: String
-- ^ Instruction mnemonic
-> (forall m . Semantics m => F.LockPrefix -> F.Value -> m ())
-- ^ Sementic definition
-> InstructionDef
defUnary mnem f = defVariadic mnem $ \pfx vs ->
case vs of
[v] -> f pfx v
_ -> fail $ "defUnary: " ++ mnem ++ " expecting 1 arguments, got " ++ show (length vs)
-- | Defines an instruction that expects a single bitvec location as an argument.
defUnaryLoc :: String
-> (forall m n. IsLocationBV m n => MLocation m (BVType n) -> m ())
-> InstructionDef
defUnaryLoc s f = defUnary s $ \_ val -> do
SomeBV v <- getSomeBVLocation val
f v
-- | Defines an instruction that expects a bitvector location with a known fixed width.
defUnaryKnown :: KnownNat n
=> String
-> (forall m . Semantics m => MLocation m (BVType n) -> m ())
-> InstructionDef
defUnaryKnown s f = defUnary s $ \_ loc -> f =<< getBVLocation loc knownNat
-- | Defines an instruction that expects a single bitvec value as an argument.
defUnaryV :: String
-> (forall m n. IsLocationBV m n => Value m (BVType n) -> m ())
-> InstructionDef
defUnaryV s f = defUnary s $ \_ val -> do
SomeBV v <- getSomeBVValue val
f v
defUnaryFPL :: String
-> (forall m flt. Semantics m => FloatInfoRepr flt -> MLocation m (FloatType flt) -> m ())
-> InstructionDef
defUnaryFPL mnem f = defUnary mnem $ \_ v -> do
Some (FPLocation repr loc) <- getFPLocation v
f repr loc
defUnaryFPV :: String
-> (forall m flt. Semantics m => FloatInfoRepr flt -> Value m (FloatType flt) -> m ())
-> InstructionDef
defUnaryFPV mnem f = defUnary mnem $ \_ v -> do
Some (FPValue repr val) <- getFPValue v
f repr val
-- | Define an instruction that expects two arguments.
defBinary :: String
-> (forall m . Semantics m => F.LockPrefix -> F.Value -> F.Value -> m ())
-> InstructionDef
defBinary mnem f = defVariadic mnem $ \pfx vs ->
case vs of
[v, v'] -> f pfx v v'
_ -> fail $ "defBinary: " ++ mnem ++ ": expecting 2 arguments, got " ++ show (length vs)
defBinaryLV :: String
-> (forall m n. IsLocationBV m n => MLocation m (BVType n) -> Value m (BVType n) -> m ())
-> InstructionDef
defBinaryLV mnem f = defBinary mnem $ \_ loc val -> do
SomeBV l <- getSomeBVLocation loc
v <- getSignExtendedValue val (typeWidth l)
f l v
-- | This defines a instruction that expects a location and a value that may have
-- differing widths
defBinaryLVpoly :: String
-> (forall m n n'
. (IsLocationBV m n, 1 <= n')
=> MLocation m (BVType n) -> Value m (BVType n') -> m ())
-> InstructionDef
defBinaryLVpoly mnem f = defBinary mnem $ \_ loc val -> do
SomeBV l <- getSomeBVLocation loc
SomeBV v <- getSomeBVValue val
f l v
-- | This defines a instruction that expects a location and a value that may have
-- differing widths, but the location must be larger than the value.
defBinaryLVge :: String
-> (forall m n n'
. (IsLocationBV m n, 1 <= n', n' <= n)
=> MLocation m (BVType n)
-> Value m (BVType n')
-> m ())
-> InstructionDef
defBinaryLVge mnem f = defBinaryLVpoly mnem $ \l v -> do
Just LeqProof <- return $ testLeq (bv_width v) (typeWidth l)
f l v
-- | Define an instruction from a function with fixed widths kmown at compile time/.
defBinaryKnown :: (KnownNat n, KnownNat n')
=> String
-> (forall m . Semantics m => MLocation m (BVType n) -> Value m (BVType n') -> m ())
-> InstructionDef
defBinaryKnown mnem f = defBinary mnem $ \_ loc val -> do
l <- getBVLocation loc knownNat
v <- getBVValue val knownNat
f l v
defBinaryXMMV :: ( KnownNat n
, 1 <= n
)
=> String
-> (forall m . Semantics m => MLocation m XMMType -> Value m (BVType n) -> m ())
-> InstructionDef
defBinaryXMMV mnem f = defBinary mnem $ \_ loc val -> do
l <- getBVLocation loc n128
v <- truncateBVValue knownNat =<< getSomeBVValue val
f l v
defBinaryLL :: String
-> (forall m n. (IsLocationBV m n, 1 <= n)
=> F.LockPrefix
-> MLocation m (BVType n) -> MLocation m (BVType n) -> m ())
-> InstructionDef
defBinaryLL mnem f = defBinary mnem $ \pfx loc loc' -> do
SomeBV l <- getSomeBVLocation loc
l' <- getBVLocation loc' (typeWidth l)
f pfx l l'
-- | Define a function that takes either two floating point arguments.
--
-- If only one argument is provided, it is used as the second argument,
-- and the first argument is implicitly the top of the floating point stack.
defFPBinaryImplicit :: String
-> (forall m flt_d flt_s
. Semantics m
=> FloatInfoRepr flt_d
-> MLocation m (FloatType flt_d)
-> FloatInfoRepr flt_s
-> Value m (FloatType flt_s)
-> m ())
-> InstructionDef
defFPBinaryImplicit mnem f = defVariadic mnem $ \_ vs -> do
case vs of
[v] -> do
Some (FPValue repr val) <- getFPValue v
f X86_80FloatRepr (X87StackRegister 0) repr val
[loc, val] -> do
l <- getBVLocation loc knownNat
v <- getBVValue val knownNat
f X86_80FloatRepr l X86_80FloatRepr v
_ -> do
fail $ "deFPBinImplicit " ++ mnem ++ ": expecting 2 arguments, got " ++ show (length vs)
-- | Define an instruction that expects three arguments.
defTernary :: String
-> (forall m . Semantics m => F.LockPrefix -> F.Value -> F.Value -> F.Value -> m ())
-> InstructionDef
defTernary mnem f = defVariadic mnem $ \pfx vs -> do
case vs of
[v, v', v''] -> f pfx v v' v''
_ ->
fail $ "defTernary: " ++ mnem ++ ": expecting 3 arguments, got " ++ show (length vs)
defTernaryLVV :: String
-> (forall m k n
. (IsLocationBV m n, 1 <= k, k <= n)
=> MLocation m (BVType n)
-> Value m (BVType n)
-> Value m (BVType k)
-> m ())
-> InstructionDef
defTernaryLVV mnem f = defTernary mnem $ \_ loc val1 val2 -> do
SomeBV l <- getSomeBVLocation loc
v1 <- getBVValue val1 (typeWidth l)
SomeBV v2 <- getSomeBVValue val2
Just LeqProof <- return $ testLeq (bv_width v2) (bv_width v1)
f l v1 v2
-- | This generates a list of instruction definitinos -- one for each conditional predicate.
defConditionals :: String
-> (String
-> (forall m. Semantics m => m (Value m BoolType))
-> InstructionDef)
-> [InstructionDef]
defConditionals pfx mkop = mk <$> conditionalDefs
where
mk :: (String, ConditionalDef) -> InstructionDef
mk (suffix, ConditionalDef sop) = mkop (pfx ++ suffix) sop

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,72 @@
{-
Copyright : (c) Galois, Inc 2017
Maintainer : Joe Hendrix <jhendrix@galois.com>
This contains a type for modeling the X86 flags
-}
{-# LANGUAGE PatternSynonyms #-}
module Data.Macaw.X86.X86Flag
( X86Flag
, flagIndex
, pattern CF
, pattern PF
, pattern AF
, pattern ZF
, pattern SF
, pattern TF
, pattern IF
, pattern DF
, pattern OF
, flagList
) where
import qualified Data.Vector as V
import Data.Word
-- | X86 flag
newtype X86Flag = X86Flag { flagIndex :: Word8 }
deriving (Eq, Ord)
flagNames :: V.Vector String
flagNames = V.fromList
[ "cf", "RESERVED", "pf", "RESERVED", "af", "RESERVED"
, "zf", "sf", "tf", "if", "df", "of"
, "iopl", "nt", "SBZ", "rf", "vm", "ac", "vif", "vip", "id"
]
instance Show X86Flag where
show (X86Flag i) =
case flagNames V.!? fromIntegral i of
Just nm -> nm
Nothing -> "Unknown" ++ show i
pattern CF :: X86Flag
pattern CF = X86Flag 0
pattern PF :: X86Flag
pattern PF = X86Flag 2
pattern AF :: X86Flag
pattern AF = X86Flag 4
pattern ZF :: X86Flag
pattern ZF = X86Flag 6
pattern SF :: X86Flag
pattern SF = X86Flag 7
pattern TF :: X86Flag
pattern TF = X86Flag 8
pattern IF :: X86Flag
pattern IF = X86Flag 9
pattern DF :: X86Flag
pattern DF = X86Flag 10
pattern OF :: X86Flag
pattern OF = X86Flag 11
-- | Return list of x86 flags
flagList :: [X86Flag]
flagList = X86Flag <$> [0,2,4,6,7,8,9,10,11]

View File

@ -0,0 +1,451 @@
{-
Copyright : (c) Galois, Inc 2015-2017
Maintainer : Joe Hendrix <jhendrix@galois.com>, Simon Winwood <sjw@galois.com>
This defines a type for representing what Reopt considers registers on
X86_64.
-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Data.Macaw.X86.X86Reg
( ProgramCounter
, GP
, Flag
, Segment
, Control
, Debug
, X87_FPU
, X87_Status
, X87_Top
, X87_Tag
, X87_ControlMask
, X87_Control
, XMM
-- * X86Reg
, X86Reg(..)
, BitConversion(..)
, BitPacking(..)
-- , registerWidth
, x87StatusNames
-- * General purpose registers
, pattern RAX
, pattern RBX
, pattern RCX
, pattern RDX
, pattern RSI
, pattern RDI
, pattern RSP
, pattern RBP
, pattern R8
, pattern R9
, pattern R10
, pattern R11
, pattern R12
, pattern R13
, pattern R14
, pattern R15
-- * X86 Flags
, pattern CF
, pattern PF
, pattern AF
, pattern ZF
, pattern SF
, pattern TF
, pattern IF
, pattern DF
, pattern OF
-- * X87 status flags
, pattern X87_IE
, pattern X87_DE
, pattern X87_ZE
, pattern X87_OE
, pattern X87_UE
, pattern X87_PE
, pattern X87_EF
, pattern X87_ES
, pattern X87_C0
, pattern X87_C1
, pattern X87_C2
, pattern X87_C3
-- * Register lists
, gpRegList
, flagRegList
, xmmRegList
, x87FPURegList
, x86StateRegs
, x86CalleeSavedRegs
, x86ArgumentRegs
, x86FloatArgumentRegs
, x86ResultRegs
, x86FloatResultRegs
) where
import Data.Macaw.CFG (RegAddrWidth, RegisterInfo(..), PrettyF(..))
import Data.Macaw.Types
import Data.Parameterized.Classes
import Data.Parameterized.NatRepr
import Data.Parameterized.Some
import Data.Set (Set)
import qualified Data.Set as Set
import qualified Data.Vector as V
import qualified Flexdis86 as F
import Text.PrettyPrint.ANSI.Leijen as PP hiding ((<$>))
import qualified Data.Macaw.X86.X86Flag as R
-- Widths of common types
type ProgramCounter = BVType 64
type GP = BVType 64
type Flag = BoolType
type Segment = BVType 16
type Control = BVType 64
type Debug = BVType 64
type X87_FPU = BVType 80
type X87_Status = BoolType
type X87_Top = BVType 3
type X87_Tag = BVType 2
type X87_ControlMask = BVType 1
type X87_Control = BVType 2
type XMM = BVType 128
------------------------------------------------------------------------
-- X86Reg
-- The datatype for x86 registers.
data X86Reg tp
= (tp ~ BVType 64) => X86_IP
| (tp ~ BVType 64) => X86_GP {-# UNPACK #-} !F.Reg64
-- ^ One of 16 general purpose registers
| (tp ~ BoolType) => X86_FlagReg {-# UNPACK #-} !R.X86Flag
-- ^ One of 32 initial flag registers.
| (tp ~ BoolType) => X87_StatusReg {-# UNPACK #-} !Int
-- ^ One of 16 x87 status registers
| (tp ~ BVType 3) => X87_TopReg
-- X87 tag register.
| (tp ~ BVType 2) => X87_TagReg {-# UNPACK #-} !Int
-- One of 8 fpu/mmx registers.
| (tp ~ BVType 80) => X87_FPUReg {-#UNPACK #-} !F.MMXReg
-- One of 8 XMM registers
| (tp ~ BVType 128) => X86_XMMReg !F.XMMReg
instance Show (X86Reg tp) where
show X86_IP = "rip"
show (X86_GP r) = show r
show (X86_FlagReg r) = show r
show (X87_StatusReg r) = nm
where Just nm = x87StatusNames V.!? r
show X87_TopReg = "x87top"
show (X87_TagReg n) = "tag" ++ show n
show (X87_FPUReg r) = show r
show (X86_XMMReg r) = show r
instance ShowF X86Reg where
showF = show
instance PrettyF X86Reg where
prettyF = text . show
instance TestEquality X86Reg where
testEquality x y = orderingIsEqual (compareF x y)
where
-- FIXME: copied from Representation.hs, move
orderingIsEqual :: OrderingF (x :: k) (y :: k) -> Maybe (x :~: y)
orderingIsEqual o =
case o of
LTF -> Nothing
EQF -> Just Refl
GTF -> Nothing
instance Eq (X86Reg tp) where
r == r'
| Just _ <- testEquality r r' = True
| otherwise = False
instance OrdF X86Reg where
compareF X86_IP X86_IP = EQF
compareF X86_IP _ = LTF
compareF _ X86_IP = GTF
compareF (X86_GP n) (X86_GP n') = fromOrdering (compare n n')
compareF X86_GP{} _ = LTF
compareF _ X86_GP{} = GTF
compareF (X86_FlagReg n) (X86_FlagReg n') = fromOrdering (compare n n')
compareF X86_FlagReg{} _ = LTF
compareF _ X86_FlagReg{} = GTF
compareF (X87_StatusReg n) (X87_StatusReg n') = fromOrdering (compare n n')
compareF X87_StatusReg{} _ = LTF
compareF _ X87_StatusReg{} = GTF
compareF X87_TopReg X87_TopReg = EQF
compareF X87_TopReg _ = LTF
compareF _ X87_TopReg = GTF
compareF (X87_TagReg n) (X87_TagReg n') = fromOrdering (compare n n')
compareF X87_TagReg{} _ = LTF
compareF _ X87_TagReg{} = GTF
compareF (X87_FPUReg n) (X87_FPUReg n') = fromOrdering (compare n n')
compareF X87_FPUReg{} _ = LTF
compareF _ X87_FPUReg{} = GTF
compareF (X86_XMMReg n) (X86_XMMReg n') = fromOrdering (compare n n')
instance Ord (X86Reg cl) where
a `compare` b = case a `compareF` b of
GTF -> GT
EQF -> EQ
LTF -> LT
instance HasRepr X86Reg TypeRepr where
typeRepr r =
case r of
X86_IP -> knownType
X86_GP{} -> knownType
X86_FlagReg{} -> knownType
X87_StatusReg{} -> knownType
X87_TopReg -> knownType
X87_TagReg{} -> knownType
X87_FPUReg{} -> knownType
X86_XMMReg{} -> knownType
{-
registerWidth :: X86Reg tp -> NatRepr (TypeBits tp)
registerWidth X86_IP = knownNat
registerWidth X86_GP{} = knownNat
registerWidth X86_FlagReg{} = knownNat
registerWidth X87_StatusReg{} = knownNat
registerWidth X87_TopReg = knownNat
registerWidth X87_TagReg{} = knownNat
registerWidth X87_FPUReg{} = knownNat
registerWidth X86_XMMReg{} = knownNat
-}
------------------------------------------------------------------------
-- Exported constructors and their conversion to words
-- | A description of how a sub-word may be extracted from a word. If a bit isn't
-- constant or from a register it is reserved.
data BitConversion n = forall m n'. (1 <= n', n' <= n)
=> RegisterBit (X86Reg (BVType n')) (NatRepr m)
| forall m. (m + 1 <= n) => ConstantBit Bool (NatRepr m)
-- | A description of how a particular status word is packed/unpacked into sub-bits
data BitPacking (n :: Nat) = BitPacking (NatRepr n) [BitConversion n]
------------------------------------------------------------------------
-- General purpose register aliases.
pattern RAX :: X86Reg GP
pattern RAX = X86_GP F.RAX
pattern RBX :: X86Reg GP
pattern RBX = X86_GP F.RBX
pattern RCX :: X86Reg GP
pattern RCX = X86_GP F.RCX
pattern RDX :: X86Reg GP
pattern RDX = X86_GP F.RDX
pattern RSI :: X86Reg GP
pattern RSI = X86_GP F.RSI
pattern RDI :: X86Reg GP
pattern RDI = X86_GP F.RDI
pattern RSP :: X86Reg GP
pattern RSP = X86_GP F.RSP
pattern RBP :: X86Reg GP
pattern RBP = X86_GP F.RBP
pattern R8 :: X86Reg GP
pattern R8 = X86_GP F.R8
pattern R9 :: X86Reg GP
pattern R9 = X86_GP F.R9
pattern R10 :: X86Reg GP
pattern R10 = X86_GP F.R10
pattern R11 :: X86Reg GP
pattern R11 = X86_GP F.R11
pattern R12 :: X86Reg GP
pattern R12 = X86_GP F.R12
pattern R13 :: X86Reg GP
pattern R13 = X86_GP F.R13
pattern R14 :: X86Reg GP
pattern R14 = X86_GP F.R14
pattern R15 :: X86Reg GP
pattern R15 = X86_GP F.R15
pattern CF :: X86Reg Flag
pattern CF = X86_FlagReg R.CF
pattern PF :: X86Reg Flag
pattern PF = X86_FlagReg R.PF
pattern AF :: X86Reg Flag
pattern AF = X86_FlagReg R.AF
pattern ZF :: X86Reg Flag
pattern ZF = X86_FlagReg R.ZF
pattern SF :: X86Reg Flag
pattern SF = X86_FlagReg R.SF
pattern TF :: X86Reg Flag
pattern TF = X86_FlagReg R.TF
pattern IF :: X86Reg Flag
pattern IF = X86_FlagReg R.IF
pattern DF :: X86Reg Flag
pattern DF = X86_FlagReg R.DF
pattern OF :: X86Reg Flag
pattern OF = X86_FlagReg R.OF
-- | x87 flags
pattern X87_IE :: X86Reg X87_Status
pattern X87_IE = X87_StatusReg 0
pattern X87_DE :: X86Reg X87_Status
pattern X87_DE = X87_StatusReg 1
pattern X87_ZE :: X86Reg X87_Status
pattern X87_ZE = X87_StatusReg 2
pattern X87_OE :: X86Reg X87_Status
pattern X87_OE = X87_StatusReg 3
pattern X87_UE :: X86Reg X87_Status
pattern X87_UE = X87_StatusReg 4
pattern X87_PE :: X86Reg X87_Status
pattern X87_PE = X87_StatusReg 5
pattern X87_EF :: X86Reg X87_Status
pattern X87_EF = X87_StatusReg 6
pattern X87_ES :: X86Reg X87_Status
pattern X87_ES = X87_StatusReg 7
pattern X87_C0 :: X86Reg X87_Status
pattern X87_C0 = X87_StatusReg 8
pattern X87_C1 :: X86Reg X87_Status
pattern X87_C1 = X87_StatusReg 9
pattern X87_C2 :: X86Reg X87_Status
pattern X87_C2 = X87_StatusReg 10
pattern X87_C3 :: X86Reg X87_Status
pattern X87_C3 = X87_StatusReg 14
x87StatusNames :: V.Vector String
x87StatusNames = V.fromList $
[ "ie", "de", "ze", "oe", "ue", "pe", "ef", "es"
, "c0", "c1", "c2", "RESERVED", "RESERVED", "RESERVED", "c3", "RESERVED"
]
------------------------------------------------------------------------
-- RegisterInfo instance
-- | The ABI defines these (http://www.x86-64.org/documentation/abi.pdf)
-- Syscalls clobber rcx and r11, but we don't really care about these anyway.
x86SyscallArgumentRegs :: [ X86Reg (BVType 64) ]
x86SyscallArgumentRegs = [ RDI, RSI, RDX, R10, R8, R9 ]
gpRegList :: [X86Reg (BVType 64)]
gpRegList = [X86_GP (F.reg64 i) | i <- [0..15]]
flagRegList :: [X86Reg BoolType]
flagRegList = X86_FlagReg <$> R.flagList
x87StatusRegList :: [X86Reg BoolType]
x87StatusRegList = [X87_StatusReg i | i <- [0..15]]
x87TagRegList :: [X86Reg (BVType 2)]
x87TagRegList = [X87_TagReg i | i <- [0..7]]
x87FPURegList :: [X86Reg (BVType 80)]
x87FPURegList = [X87_FPUReg (F.mmxReg i) | i <- [0..7]]
xmmRegList :: [X86Reg (BVType 128)]
xmmRegList = [X86_XMMReg (F.xmmReg i) | i <- [0..15]]
-- | List of registers stored in X86State
x86StateRegs :: [Some X86Reg]
x86StateRegs
= [Some X86_IP]
++ (Some <$> gpRegList)
++ (Some <$> flagRegList)
++ (Some <$> x87StatusRegList)
++ [Some X87_TopReg]
++ (Some <$> x87TagRegList)
++ (Some <$> x87FPURegList)
++ (Some <$> xmmRegList)
type instance RegAddrWidth X86Reg = 64
instance RegisterInfo X86Reg where
archRegs = x86StateRegs
ip_reg = X86_IP
sp_reg = RSP
-- The register used to store system call numbers.
syscall_num_reg = RAX
-- The ABI defines these (http://www.x86-64.org/documentation/abi.pdf)
-- Syscalls clobber rcx and r11, but we don't really care about these
-- anyway.
syscallArgumentRegs = x86SyscallArgumentRegs
------------------------------------------------------------------------
-- Register information
-- | List of registers that a callee must save.
x86CalleeSavedRegs :: Set (Some X86Reg)
x86CalleeSavedRegs = Set.fromList $
[ -- Some rsp sjw: rsp is special
Some RBP
, Some RBX
, Some R12
, Some R13
, Some R14
, Some R15
, Some DF
, Some X87_TopReg
]
x86ArgumentRegs :: [X86Reg (BVType 64)]
x86ArgumentRegs = [ RDI, RSI, RDX, RCX, R8, R9 ]
x86FloatArgumentRegs :: [X86Reg (BVType 128)]
x86FloatArgumentRegs = X86_XMMReg . F.xmmReg <$> [0..7]
x86ResultRegs :: [X86Reg (BVType 64)]
x86ResultRegs = [ RAX, RDX ]
x86FloatResultRegs :: [X86Reg (BVType 128)]
x86FloatResultRegs = [ X86_XMMReg (F.xmmReg 0) ]

View File

@ -0,0 +1,115 @@
{-
Copyright : (c) Galois, Inc 2017
Maintainer : Joe Hendrix <jhendrix@galois.com>
This contains a type for modeling the X87 control register
-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeOperators #-}
module Data.Macaw.X86.X87ControlReg
( X87_ControlReg
, x87_IM
, x87_DM
, x87_ZM
, x87_OM
, x87_UM
, x87_PM
, x87_PC
, x87_RC
, x87_X
, x87ControlRegWidthIsPos
) where
import Data.Macaw.Types
import Data.Parameterized.Classes
import Data.Parameterized.NatRepr
-- | One of the X87 control registrs
data X87_ControlReg w = (1 <= w) => X87_ControlReg !Int !(NatRepr w)
instance TestEquality X87_ControlReg where
testEquality (X87_ControlReg xi xw) (X87_ControlReg yi yw) =
if xi == yi then
testEquality xw yw
else
Nothing
instance OrdF X87_ControlReg where
compareF (X87_ControlReg xi xw) (X87_ControlReg yi yw) =
case compare xi yi of
LT -> LTF
GT -> GTF
EQ -> compareF xw yw
instance HasRepr X87_ControlReg NatRepr where
typeRepr (X87_ControlReg _ w) = w
instance Show (X87_ControlReg w) where
show (X87_ControlReg i _) =
case i of
0 -> "im"
1 -> "dm"
2 -> "zm"
3 -> "om"
4 -> "um"
5 -> "pm"
8 -> "pc"
10 -> "rc"
12 -> "x"
_ -> "reserved"
x87_IM :: X87_ControlReg 1
x87_IM = X87_ControlReg 0 n1
x87_DM :: X87_ControlReg 1
x87_DM = X87_ControlReg 1 n1
x87_ZM :: X87_ControlReg 1
x87_ZM = X87_ControlReg 2 n1
x87_OM :: X87_ControlReg 1
x87_OM = X87_ControlReg 3 n1
x87_UM :: X87_ControlReg 1
x87_UM = X87_ControlReg 4 n1
x87_PM :: X87_ControlReg 1
x87_PM = X87_ControlReg 5 n1
-- | X87 precision control field.
--
-- Values are:
-- 00 Single Precision (24 bits)
-- 01 Reserved
-- 10 Double Precision (53 bits)
-- 11 Double Extended Precision (64 bits)
x87_PC :: X87_ControlReg 2
x87_PC = X87_ControlReg 8 knownNat
-- | X87 rounding control field. Values are:
--
-- 00 Round to nearest (even)
-- Rounded result is the closest to the infinitely precise result. If two
-- values are equally close, the result is the even value (that is, the one
-- with the least-significant bit of zero). Default
--
-- 01 Round down (toward −∞)
-- Rounded result is closest to but no greater than the infinitely precise result.
--
-- 10 Round up (toward +∞)
-- Rounded result is closest to but no less than the infinitely precise result.
--
-- 11 Round toward zero (Truncate)
-- Rounded result is closest to but no greater in absolute value than the
-- infinitely precise result.
x87_RC :: X87_ControlReg 2
x87_RC = X87_ControlReg 10 knownNat
x87_X :: X87_ControlReg 1
x87_X = X87_ControlReg 12 n1
x87ControlRegWidthIsPos :: X87_ControlReg w -> LeqProof 1 w
x87ControlRegWidthIsPos (X87_ControlReg _ _) = LeqProof

2
x86/support/README.md Normal file
View File

@ -0,0 +1,2 @@
This directory contains a cabal file with utilities for automatically
generating the system call definitions from the include files.

View File

@ -0,0 +1,33 @@
name: macaw-x86-support
version: 0.0.1
author: Galois, Inc.
maintainer: jhendrix@galois.com
build-type: Simple
cabal-version: >= 1.9.2
executable make_bsd_syscalls
build-depends:
base >= 4,
bytestring,
language-c <= 0.5.0,
lens,
pretty,
containers,
pretty-show,
attoparsec
hs-source-dirs: make_bsd_syscalls
main-is: Main.hs
executable make_linux_syscalls
build-depends:
base >= 4,
bytestring,
language-c <= 0.5.0,
lens,
pretty,
containers,
pretty-show,
attoparsec
hs-source-dirs: make_linux_syscalls
main-is: Main.hs

View File

@ -0,0 +1,257 @@
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
module Main
( main
) where
import Control.Lens
import Data.Attoparsec.ByteString.Char8 (Parser)
import qualified Data.Attoparsec.ByteString.Char8 as P
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BS
import Data.Either (either)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (catMaybes, maybe)
import Language.C
import Language.C.Analysis.AstAnalysis
import Language.C.Analysis.SemRep
import Language.C.Analysis.TravMonad
import Language.C.Data.Ident
import Language.C.Data.Name (newNameSupply)
import Language.C.Data.Position (position)
import System.Environment (getArgs)
import System.Exit
import System.IO
import Text.PrettyPrint
import Text.Show.Pretty
import Debug.Trace
-- FIXME: clag from Data.Macaw.Architecture.Syscall
data SyscallArgType = VoidArgType | WordArgType
deriving (Eq, Show, Read)
-- | The syscall.master file looks like (after pre-processing)
--
-- # <line no> filename
-- ... c header stuff
-- # <line no> "syscalls.master"
-- ; comment line
-- ...
-- <syscall no.>\t<audit>\t<syscall type>\t<prototype> ... ignored stuff ...
--
-- for example
--
-- 538 43207 STD { int bindat(int fd, int s, caddr_t name, int namelen); }
--
-- This file then does the following:
-- 1. Divide the file into two parts: the C headers and the syscall defs
-- 2. Parse each line in the syscall defs to extract the propotype
-- 3. Extract the argument types from the C prototype.
data SyscallInfo =
SyscallInfo { syscallNo :: Integer
, syscallAudit :: Integer
, syscallType :: ByteString
, syscallProto :: Maybe CExtDecl
}
deriving Show
syscallLine :: [Ident] -> Parser (Maybe SyscallInfo)
syscallLine idents =
P.choice [ P.char ';' >> return Nothing
, parseLine
]
where
parseLine = do
num <- P.decimal
P.skipSpace
audit <- P.decimal
P.skipSpace
cl <- P.takeWhile (not . P.isSpace)
P.skipSpace
cdecl <- P.choice [ P.char '{' >> P.takeTill ((==) '}') >>= return . parseDecl
, P.takeWhile1 (not . P.isSpace) >> return Nothing
]
return (Just (SyscallInfo num audit cl cdecl))
parseDecl bytes =
-- FIXME: we should maybe chain through newNameSupply? I don't think it is ever used ...
case execParser extDeclP bytes (position 0 "" 0 0) idents newNameSupply of
Left _err -> Nothing
Right (cdecl, _unusedNames) -> Just cdecl
------------------------------------------------------------------------
-- Haskell generation
-- A bit hacky, but no less than using TH to read in a text file
generateHSFile :: CTranslUnit -> [SyscallInfo] -> Doc
generateHSFile tunit sis =
vcat [ text "-- DO NOT EDIT. Generated from make_bsd_syscalls/Main.hs"
, text "module Data.Macaw.X86.SyscallInfo.FreeBSD (syscallInfo) where"
, text "import Data.Macaw.Architecture.Syscall"
, text "import Data.Map (Map, fromList)"
, text "import Data.Word"
, text ""
, text "syscallInfo :: Map Word64 SyscallTypeInfo"
, text "syscallInfo =" <+> ppDoc syscallMap ]
where
syscallMap = Map.fromList [ (syscallNo si, info)
| si <- sis
, Just d <- [ syscallProto si ]
, Right (info, _) <- [ syscallInfo d ] ]
-- syscallInfo :: CExtDecl -> Maybe (String, SyscallArgType, [SyscallArgType])
syscallInfo cdecl =
runTrav (error "no decl") $ do
_ <- analyseAST tunit
let handler (DeclEvent idecl) = modifyUserState (const $ summariseDeclEvent idecl)
handler _ = return ()
withExtDeclHandler (analyseExt cdecl) handler
getUserState
-- summariseDeclEvent idecl = pretty idecl
summariseDeclEvent (getVarDecl -> VarDecl vname _ (FunctionType (FunType rettyp params _) _)) =
( identToString (identOfVarName vname)
, typeToArgType rettyp
, map (typeToArgType . declType) params )
-- syscallInfo (CDeclExt (CDecl [CTypeSpec spec] [(Just declr, _, _)] _))
-- | CDeclr (Just ident) [CFunDeclr (Right (decls, _)) _ _] _ _ _ <- declr
-- = Just (identToString ident, typeSpecToArgType spec, map declToArgType decls)
-- syscallInfo d = error ("unhandled decl" ++ show d)
-- declToArgType (CDecl [CTypeSpec spec] _) = typeSpecToArgType spec
-- declToArgType d = error ("unhandled decl (in type) " ++ show d)
typeToArgType :: Type -> SyscallArgType
typeToArgType typ =
case typ of
DirectType typ' _ _ ->
case typ' of
TyVoid -> VoidArgType
TyIntegral _ -> WordArgType
TyFloating TyLDouble -> unhandled
TyFloating _ -> unhandled -- XMMFloatType
TyComplex _ -> unhandled
TyComp comp -> unhandled -- compTypeToArgType comp
TyEnum _ -> WordArgType -- FIXME: ???
TyBuiltin _ -> unhandled
PtrType _ _ _ -> WordArgType
ArrayType _ _ _ _ -> WordArgType
FunctionType _ _ -> unhandled
TypeDefType (TypeDefRef _ (Just typ) _) _ _ -> typeToArgType typ
where
unhandled = error ("Unhandled type: " ++ show (pretty typ))
------------------------------------------------------------------------
-- File preprocessing
cppLinePragma :: Parser (Integer, String)
cppLinePragma = do
_ <- P.string "# "
n <- P.decimal
_ <- P.space
_ <- P.char '"'
filename <- P.many1 (P.satisfy ((/=) '"'))
_ <- P.char '"'
-- .. other stuff until end of line, we don't really care though
return (n, filename)
-- | This attempts to parses a bytestring line of the form:
--
-- "# ?decimal "?filename".*
--
-- If it matches this, then it returns the decimal value and
-- filenumber. If it does not, then it returns nothing.
isCPPLinePragma :: BS.ByteString
-> Maybe (Integer, String)
isCPPLinePragma str =
case P.parseOnly cppLinePragma str of
Left _ -> Nothing
Right r -> Just r
-- | This takes the lines in a file, and returns a pair of lines.
-- The first contains those lines between a pragma of the form
--
-- # XX "syscalls.master"
--
-- and a pragma with any other filename.
--
-- The second contains the other lines.
splitFile :: [BS.ByteString] -> ([BS.ByteString], [BS.ByteString])
splitFile = go False mempty
where
go :: Bool
-- ^ This flag is true if the last CPP line pragma had the filemname
-- syscalls.master"
-> ([BS.ByteString], [BS.ByteString])
-- ^ This contains the lines outside the system call
-- contents and the lines inside of respectively.
-> [BS.ByteString]
-> ([BS.ByteString], [BS.ByteString])
go _ acc [] = acc
go inSyscalls acc (l : ls)
| Just (_, filename) <- isCPPLinePragma l
= go (filename == "syscalls.master") acc ls
-- Add lines in the system
| otherwise =
go inSyscalls (acc & (if inSyscalls then _1 else _2) %~ (++ [l])) ls
------------------------------------------------------------------------
-- Parsing
translUnitToIdents :: CTranslUnit -> [Ident]
translUnitToIdents (CTranslUnit decls _) =
[ ident | CDeclExt (CDecl _ tdecls _) <- decls
, (Just (CDeclr (Just ident) _ _ _ _), _, _) <- tdecls ]
------------------------------------------------------------------------
-- Main
parseSyscallLine :: [Ident] -> BS.ByteString -> IO (Maybe SyscallInfo)
parseSyscallLine idents l =
case P.parseOnly (syscallLine idents) l of
Left err -> do
hPutStrLn stderr $ "Could not parse system call:"
hPutStrLn stderr $ " " ++ show err
hPutStrLn stderr $ " Input: " ++ BS.unpack l
exitFailure
Right i ->
return i
showUsageAndExit :: IO a
showUsageAndExit = do
hPutStrLn stderr $ unlines
[ "This program generates the Haskell module that maps system call ids"
, "in FreeBSD to the name, argument types, and result type."
, ""
, "Please specify the system.master.h file as the first argument."
, "The resulting Haskell module will be written to standard out."
]
exitFailure
main :: IO ()
main = do
args <- getArgs
input <-
case args of
[input] -> pure input
_ -> showUsageAndExit
-- Get contents and split into lines.
ls <- BS.split '\n' <$> BS.readFile input
let (syscalls, split_headers) = splitFile (filter (not . BS.null) ls)
headers = BS.intercalate "\n" split_headers
Right tunit = parseC headers (position 0 "" 0 0)
idents = translUnitToIdents tunit
ms <- mapM (parseSyscallLine idents) (tail syscalls)
putStrLn "Got ms"
-- mapM_ pp (catMaybes ms)
print $ generateHSFile tunit $ catMaybes ms

View File

@ -0,0 +1,927 @@
$FreeBSD: src/sys/kern/syscalls.master,v 1.259.2.3.2.1 2010/06/14 02:09:06 kensmith Exp $
; from: @(#)syscalls.master 8.2 (Berkeley) 1/13/94
;
; System call name/number master file.
; Processed to created init_sysent.c, syscalls.c and syscall.h.
; Columns: number audit type name alt{name,tag,rtyp}/comments
; number system call number, must be in order
; audit the audit event associated with the system call
; A value of AUE_NULL means no auditing, but it also means that
; there is no audit event for the call at this time. For the
; case where the event exists, but we don't want auditing, the
; event should be #defined to AUE_NULL in audit_kevents.h.
; type one of STD, OBSOL, UNIMPL, COMPAT, COMPAT4, COMPAT6,
; COMPAT7, LIBCOMPAT, NODEF, NOARGS, NOPROTO, NOSTD
; The COMPAT* options may be combined with one or more NO*
; options separated by '|' with no spaces (e.g. COMPAT|NOARGS)
; name psuedo-prototype of syscall routine
; If one of the following alts is different, then all appear:
; altname name of system call if different
; alttag name of args struct tag if different from [o]`name'"_args"
; altrtyp return type if not int (bogus - syscalls always return int)
; for UNIMPL/OBSOL, name continues with comments
; types:
; STD always included
; COMPAT included on COMPAT #ifdef
; COMPAT4 included on COMPAT4 #ifdef (FreeBSD 4 compat)
; COMPAT6 included on COMPAT6 #ifdef (FreeBSD 6 compat)
; COMPAT7 included on COMPAT7 #ifdef (FreeBSD 7 compat)
; LIBCOMPAT included on COMPAT #ifdef, and placed in syscall.h
; OBSOL obsolete, not included in system, only specifies name
; UNIMPL not implemented, placeholder only
; NOSTD implemented but as a lkm that can be statically
; compiled in; sysent entry will be filled with lkmressys
; so the SYSCALL_MODULE macro works
; NOARGS same as STD except do not create structure in sys/sysproto.h
; NODEF same as STD except only have the entry in the syscall table
; added. Meaning - do not create structure or function
; prototype in sys/sysproto.h
; NOPROTO same as STD except do not create structure or
; function prototype in sys/sysproto.h. Does add a
; definition to syscall.h besides adding a sysent.
;
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master
; #ifdef's, etc. may be included, and are copied to the output files.
#include <sys/param.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
; Reserved/unimplemented system calls in the range 0-150 inclusive
; are reserved for use in future Berkeley releases.
; Additional system calls implemented in vendor and other
; redistributions should be placed in the reserved range at the end
; of the current calls.
0 AUE_NULL STD { int nosys(void); } syscall nosys_args int
1 AUE_EXIT STD { void sys_exit(int rval); } exit \
sys_exit_args void
2 AUE_FORK STD { int fork(void); }
3 AUE_NULL STD { ssize_t read(int fd, void *buf, \
size_t nbyte); }
4 AUE_NULL STD { ssize_t write(int fd, const void *buf, \
size_t nbyte); }
5 AUE_OPEN_RWTC STD { int open(char *path, int flags, int mode); }
; XXX should be { int open(const char *path, int flags, ...); }
; but we're not ready for `const' or varargs.
; XXX man page says `mode_t mode'.
6 AUE_CLOSE STD { int close(int fd); }
7 AUE_WAIT4 STD { int wait4(int pid, int *status, \
int options, struct rusage *rusage); } \
wait4 wait_args int
8 AUE_CREAT COMPAT { int creat(char *path, int mode); }
9 AUE_LINK STD { int link(char *path, char *link); }
10 AUE_UNLINK STD { int unlink(char *path); }
11 AUE_NULL OBSOL execv
12 AUE_CHDIR STD { int chdir(char *path); }
13 AUE_FCHDIR STD { int fchdir(int fd); }
14 AUE_MKNOD STD { int mknod(char *path, int mode, int dev); }
15 AUE_CHMOD STD { int chmod(char *path, int mode); }
16 AUE_CHOWN STD { int chown(char *path, int uid, int gid); }
17 AUE_NULL STD { int obreak(char *nsize); } break \
obreak_args int
18 AUE_GETFSSTAT COMPAT4 { int getfsstat(struct ostatfs *buf, \
long bufsize, int flags); }
19 AUE_LSEEK COMPAT { long lseek(int fd, long offset, \
int whence); }
20 AUE_GETPID STD { pid_t getpid(void); }
21 AUE_MOUNT STD { int mount(char *type, char *path, \
int flags, caddr_t data); }
; XXX `path' should have type `const char *' but we're not ready for that.
22 AUE_UMOUNT STD { int unmount(char *path, int flags); }
23 AUE_SETUID STD { int setuid(uid_t uid); }
24 AUE_GETUID STD { uid_t getuid(void); }
25 AUE_GETEUID STD { uid_t geteuid(void); }
26 AUE_PTRACE STD { int ptrace(int req, pid_t pid, \
caddr_t addr, int data); }
27 AUE_RECVMSG STD { int recvmsg(int s, struct msghdr *msg, \
int flags); }
28 AUE_SENDMSG STD { int sendmsg(int s, struct msghdr *msg, \
int flags); }
29 AUE_RECVFROM STD { int recvfrom(int s, caddr_t buf, \
size_t len, int flags, \
struct sockaddr * __restrict from, \
__socklen_t * __restrict fromlenaddr); }
30 AUE_ACCEPT STD { int accept(int s, \
struct sockaddr * __restrict name, \
__socklen_t * __restrict anamelen); }
31 AUE_GETPEERNAME STD { int getpeername(int fdes, \
struct sockaddr * __restrict asa, \
__socklen_t * __restrict alen); }
32 AUE_GETSOCKNAME STD { int getsockname(int fdes, \
struct sockaddr * __restrict asa, \
__socklen_t * __restrict alen); }
33 AUE_ACCESS STD { int access(char *path, int flags); }
34 AUE_CHFLAGS STD { int chflags(char *path, int flags); }
35 AUE_FCHFLAGS STD { int fchflags(int fd, int flags); }
36 AUE_SYNC STD { int sync(void); }
37 AUE_KILL STD { int kill(int pid, int signum); }
38 AUE_STAT COMPAT { int stat(char *path, struct ostat *ub); }
39 AUE_GETPPID STD { pid_t getppid(void); }
40 AUE_LSTAT COMPAT { int lstat(char *path, struct ostat *ub); }
41 AUE_DUP STD { int dup(u_int fd); }
42 AUE_PIPE STD { int pipe(void); }
43 AUE_GETEGID STD { gid_t getegid(void); }
44 AUE_PROFILE STD { int profil(caddr_t samples, size_t size, \
size_t offset, u_int scale); }
45 AUE_KTRACE STD { int ktrace(const char *fname, int ops, \
int facs, int pid); }
46 AUE_SIGACTION COMPAT { int sigaction(int signum, \
struct osigaction *nsa, \
struct osigaction *osa); }
47 AUE_GETGID STD { gid_t getgid(void); }
48 AUE_SIGPROCMASK COMPAT { int sigprocmask(int how, osigset_t mask); }
; XXX note nonstandard (bogus) calling convention - the libc stub passes
; us the mask, not a pointer to it, and we return the old mask as the
; (int) return value.
49 AUE_GETLOGIN STD { int getlogin(char *namebuf, u_int \
namelen); }
50 AUE_SETLOGIN STD { int setlogin(char *namebuf); }
51 AUE_ACCT STD { int acct(char *path); }
52 AUE_SIGPENDING COMPAT { int sigpending(void); }
53 AUE_SIGALTSTACK STD { int sigaltstack(stack_t *ss, \
stack_t *oss); }
54 AUE_IOCTL STD { int ioctl(int fd, u_long com, \
caddr_t data); }
55 AUE_REBOOT STD { int reboot(int opt); }
56 AUE_REVOKE STD { int revoke(char *path); }
57 AUE_SYMLINK STD { int symlink(char *path, char *link); }
58 AUE_READLINK STD { ssize_t readlink(char *path, char *buf, \
size_t count); }
59 AUE_EXECVE STD { int execve(char *fname, char **argv, \
char **envv); }
60 AUE_UMASK STD { int umask(int newmask); } umask umask_args \
int
61 AUE_CHROOT STD { int chroot(char *path); }
62 AUE_FSTAT COMPAT { int fstat(int fd, struct ostat *sb); }
63 AUE_NULL COMPAT { int getkerninfo(int op, char *where, \
size_t *size, int arg); } getkerninfo \
getkerninfo_args int
64 AUE_NULL COMPAT { int getpagesize(void); } getpagesize \
getpagesize_args int
65 AUE_MSYNC STD { int msync(void *addr, size_t len, \
int flags); }
66 AUE_VFORK STD { int vfork(void); }
67 AUE_NULL OBSOL vread
68 AUE_NULL OBSOL vwrite
69 AUE_SBRK STD { int sbrk(int incr); }
70 AUE_SSTK STD { int sstk(int incr); }
71 AUE_MMAP COMPAT { int mmap(void *addr, int len, int prot, \
int flags, int fd, long pos); }
72 AUE_O_VADVISE STD { int ovadvise(int anom); } vadvise \
ovadvise_args int
73 AUE_MUNMAP STD { int munmap(void *addr, size_t len); }
74 AUE_MPROTECT STD { int mprotect(const void *addr, size_t len, \
int prot); }
75 AUE_MADVISE STD { int madvise(void *addr, size_t len, \
int behav); }
76 AUE_NULL OBSOL vhangup
77 AUE_NULL OBSOL vlimit
78 AUE_MINCORE STD { int mincore(const void *addr, size_t len, \
char *vec); }
79 AUE_GETGROUPS STD { int getgroups(u_int gidsetsize, \
gid_t *gidset); }
80 AUE_SETGROUPS STD { int setgroups(u_int gidsetsize, \
gid_t *gidset); }
81 AUE_GETPGRP STD { int getpgrp(void); }
82 AUE_SETPGRP STD { int setpgid(int pid, int pgid); }
83 AUE_SETITIMER STD { int setitimer(u_int which, struct \
itimerval *itv, struct itimerval *oitv); }
84 AUE_WAIT4 COMPAT { int wait(void); }
85 AUE_SWAPON STD { int swapon(char *name); }
86 AUE_GETITIMER STD { int getitimer(u_int which, \
struct itimerval *itv); }
87 AUE_SYSCTL COMPAT { int gethostname(char *hostname, \
u_int len); } gethostname \
gethostname_args int
88 AUE_SYSCTL COMPAT { int sethostname(char *hostname, \
u_int len); } sethostname \
sethostname_args int
89 AUE_GETDTABLESIZE STD { int getdtablesize(void); }
90 AUE_DUP2 STD { int dup2(u_int from, u_int to); }
91 AUE_NULL UNIMPL getdopt
92 AUE_FCNTL STD { int fcntl(int fd, int cmd, long arg); }
; XXX should be { int fcntl(int fd, int cmd, ...); }
; but we're not ready for varargs.
93 AUE_SELECT STD { int select(int nd, fd_set *in, fd_set *ou, \
fd_set *ex, struct timeval *tv); }
94 AUE_NULL UNIMPL setdopt
95 AUE_FSYNC STD { int fsync(int fd); }
96 AUE_SETPRIORITY STD { int setpriority(int which, int who, \
int prio); }
97 AUE_SOCKET STD { int socket(int domain, int type, \
int protocol); }
98 AUE_CONNECT STD { int connect(int s, caddr_t name, \
int namelen); }
99 AUE_ACCEPT COMPAT|NOARGS { int accept(int s, caddr_t name, \
int *anamelen); } accept accept_args int
100 AUE_GETPRIORITY STD { int getpriority(int which, int who); }
101 AUE_SEND COMPAT { int send(int s, caddr_t buf, int len, \
int flags); }
102 AUE_RECV COMPAT { int recv(int s, caddr_t buf, int len, \
int flags); }
103 AUE_SIGRETURN COMPAT { int sigreturn( \
struct osigcontext *sigcntxp); }
104 AUE_BIND STD { int bind(int s, caddr_t name, \
int namelen); }
105 AUE_SETSOCKOPT STD { int setsockopt(int s, int level, int name, \
caddr_t val, int valsize); }
106 AUE_LISTEN STD { int listen(int s, int backlog); }
107 AUE_NULL OBSOL vtimes
108 AUE_NULL COMPAT { int sigvec(int signum, struct sigvec *nsv, \
struct sigvec *osv); }
109 AUE_NULL COMPAT { int sigblock(int mask); }
110 AUE_NULL COMPAT { int sigsetmask(int mask); }
111 AUE_NULL COMPAT { int sigsuspend(osigset_t mask); }
; XXX note nonstandard (bogus) calling convention - the libc stub passes
; us the mask, not a pointer to it.
112 AUE_NULL COMPAT { int sigstack(struct sigstack *nss, \
struct sigstack *oss); }
113 AUE_RECVMSG COMPAT { int recvmsg(int s, struct omsghdr *msg, \
int flags); }
114 AUE_SENDMSG COMPAT { int sendmsg(int s, caddr_t msg, \
int flags); }
115 AUE_NULL OBSOL vtrace
116 AUE_GETTIMEOFDAY STD { int gettimeofday(struct timeval *tp, \
struct timezone *tzp); }
117 AUE_GETRUSAGE STD { int getrusage(int who, \
struct rusage *rusage); }
118 AUE_GETSOCKOPT STD { int getsockopt(int s, int level, int name, \
caddr_t val, int *avalsize); }
119 AUE_NULL UNIMPL resuba (BSD/OS 2.x)
120 AUE_READV STD { int readv(int fd, struct iovec *iovp, \
u_int iovcnt); }
121 AUE_WRITEV STD { int writev(int fd, struct iovec *iovp, \
u_int iovcnt); }
122 AUE_SETTIMEOFDAY STD { int settimeofday(struct timeval *tv, \
struct timezone *tzp); }
123 AUE_FCHOWN STD { int fchown(int fd, int uid, int gid); }
124 AUE_FCHMOD STD { int fchmod(int fd, int mode); }
125 AUE_RECVFROM COMPAT|NOARGS { int recvfrom(int s, caddr_t buf, \
size_t len, int flags, caddr_t from, int \
*fromlenaddr); } recvfrom recvfrom_args \
int
126 AUE_SETREUID STD { int setreuid(int ruid, int euid); }
127 AUE_SETREGID STD { int setregid(int rgid, int egid); }
128 AUE_RENAME STD { int rename(char *from, char *to); }
129 AUE_TRUNCATE COMPAT { int truncate(char *path, long length); }
130 AUE_FTRUNCATE COMPAT { int ftruncate(int fd, long length); }
131 AUE_FLOCK STD { int flock(int fd, int how); }
132 AUE_MKFIFO STD { int mkfifo(char *path, int mode); }
133 AUE_SENDTO STD { int sendto(int s, caddr_t buf, size_t len, \
int flags, caddr_t to, int tolen); }
134 AUE_SHUTDOWN STD { int shutdown(int s, int how); }
135 AUE_SOCKETPAIR STD { int socketpair(int domain, int type, \
int protocol, int *rsv); }
136 AUE_MKDIR STD { int mkdir(char *path, int mode); }
137 AUE_RMDIR STD { int rmdir(char *path); }
138 AUE_UTIMES STD { int utimes(char *path, \
struct timeval *tptr); }
139 AUE_NULL OBSOL 4.2 sigreturn
140 AUE_ADJTIME STD { int adjtime(struct timeval *delta, \
struct timeval *olddelta); }
141 AUE_GETPEERNAME COMPAT { int getpeername(int fdes, caddr_t asa, \
int *alen); }
142 AUE_SYSCTL COMPAT { long gethostid(void); }
143 AUE_SYSCTL COMPAT { int sethostid(long hostid); }
144 AUE_GETRLIMIT COMPAT { int getrlimit(u_int which, struct \
orlimit *rlp); }
145 AUE_SETRLIMIT COMPAT { int setrlimit(u_int which, \
struct orlimit *rlp); }
146 AUE_KILLPG COMPAT { int killpg(int pgid, int signum); }
147 AUE_SETSID STD { int setsid(void); }
148 AUE_QUOTACTL STD { int quotactl(char *path, int cmd, int uid, \
caddr_t arg); }
149 AUE_O_QUOTA COMPAT { int quota(void); }
150 AUE_GETSOCKNAME COMPAT|NOARGS { int getsockname(int fdec, \
caddr_t asa, int *alen); } getsockname \
getsockname_args int
; Syscalls 151-180 inclusive are reserved for vendor-specific
; system calls. (This includes various calls added for compatibity
; with other Unix variants.)
; Some of these calls are now supported by BSD...
151 AUE_NULL UNIMPL sem_lock (BSD/OS 2.x)
152 AUE_NULL UNIMPL sem_wakeup (BSD/OS 2.x)
153 AUE_NULL UNIMPL asyncdaemon (BSD/OS 2.x)
; 154 is initialised by the NLM code, if present.
154 AUE_NULL NOSTD { int nlm_syscall(int debug_level, int grace_period, int addr_count, char **addrs); }
; 155 is initialized by the NFS code, if present.
155 AUE_NFS_SVC NOSTD { int nfssvc(int flag, caddr_t argp); }
156 AUE_GETDIRENTRIES COMPAT { int getdirentries(int fd, char *buf, \
u_int count, long *basep); }
157 AUE_STATFS COMPAT4 { int statfs(char *path, \
struct ostatfs *buf); }
158 AUE_FSTATFS COMPAT4 { int fstatfs(int fd, \
struct ostatfs *buf); }
159 AUE_NULL UNIMPL nosys
160 AUE_LGETFH STD { int lgetfh(char *fname, \
struct fhandle *fhp); }
161 AUE_NFS_GETFH STD { int getfh(char *fname, \
struct fhandle *fhp); }
162 AUE_SYSCTL COMPAT4 { int getdomainname(char *domainname, \
int len); }
163 AUE_SYSCTL COMPAT4 { int setdomainname(char *domainname, \
int len); }
164 AUE_NULL COMPAT4 { int uname(struct utsname *name); }
165 AUE_SYSARCH STD { int sysarch(int op, char *parms); }
166 AUE_RTPRIO STD { int rtprio(int function, pid_t pid, \
struct rtprio *rtp); }
167 AUE_NULL UNIMPL nosys
168 AUE_NULL UNIMPL nosys
169 AUE_SEMSYS NOSTD { int semsys(int which, int a2, int a3, \
int a4, int a5); }
; XXX should be { int semsys(int which, ...); }
170 AUE_MSGSYS NOSTD { int msgsys(int which, int a2, int a3, \
int a4, int a5, int a6); }
; XXX should be { int msgsys(int which, ...); }
171 AUE_SHMSYS NOSTD { int shmsys(int which, int a2, int a3, \
int a4); }
; XXX should be { int shmsys(int which, ...); }
172 AUE_NULL UNIMPL nosys
173 AUE_PREAD STD { ssize_t freebsd6_pread(int fd, void *buf, \
size_t nbyte, int pad, off_t offset); }
174 AUE_PWRITE STD { ssize_t freebsd6_pwrite(int fd, \
const void *buf, \
size_t nbyte, int pad, off_t offset); }
175 AUE_NULL STD { int setfib(int fibnum); }
176 AUE_NTP_ADJTIME STD { int ntp_adjtime(struct timex *tp); }
177 AUE_NULL UNIMPL sfork (BSD/OS 2.x)
178 AUE_NULL UNIMPL getdescriptor (BSD/OS 2.x)
179 AUE_NULL UNIMPL setdescriptor (BSD/OS 2.x)
180 AUE_NULL UNIMPL nosys
; Syscalls 181-199 are used by/reserved for BSD
181 AUE_SETGID STD { int setgid(gid_t gid); }
182 AUE_SETEGID STD { int setegid(gid_t egid); }
183 AUE_SETEUID STD { int seteuid(uid_t euid); }
184 AUE_NULL UNIMPL lfs_bmapv
185 AUE_NULL UNIMPL lfs_markv
186 AUE_NULL UNIMPL lfs_segclean
187 AUE_NULL UNIMPL lfs_segwait
188 AUE_STAT STD { int stat(char *path, struct stat *ub); }
189 AUE_FSTAT STD { int fstat(int fd, struct stat *sb); }
190 AUE_LSTAT STD { int lstat(char *path, struct stat *ub); }
191 AUE_PATHCONF STD { int pathconf(char *path, int name); }
192 AUE_FPATHCONF STD { int fpathconf(int fd, int name); }
193 AUE_NULL UNIMPL nosys
194 AUE_GETRLIMIT STD { int getrlimit(u_int which, \
struct rlimit *rlp); } getrlimit \
__getrlimit_args int
195 AUE_SETRLIMIT STD { int setrlimit(u_int which, \
struct rlimit *rlp); } setrlimit \
__setrlimit_args int
196 AUE_GETDIRENTRIES STD { int getdirentries(int fd, char *buf, \
u_int count, long *basep); }
197 AUE_MMAP STD { caddr_t freebsd6_mmap(caddr_t addr, \
size_t len, int prot, int flags, int fd, \
int pad, off_t pos); }
198 AUE_NULL NOPROTO { int nosys(void); } __syscall \
__syscall_args int
199 AUE_LSEEK STD { off_t freebsd6_lseek(int fd, int pad, \
off_t offset, int whence); }
200 AUE_TRUNCATE STD { int freebsd6_truncate(char *path, int pad, \
off_t length); }
201 AUE_FTRUNCATE STD { int freebsd6_ftruncate(int fd, int pad, \
off_t length); }
202 AUE_SYSCTL STD { int __sysctl(int *name, u_int namelen, \
void *old, size_t *oldlenp, void *new, \
size_t newlen); } __sysctl sysctl_args int
203 AUE_MLOCK STD { int mlock(const void *addr, size_t len); }
204 AUE_MUNLOCK STD { int munlock(const void *addr, size_t len); }
205 AUE_UNDELETE STD { int undelete(char *path); }
206 AUE_FUTIMES STD { int futimes(int fd, struct timeval *tptr); }
207 AUE_GETPGID STD { int getpgid(pid_t pid); }
208 AUE_NULL UNIMPL newreboot (NetBSD)
209 AUE_POLL STD { int poll(struct pollfd *fds, u_int nfds, \
int timeout); }
;
; The following are reserved for loadable syscalls
;
210 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
211 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
212 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
213 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
214 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
215 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
216 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
217 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
218 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
219 AUE_NULL NODEF lkmnosys lkmnosys nosys_args int
;
; The following were introduced with NetBSD/4.4Lite-2
220 AUE_SEMCTL COMPAT7|NOSTD { int __semctl(int semid, int semnum, \
int cmd, union semun_old *arg); }
221 AUE_SEMGET NOSTD { int semget(key_t key, int nsems, \
int semflg); }
222 AUE_SEMOP NOSTD { int semop(int semid, struct sembuf *sops, \
size_t nsops); }
223 AUE_NULL UNIMPL semconfig
224 AUE_MSGCTL COMPAT7|NOSTD { int msgctl(int msqid, int cmd, \
struct msqid_ds_old *buf); }
225 AUE_MSGGET NOSTD { int msgget(key_t key, int msgflg); }
226 AUE_MSGSND NOSTD { int msgsnd(int msqid, const void *msgp, \
size_t msgsz, int msgflg); }
227 AUE_MSGRCV NOSTD { int msgrcv(int msqid, void *msgp, \
size_t msgsz, long msgtyp, int msgflg); }
228 AUE_SHMAT NOSTD { int shmat(int shmid, const void *shmaddr, \
int shmflg); }
229 AUE_SHMCTL COMPAT7|NOSTD { int shmctl(int shmid, int cmd, \
struct shmid_ds_old *buf); }
230 AUE_SHMDT NOSTD { int shmdt(const void *shmaddr); }
231 AUE_SHMGET NOSTD { int shmget(key_t key, size_t size, \
int shmflg); }
;
232 AUE_NULL STD { int clock_gettime(clockid_t clock_id, \
struct timespec *tp); }
233 AUE_CLOCK_SETTIME STD { int clock_settime( \
clockid_t clock_id, \
const struct timespec *tp); }
234 AUE_NULL STD { int clock_getres(clockid_t clock_id, \
struct timespec *tp); }
235 AUE_NULL STD { int ktimer_create(clockid_t clock_id, \
struct sigevent *evp, int *timerid); }
236 AUE_NULL STD { int ktimer_delete(int timerid); }
237 AUE_NULL STD { int ktimer_settime(int timerid, int flags, \
const struct itimerspec *value, \
struct itimerspec *ovalue); }
238 AUE_NULL STD { int ktimer_gettime(int timerid, struct \
itimerspec *value); }
239 AUE_NULL STD { int ktimer_getoverrun(int timerid); }
240 AUE_NULL STD { int nanosleep(const struct timespec *rqtp, \
struct timespec *rmtp); }
241 AUE_NULL UNIMPL nosys
242 AUE_NULL UNIMPL nosys
243 AUE_NULL UNIMPL nosys
244 AUE_NULL UNIMPL nosys
245 AUE_NULL UNIMPL nosys
246 AUE_NULL UNIMPL nosys
247 AUE_NULL UNIMPL nosys
248 AUE_NULL STD { int ntp_gettime(struct ntptimeval *ntvp); }
249 AUE_NULL UNIMPL nosys
; syscall numbers initially used in OpenBSD
250 AUE_MINHERIT STD { int minherit(void *addr, size_t len, \
int inherit); }
251 AUE_RFORK STD { int rfork(int flags); }
252 AUE_POLL STD { int openbsd_poll(struct pollfd *fds, \
u_int nfds, int timeout); }
253 AUE_ISSETUGID STD { int issetugid(void); }
254 AUE_LCHOWN STD { int lchown(char *path, int uid, int gid); }
255 AUE_NULL NOSTD { int aio_read(struct aiocb *aiocbp); }
256 AUE_NULL NOSTD { int aio_write(struct aiocb *aiocbp); }
257 AUE_NULL NOSTD { int lio_listio(int mode, \
struct aiocb * const *acb_list, \
int nent, struct sigevent *sig); }
258 AUE_NULL UNIMPL nosys
259 AUE_NULL UNIMPL nosys
260 AUE_NULL UNIMPL nosys
261 AUE_NULL UNIMPL nosys
262 AUE_NULL UNIMPL nosys
263 AUE_NULL UNIMPL nosys
264 AUE_NULL UNIMPL nosys
265 AUE_NULL UNIMPL nosys
266 AUE_NULL UNIMPL nosys
267 AUE_NULL UNIMPL nosys
268 AUE_NULL UNIMPL nosys
269 AUE_NULL UNIMPL nosys
270 AUE_NULL UNIMPL nosys
271 AUE_NULL UNIMPL nosys
272 AUE_O_GETDENTS STD { int getdents(int fd, char *buf, \
size_t count); }
273 AUE_NULL UNIMPL nosys
274 AUE_LCHMOD STD { int lchmod(char *path, mode_t mode); }
275 AUE_LCHOWN NOPROTO { int lchown(char *path, uid_t uid, \
gid_t gid); } netbsd_lchown lchown_args \
int
276 AUE_LUTIMES STD { int lutimes(char *path, \
struct timeval *tptr); }
277 AUE_MSYNC NOPROTO { int msync(void *addr, size_t len, \
int flags); } netbsd_msync msync_args int
278 AUE_STAT STD { int nstat(char *path, struct nstat *ub); }
279 AUE_FSTAT STD { int nfstat(int fd, struct nstat *sb); }
280 AUE_LSTAT STD { int nlstat(char *path, struct nstat *ub); }
281 AUE_NULL UNIMPL nosys
282 AUE_NULL UNIMPL nosys
283 AUE_NULL UNIMPL nosys
284 AUE_NULL UNIMPL nosys
285 AUE_NULL UNIMPL nosys
286 AUE_NULL UNIMPL nosys
287 AUE_NULL UNIMPL nosys
288 AUE_NULL UNIMPL nosys
; 289 and 290 from NetBSD (OpenBSD: 267 and 268)
289 AUE_PREADV STD { ssize_t preadv(int fd, struct iovec *iovp, \
u_int iovcnt, off_t offset); }
290 AUE_PWRITEV STD { ssize_t pwritev(int fd, struct iovec *iovp, \
u_int iovcnt, off_t offset); }
291 AUE_NULL UNIMPL nosys
292 AUE_NULL UNIMPL nosys
293 AUE_NULL UNIMPL nosys
294 AUE_NULL UNIMPL nosys
295 AUE_NULL UNIMPL nosys
296 AUE_NULL UNIMPL nosys
; XXX 297 is 300 in NetBSD
297 AUE_FHSTATFS COMPAT4 { int fhstatfs( \
const struct fhandle *u_fhp, \
struct ostatfs *buf); }
298 AUE_FHOPEN STD { int fhopen(const struct fhandle *u_fhp, \
int flags); }
299 AUE_FHSTAT STD { int fhstat(const struct fhandle *u_fhp, \
struct stat *sb); }
; syscall numbers for FreeBSD
300 AUE_NULL STD { int modnext(int modid); }
301 AUE_NULL STD { int modstat(int modid, \
struct module_stat *stat); }
302 AUE_NULL STD { int modfnext(int modid); }
303 AUE_NULL STD { int modfind(const char *name); }
304 AUE_MODLOAD STD { int kldload(const char *file); }
305 AUE_MODUNLOAD STD { int kldunload(int fileid); }
306 AUE_NULL STD { int kldfind(const char *file); }
307 AUE_NULL STD { int kldnext(int fileid); }
308 AUE_NULL STD { int kldstat(int fileid, struct \
kld_file_stat* stat); }
309 AUE_NULL STD { int kldfirstmod(int fileid); }
310 AUE_GETSID STD { int getsid(pid_t pid); }
311 AUE_SETRESUID STD { int setresuid(uid_t ruid, uid_t euid, \
uid_t suid); }
312 AUE_SETRESGID STD { int setresgid(gid_t rgid, gid_t egid, \
gid_t sgid); }
313 AUE_NULL OBSOL signanosleep
314 AUE_NULL NOSTD { int aio_return(struct aiocb *aiocbp); }
315 AUE_NULL NOSTD { int aio_suspend( \
struct aiocb * const * aiocbp, int nent, \
const struct timespec *timeout); }
316 AUE_NULL NOSTD { int aio_cancel(int fd, \
struct aiocb *aiocbp); }
317 AUE_NULL NOSTD { int aio_error(struct aiocb *aiocbp); }
318 AUE_NULL NOSTD { int oaio_read(struct oaiocb *aiocbp); }
319 AUE_NULL NOSTD { int oaio_write(struct oaiocb *aiocbp); }
320 AUE_NULL NOSTD { int olio_listio(int mode, \
struct oaiocb * const *acb_list, \
int nent, struct osigevent *sig); }
321 AUE_NULL STD { int yield(void); }
322 AUE_NULL OBSOL thr_sleep
323 AUE_NULL OBSOL thr_wakeup
324 AUE_MLOCKALL STD { int mlockall(int how); }
325 AUE_MUNLOCKALL STD { int munlockall(void); }
326 AUE_GETCWD STD { int __getcwd(u_char *buf, u_int buflen); }
327 AUE_NULL STD { int sched_setparam (pid_t pid, \
const struct sched_param *param); }
328 AUE_NULL STD { int sched_getparam (pid_t pid, struct \
sched_param *param); }
329 AUE_NULL STD { int sched_setscheduler (pid_t pid, int \
policy, const struct sched_param \
*param); }
330 AUE_NULL STD { int sched_getscheduler (pid_t pid); }
331 AUE_NULL STD { int sched_yield (void); }
332 AUE_NULL STD { int sched_get_priority_max (int policy); }
333 AUE_NULL STD { int sched_get_priority_min (int policy); }
334 AUE_NULL STD { int sched_rr_get_interval (pid_t pid, \
struct timespec *interval); }
335 AUE_NULL STD { int utrace(const void *addr, size_t len); }
336 AUE_SENDFILE COMPAT4 { int sendfile(int fd, int s, \
off_t offset, size_t nbytes, \
struct sf_hdtr *hdtr, off_t *sbytes, \
int flags); }
337 AUE_NULL STD { int kldsym(int fileid, int cmd, \
void *data); }
338 AUE_JAIL STD { int jail(struct jail *jail); }
339 AUE_NULL UNIMPL pioctl
340 AUE_SIGPROCMASK STD { int sigprocmask(int how, \
const sigset_t *set, sigset_t *oset); }
341 AUE_SIGSUSPEND STD { int sigsuspend(const sigset_t *sigmask); }
342 AUE_SIGACTION COMPAT4 { int sigaction(int sig, const \
struct sigaction *act, \
struct sigaction *oact); }
343 AUE_SIGPENDING STD { int sigpending(sigset_t *set); }
344 AUE_SIGRETURN COMPAT4 { int sigreturn( \
const struct ucontext4 *sigcntxp); }
345 AUE_SIGWAIT STD { int sigtimedwait(const sigset_t *set, \
siginfo_t *info, \
const struct timespec *timeout); }
346 AUE_NULL STD { int sigwaitinfo(const sigset_t *set, \
siginfo_t *info); }
347 AUE_NULL STD { int __acl_get_file(const char *path, \
acl_type_t type, struct acl *aclp); }
348 AUE_NULL STD { int __acl_set_file(const char *path, \
acl_type_t type, struct acl *aclp); }
349 AUE_NULL STD { int __acl_get_fd(int filedes, \
acl_type_t type, struct acl *aclp); }
350 AUE_NULL STD { int __acl_set_fd(int filedes, \
acl_type_t type, struct acl *aclp); }
351 AUE_NULL STD { int __acl_delete_file(const char *path, \
acl_type_t type); }
352 AUE_NULL STD { int __acl_delete_fd(int filedes, \
acl_type_t type); }
353 AUE_NULL STD { int __acl_aclcheck_file(const char *path, \
acl_type_t type, struct acl *aclp); }
354 AUE_NULL STD { int __acl_aclcheck_fd(int filedes, \
acl_type_t type, struct acl *aclp); }
355 AUE_EXTATTRCTL STD { int extattrctl(const char *path, int cmd, \
const char *filename, int attrnamespace, \
const char *attrname); }
356 AUE_EXTATTR_SET_FILE STD { int extattr_set_file( \
const char *path, int attrnamespace, \
const char *attrname, void *data, \
size_t nbytes); }
357 AUE_EXTATTR_GET_FILE STD { ssize_t extattr_get_file( \
const char *path, int attrnamespace, \
const char *attrname, void *data, \
size_t nbytes); }
358 AUE_EXTATTR_DELETE_FILE STD { int extattr_delete_file(const char *path, \
int attrnamespace, \
const char *attrname); }
359 AUE_NULL NOSTD { int aio_waitcomplete( \
struct aiocb **aiocbp, \
struct timespec *timeout); }
360 AUE_GETRESUID STD { int getresuid(uid_t *ruid, uid_t *euid, \
uid_t *suid); }
361 AUE_GETRESGID STD { int getresgid(gid_t *rgid, gid_t *egid, \
gid_t *sgid); }
362 AUE_KQUEUE STD { int kqueue(void); }
363 AUE_NULL STD { int kevent(int fd, \
struct kevent *changelist, int nchanges, \
struct kevent *eventlist, int nevents, \
const struct timespec *timeout); }
364 AUE_NULL UNIMPL __cap_get_proc
365 AUE_NULL UNIMPL __cap_set_proc
366 AUE_NULL UNIMPL __cap_get_fd
367 AUE_NULL UNIMPL __cap_get_file
368 AUE_NULL UNIMPL __cap_set_fd
369 AUE_NULL UNIMPL __cap_set_file
370 AUE_NULL UNIMPL nosys
371 AUE_EXTATTR_SET_FD STD { int extattr_set_fd(int fd, \
int attrnamespace, const char *attrname, \
void *data, size_t nbytes); }
372 AUE_EXTATTR_GET_FD STD { ssize_t extattr_get_fd(int fd, \
int attrnamespace, const char *attrname, \
void *data, size_t nbytes); }
373 AUE_EXTATTR_DELETE_FD STD { int extattr_delete_fd(int fd, \
int attrnamespace, \
const char *attrname); }
374 AUE_NULL STD { int __setugid(int flag); }
375 AUE_NULL UNIMPL nfsclnt
376 AUE_EACCESS STD { int eaccess(char *path, int flags); }
377 AUE_NULL UNIMPL afs_syscall
378 AUE_NMOUNT STD { int nmount(struct iovec *iovp, \
unsigned int iovcnt, int flags); }
379 AUE_NULL UNIMPL kse_exit
380 AUE_NULL UNIMPL kse_wakeup
381 AUE_NULL UNIMPL kse_create
382 AUE_NULL UNIMPL kse_thr_interrupt
383 AUE_NULL UNIMPL kse_release
384 AUE_NULL STD { int __mac_get_proc(struct mac *mac_p); }
385 AUE_NULL STD { int __mac_set_proc(struct mac *mac_p); }
386 AUE_NULL STD { int __mac_get_fd(int fd, \
struct mac *mac_p); }
387 AUE_NULL STD { int __mac_get_file(const char *path_p, \
struct mac *mac_p); }
388 AUE_NULL STD { int __mac_set_fd(int fd, \
struct mac *mac_p); }
389 AUE_NULL STD { int __mac_set_file(const char *path_p, \
struct mac *mac_p); }
390 AUE_NULL STD { int kenv(int what, const char *name, \
char *value, int len); }
391 AUE_LCHFLAGS STD { int lchflags(const char *path, int flags); }
392 AUE_NULL STD { int uuidgen(struct uuid *store, \
int count); }
393 AUE_SENDFILE STD { int sendfile(int fd, int s, off_t offset, \
size_t nbytes, struct sf_hdtr *hdtr, \
off_t *sbytes, int flags); }
394 AUE_NULL STD { int mac_syscall(const char *policy, \
int call, void *arg); }
395 AUE_GETFSSTAT STD { int getfsstat(struct statfs *buf, \
long bufsize, int flags); }
396 AUE_STATFS STD { int statfs(char *path, \
struct statfs *buf); }
397 AUE_FSTATFS STD { int fstatfs(int fd, struct statfs *buf); }
398 AUE_FHSTATFS STD { int fhstatfs(const struct fhandle *u_fhp, \
struct statfs *buf); }
399 AUE_NULL UNIMPL nosys
400 AUE_NULL NOSTD { int ksem_close(semid_t id); }
401 AUE_NULL NOSTD { int ksem_post(semid_t id); }
402 AUE_NULL NOSTD { int ksem_wait(semid_t id); }
403 AUE_NULL NOSTD { int ksem_trywait(semid_t id); }
404 AUE_NULL NOSTD { int ksem_init(semid_t *idp, \
unsigned int value); }
405 AUE_NULL NOSTD { int ksem_open(semid_t *idp, \
const char *name, int oflag, \
mode_t mode, unsigned int value); }
406 AUE_NULL NOSTD { int ksem_unlink(const char *name); }
407 AUE_NULL NOSTD { int ksem_getvalue(semid_t id, int *val); }
408 AUE_NULL NOSTD { int ksem_destroy(semid_t id); }
409 AUE_NULL STD { int __mac_get_pid(pid_t pid, \
struct mac *mac_p); }
410 AUE_NULL STD { int __mac_get_link(const char *path_p, \
struct mac *mac_p); }
411 AUE_NULL STD { int __mac_set_link(const char *path_p, \
struct mac *mac_p); }
412 AUE_EXTATTR_SET_LINK STD { int extattr_set_link( \
const char *path, int attrnamespace, \
const char *attrname, void *data, \
size_t nbytes); }
413 AUE_EXTATTR_GET_LINK STD { ssize_t extattr_get_link( \
const char *path, int attrnamespace, \
const char *attrname, void *data, \
size_t nbytes); }
414 AUE_EXTATTR_DELETE_LINK STD { int extattr_delete_link( \
const char *path, int attrnamespace, \
const char *attrname); }
415 AUE_NULL STD { int __mac_execve(char *fname, char **argv, \
char **envv, struct mac *mac_p); }
416 AUE_SIGACTION STD { int sigaction(int sig, \
const struct sigaction *act, \
struct sigaction *oact); }
417 AUE_SIGRETURN STD { int sigreturn( \
const struct __ucontext *sigcntxp); }
418 AUE_NULL UNIMPL __xstat
419 AUE_NULL UNIMPL __xfstat
420 AUE_NULL UNIMPL __xlstat
421 AUE_NULL STD { int getcontext(struct __ucontext *ucp); }
422 AUE_NULL STD { int setcontext( \
const struct __ucontext *ucp); }
423 AUE_NULL STD { int swapcontext(struct __ucontext *oucp, \
const struct __ucontext *ucp); }
424 AUE_SWAPOFF STD { int swapoff(const char *name); }
425 AUE_NULL STD { int __acl_get_link(const char *path, \
acl_type_t type, struct acl *aclp); }
426 AUE_NULL STD { int __acl_set_link(const char *path, \
acl_type_t type, struct acl *aclp); }
427 AUE_NULL STD { int __acl_delete_link(const char *path, \
acl_type_t type); }
428 AUE_NULL STD { int __acl_aclcheck_link(const char *path, \
acl_type_t type, struct acl *aclp); }
429 AUE_SIGWAIT STD { int sigwait(const sigset_t *set, \
int *sig); }
430 AUE_NULL STD { int thr_create(ucontext_t *ctx, long *id, \
int flags); }
431 AUE_NULL STD { void thr_exit(long *state); }
432 AUE_NULL STD { int thr_self(long *id); }
433 AUE_NULL STD { int thr_kill(long id, int sig); }
434 AUE_NULL STD { int _umtx_lock(struct umtx *umtx); }
435 AUE_NULL STD { int _umtx_unlock(struct umtx *umtx); }
436 AUE_NULL STD { int jail_attach(int jid); }
437 AUE_EXTATTR_LIST_FD STD { ssize_t extattr_list_fd(int fd, \
int attrnamespace, void *data, \
size_t nbytes); }
438 AUE_EXTATTR_LIST_FILE STD { ssize_t extattr_list_file( \
const char *path, int attrnamespace, \
void *data, size_t nbytes); }
439 AUE_EXTATTR_LIST_LINK STD { ssize_t extattr_list_link( \
const char *path, int attrnamespace, \
void *data, size_t nbytes); }
440 AUE_NULL UNIMPL kse_switchin
441 AUE_NULL NOSTD { int ksem_timedwait(semid_t id, \
const struct timespec *abstime); }
442 AUE_NULL STD { int thr_suspend( \
const struct timespec *timeout); }
443 AUE_NULL STD { int thr_wake(long id); }
444 AUE_MODUNLOAD STD { int kldunloadf(int fileid, int flags); }
445 AUE_AUDIT STD { int audit(const void *record, \
u_int length); }
446 AUE_AUDITON STD { int auditon(int cmd, void *data, \
u_int length); }
447 AUE_GETAUID STD { int getauid(uid_t *auid); }
448 AUE_SETAUID STD { int setauid(uid_t *auid); }
449 AUE_GETAUDIT STD { int getaudit(struct auditinfo *auditinfo); }
450 AUE_SETAUDIT STD { int setaudit(struct auditinfo *auditinfo); }
451 AUE_GETAUDIT_ADDR STD { int getaudit_addr( \
struct auditinfo_addr *auditinfo_addr, \
u_int length); }
452 AUE_SETAUDIT_ADDR STD { int setaudit_addr( \
struct auditinfo_addr *auditinfo_addr, \
u_int length); }
453 AUE_AUDITCTL STD { int auditctl(char *path); }
454 AUE_NULL STD { int _umtx_op(void *obj, int op, \
u_long val, void *uaddr1, void *uaddr2); }
455 AUE_NULL STD { int thr_new(struct thr_param *param, \
int param_size); }
456 AUE_NULL STD { int sigqueue(pid_t pid, int signum, void *value); }
457 AUE_NULL NOSTD { int kmq_open(const char *path, int flags, \
mode_t mode, const struct mq_attr *attr); }
458 AUE_NULL NOSTD { int kmq_setattr(int mqd, \
const struct mq_attr *attr, \
struct mq_attr *oattr); }
459 AUE_NULL NOSTD { int kmq_timedreceive(int mqd, \
char *msg_ptr, size_t msg_len, \
unsigned *msg_prio, \
const struct timespec *abs_timeout); }
460 AUE_NULL NOSTD { int kmq_timedsend(int mqd, \
const char *msg_ptr, size_t msg_len,\
unsigned msg_prio, \
const struct timespec *abs_timeout);}
461 AUE_NULL NOSTD { int kmq_notify(int mqd, \
const struct sigevent *sigev); }
462 AUE_NULL NOSTD { int kmq_unlink(const char *path); }
463 AUE_NULL STD { int abort2(const char *why, int nargs, void **args); }
464 AUE_NULL STD { int thr_set_name(long id, const char *name); }
465 AUE_NULL NOSTD { int aio_fsync(int op, struct aiocb *aiocbp); }
466 AUE_RTPRIO STD { int rtprio_thread(int function, \
lwpid_t lwpid, struct rtprio *rtp); }
467 AUE_NULL UNIMPL nosys
468 AUE_NULL UNIMPL nosys
469 AUE_NULL UNIMPL __getpath_fromfd
470 AUE_NULL UNIMPL __getpath_fromaddr
471 AUE_NULL STD { int sctp_peeloff(int sd, uint32_t name); }
472 AUE_NULL STD { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, \
caddr_t to, __socklen_t tolen, \
struct sctp_sndrcvinfo *sinfo, int flags); }
473 AUE_NULL STD { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, \
caddr_t to, __socklen_t tolen, \
struct sctp_sndrcvinfo *sinfo, int flags); }
474 AUE_NULL STD { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, \
struct sockaddr * from, __socklen_t *fromlenaddr, \
struct sctp_sndrcvinfo *sinfo, int *msg_flags); }
475 AUE_PREAD STD { ssize_t pread(int fd, void *buf, \
size_t nbyte, off_t offset); }
476 AUE_PWRITE STD { ssize_t pwrite(int fd, const void *buf, \
size_t nbyte, off_t offset); }
477 AUE_MMAP STD { caddr_t mmap(caddr_t addr, size_t len, \
int prot, int flags, int fd, off_t pos); }
478 AUE_LSEEK STD { off_t lseek(int fd, off_t offset, \
int whence); }
479 AUE_TRUNCATE STD { int truncate(char *path, off_t length); }
480 AUE_FTRUNCATE STD { int ftruncate(int fd, off_t length); }
481 AUE_KILL STD { int thr_kill2(pid_t pid, long id, int sig); }
482 AUE_SHMOPEN STD { int shm_open(const char *path, int flags, \
mode_t mode); }
483 AUE_SHMUNLINK STD { int shm_unlink(const char *path); }
484 AUE_NULL STD { int cpuset(cpusetid_t *setid); }
485 AUE_NULL STD { int cpuset_setid(cpuwhich_t which, id_t id, \
cpusetid_t setid); }
486 AUE_NULL STD { int cpuset_getid(cpulevel_t level, \
cpuwhich_t which, id_t id, \
cpusetid_t *setid); }
487 AUE_NULL STD { int cpuset_getaffinity(cpulevel_t level, \
cpuwhich_t which, id_t id, size_t cpusetsize, \
cpuset_t *mask); }
488 AUE_NULL STD { int cpuset_setaffinity(cpulevel_t level, \
cpuwhich_t which, id_t id, size_t cpusetsize, \
const cpuset_t *mask); }
489 AUE_FACCESSAT STD { int faccessat(int fd, char *path, int mode, \
int flag); }
490 AUE_FCHMODAT STD { int fchmodat(int fd, char *path, mode_t mode, \
int flag); }
491 AUE_FCHOWNAT STD { int fchownat(int fd, char *path, uid_t uid, \
gid_t gid, int flag); }
492 AUE_FEXECVE STD { int fexecve(int fd, char **argv, \
char **envv); }
493 AUE_FSTATAT STD { int fstatat(int fd, char *path, \
struct stat *buf, int flag); }
494 AUE_FUTIMESAT STD { int futimesat(int fd, char *path, \
struct timeval *times); }
495 AUE_LINKAT STD { int linkat(int fd1, char *path1, int fd2, \
char *path2, int flag); }
496 AUE_MKDIRAT STD { int mkdirat(int fd, char *path, mode_t mode); }
497 AUE_MKFIFOAT STD { int mkfifoat(int fd, char *path, mode_t mode); }
498 AUE_MKNODAT STD { int mknodat(int fd, char *path, mode_t mode, \
dev_t dev); }
; XXX: see the comment for open
499 AUE_OPENAT_RWTC STD { int openat(int fd, char *path, int flag, \
mode_t mode); }
500 AUE_READLINKAT STD { int readlinkat(int fd, char *path, char *buf, \
size_t bufsize); }
501 AUE_RENAMEAT STD { int renameat(int oldfd, char *old, int newfd, \
char *new); }
502 AUE_SYMLINKAT STD { int symlinkat(char *path1, int fd, \
char *path2); }
503 AUE_UNLINKAT STD { int unlinkat(int fd, char *path, int flag); }
504 AUE_POSIX_OPENPT STD { int posix_openpt(int flags); }
; 505 is initialised by the kgssapi code, if present.
505 AUE_NULL NOSTD { int gssd_syscall(char *path); }
506 AUE_NULL STD { int jail_get(struct iovec *iovp, \
unsigned int iovcnt, int flags); }
507 AUE_NULL STD { int jail_set(struct iovec *iovp, \
unsigned int iovcnt, int flags); }
508 AUE_NULL STD { int jail_remove(int jid); }
509 AUE_CLOSEFROM STD { int closefrom(int lowfd); }
510 AUE_SEMCTL NOSTD { int __semctl(int semid, int semnum, \
int cmd, union semun *arg); }
511 AUE_MSGCTL NOSTD { int msgctl(int msqid, int cmd, \
struct msqid_ds *buf); }
512 AUE_SHMCTL NOSTD { int shmctl(int shmid, int cmd, \
struct shmid_ds *buf); }
513 AUE_LPATHCONF STD { int lpathconf(char *path, int name); }
514 AUE_CAP_NEW UNIMPL cap_new
515 AUE_CAP_GETRIGHTS UNIMPL cap_getrights
516 AUE_CAP_ENTER UNIMPL cap_enter
517 AUE_CAP_GETMODE UNIMPL cap_getmode
518 AUE_PDFORK UNIMPL pdfork
519 AUE_PDKILL UNIMPL pdkill
520 AUE_PDGETPID UNIMPL pdgetpid
521 AUE_PDWAIT UNIMPL pdwait
522 AUE_SELECT STD { int pselect(int nd, fd_set *in, \
fd_set *ou, fd_set *ex, \
const struct timespec *ts, \
const sigset_t *sm); }
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,220 @@
{-
The driver for creating SyscallInfo.Linux
-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
module Main (main) where
import Control.Lens
import Data.Attoparsec.ByteString.Char8 (Parser)
import qualified Data.Attoparsec.ByteString.Char8 as P
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BS
import Data.Either (either)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (catMaybes, maybe, isNothing, listToMaybe)
import Language.C
import Language.C.Analysis.AstAnalysis
import Language.C.Analysis.SemRep
import Language.C.Analysis.TravMonad
import Language.C.Data.Ident
import Language.C.Data.Name (newNameSupply)
import Language.C.Data.Position (position)
import Language.C.System.GCC (newGCC)
import System.Environment (getArgs)
import System.Exit
import System.IO
import Text.PrettyPrint
import Text.Show.Pretty
import Debug.Trace
-- FIXME: clag from Data.Macaw.Architecture.Syscall
data SyscallArgType = VoidArgType | WordArgType | XMMFloatType
deriving (Eq, Show, Read)
-- | The syscall_64.tbl file looks like (after pre-processing)
--
-- # comment1
-- ... more comments
-- # commentn
-- <syscall no.>\t+<abi>\t+<syscall name>\t<entry point>
--
-- for example
--
-- 5 common fstat sys_newfstat
--
-- entry point is optional -- if it is not present, syscall name is used.
data SyscallInfo =
SyscallInfo { syscallNo :: Integer
, syscallABI :: ByteString
, syscallName :: ByteString
, syscallProto :: Either ByteString IdentDecl
}
-- deriving Show
pp si = print $ integer (syscallNo si) <+> text (show $ syscallName si)
<+> text "->"
<+> either (const "???") pretty (syscallProto si)
-- A bit hacky, but no less than using TH to read in a text file
generateHSFile :: [SyscallInfo] -> Doc
generateHSFile sis =
vcat $ [ text "-- DO NOT EDIT. Generated from make_linux_syscalls/Main.hs"
, text "module Data.Macaw.X86.SyscallInfo.Linux (syscallInfo) where"
, text "import Data.Macaw.Architecture.Syscall"
, text "import Data.Map (Map, fromList)"
, text "import Data.Word"
, text ""
, text "syscallInfo :: Map Word64 SyscallTypeInfo"
, text "syscallInfo =" <+> ppDoc syscallMap ]
++ unknownSyscalls
where
syscallMap = Map.fromList [ (syscallNo si, syscallInfo idecl)
| si <- sis
, Right idecl <- [ syscallProto si ] ]
unknownSyscalls =
text "-- Unknown system calls: " :
[ text "--" <+> integer (syscallNo si) <+> text (BS.unpack str)
| si <- sis
, Left str <- [ syscallProto si ] ]
-- syscallInfo :: CExtDecl -> Maybe (String, SyscallArgType, [SyscallArgType])
syscallInfo (getVarDecl -> VarDecl vname _ (FunctionType (FunType rettyp params _) _)) =
( identToString (identOfVarName vname)
, typeToArgType rettyp
, map (typeToArgType . declType) params )
-- syscallInfo (CDeclExt (CDecl [CTypeSpec spec] [(Just declr, _, _)] _))
-- | CDeclr (Just ident) [CFunDeclr (Right (decls, _)) _ _] _ _ _ <- declr
-- = Just (identToString ident, typeSpecToArgType spec, map declToArgType decls)
-- syscallInfo d = error ("unhandled decl" ++ show d)
-- declToArgType (CDecl [CTypeSpec spec] _) = typeSpecToArgType spec
-- declToArgType d = error ("unhandled decl (in type) " ++ show d)
typeToArgType :: Type -> SyscallArgType
typeToArgType typ =
case typ of
DirectType typ' _ _ ->
case typ' of
TyVoid -> VoidArgType
TyIntegral _ -> WordArgType
TyFloating TyLDouble -> unhandled
TyFloating _ -> XMMFloatType
TyComplex _ -> unhandled
TyComp comp -> unhandled -- compTypeToArgType comp
TyEnum _ -> WordArgType -- FIXME: ???
TyBuiltin _ -> unhandled
PtrType _ _ _ -> WordArgType
ArrayType _ _ _ _ -> WordArgType
FunctionType _ _ -> unhandled
TypeDefType (TypeDefRef _ (Just typ) _) _ _ -> typeToArgType typ
where
unhandled = error ("Unhandled type: " ++ show (pretty typ))
compTypeToArgType :: CompTypeRef -> SyscallArgType
compTypeToArgType ctyp = trace ("Comp type: " ++ show (pretty ctyp)) WordArgType
-- We support as little as possible here ...
-- typeSpecToArgType :: Show a => CTypeSpecifier a -> SyscallArgType
-- typeSpecToArgType tspec =
-- case tspec of
-- CVoidType _ -> VoidArgType
-- CCharType _ -> WordArgType
-- CShortType _ -> WordArgType
-- CIntType _ -> WordArgType
-- CLongType _ -> WordArgType
-- CFloatType _ -> XMMFloatType
-- CDoubleType _ -> XMMFloatType
-- CSignedType _ -> WordArgType
-- CUnsigType _ -> WordArgType
-- CBoolType _ -> WordArgType
-- CSUType _ _ -> unhandled
-- CEnumType _ _ -> WordArgType -- FIXME: does it fit in a word?
-- CComplexType _ -> unhandled
-- CTypeDef __dent _ -> unhandled
-- CTypeOfExpr _ _ -> unhandled
-- CTypeOfType _ _ -> unhandled
-- where
-- unhandled = error ("Unhandled type specifier: " ++ show tspec)
readOneCFile :: FilePath -> IO (Map ByteString IdentDecl)
readOneCFile f = do
r <- parseCFile (newGCC "gcc") Nothing [] f
tunit <- case r of
Right v -> return v
Left err -> error (show err)
let gdecls = case runTrav_ (analyseAST tunit) of
Left err -> error $ "Error: " ++ (show err)
Right (gdecls, _) -> gdecls
return (Map.mapKeys (\(Ident name _ _) -> BS.pack name) $ gObjs gdecls)
syscallLine :: Map ByteString IdentDecl -> Parser (Maybe SyscallInfo)
syscallLine idents = do
P.skipSpace
P.choice [ P.char '#' >> return Nothing
, P.endOfInput >> return Nothing
, parseLine
]
where
parseLine = do
num <- P.decimal
P.skipSpace
abi <- P.takeWhile (not . P.isSpace)
P.skipSpace
name <- P.takeWhile (not . P.isSpace)
P.skipSpace
ident <- P.choice [ P.takeWhile1 (not . P.isSpace)
, return name ]
if abi == "x32"
then return Nothing
else return (Just (SyscallInfo num abi name (findIdent ident)))
findIdent bytes =
case (Map.lookup bytes idents) of
Nothing -> Left bytes
Just v -> Right v
-- -- FIXME: we should maybe chain through newNameSupply? I don't think it is ever used ...
-- case execParser expressionP bytes (position 0 "" 0 0) idents newNameSupply of
-- Right (CVar ident _, _unusedNames) -> Just ident
-- Right (e, _) -> trace ("Unknown expr: " ++ show e) Nothing
-- _ -> trace ("Couldn't find '" ++ show bytes ++ "'") Nothing
showUsageAndExit :: IO a
showUsageAndExit = do
hPutStrLn stderr $ unlines
[ "This program generates the Haskell module that maps system call ids"
, "in Linux to the name, argument types, and result type."
, ""
, "Please specify the syscals_tbl file and header files arguments."
, "The resulting Haskell module will be written to standard out."
]
exitFailure
main :: IO ()
main = do
args <- getArgs
(syscalls_tbl_file, h_files) <-
case args of
tbl_file : h_files -> pure (tbl_file, h_files)
[] -> showUsageAndExit
syscalls <- BS.lines <$> BS.readFile syscalls_tbl_file
gdecls <- mconcat <$> mapM readOneCFile h_files
ms <- case mapM (P.parseOnly (syscallLine gdecls)) syscalls of
Left err -> error $ "Error: " ++ err
Right ms -> return ms
-- mapM_ pp (catMaybes ms)
print (generateHSFile $ catMaybes ms)

View File

@ -0,0 +1,10 @@
This directory contains a script to scrape the Linux header files to
produce types for most system calls.
From the build directory, run the following for FILE in {source/arch/x86/include/asm/syscalls.h, source/include/linux/syscalls.h}
sed -i 's/#define CONFIG_ARCH_SUPPORTS_INT128.*//' include/generated/autoconf.h && gcc -Wp,-MD,init/.main.o.d -nostdinc -isystem /usr/lib/gcc/x86_64-linux-gnu/4.9/include -I/usr/src/linux-headers-lbm- -I/usr/src/linux-source-3.19.0/linux-source-3.19.0/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated -I/usr/src/linux-source-3.19.0/linux-source-3.19.0/include -Iinclude -I/usr/src/linux-source-3.19.0/linux-source-3.19.0/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/usr/src/linux-source-3.19.0/linux-source-3.19.0/include/uapi -Iinclude/generated/uapi -include /usr/src/linux-source-3.19.0/linux-source-3.19.0/include/linux/kconfig.h -Iubuntu/include -I/usr/src/linux-source-3.19.0/linux-source-3.19.0/ubuntu/include -I/usr/src/linux-source-3.19.0/linux-source-3.19.0/init -Iinit -D__KERNEL__ -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -m64 -mno-80387 -mno-fp-ret-in-387 -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -maccumulate-outgoing-args -DCONFIG_X86_X32_ABI -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -DCONFIG_AS_CFI_SECTIONS=1 -DCONFIG_AS_FXSAVEQ=1 -DCONFIG_AS_CRC32=1 -DCONFIG_AS_AVX=1 -DCONFIG_AS_AVX2=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -fno-delete-null-pointer-checks -O2 --param=allow-store-data-races=0 -Wframe-larger-than=1024 -fstack-protector -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-var-tracking-assignments -g -gdwarf-4 -pg -mfentry -DCC_USING_FENTRY -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(main)" -D"KBUILD_MODNAME=KBUILD_STR(main)" -E FILE > FILE.cpp
sed 's/stub_/sys_/' source/arch/x86/syscall_64.tbl > syscall_64.tbl

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,370 @@
#
# 64-bit system call numbers and entry vectors
#
# The format is:
# <number> <abi> <name> <entry point>
#
# The abi is "common", "64" or "x32" for this file.
#
0 common read sys_read
1 common write sys_write
2 common open sys_open
3 common close sys_close
4 common stat sys_newstat
5 common fstat sys_newfstat
6 common lstat sys_newlstat
7 common poll sys_poll
8 common lseek sys_lseek
9 common mmap sys_mmap
10 common mprotect sys_mprotect
11 common munmap sys_munmap
12 common brk sys_brk
13 64 rt_sigaction sys_rt_sigaction
14 common rt_sigprocmask sys_rt_sigprocmask
15 64 rt_sigreturn sys_rt_sigreturn
16 64 ioctl sys_ioctl
17 common pread64 sys_pread64
18 common pwrite64 sys_pwrite64
19 64 readv sys_readv
20 64 writev sys_writev
21 common access sys_access
22 common pipe sys_pipe
23 common select sys_select
24 common sched_yield sys_sched_yield
25 common mremap sys_mremap
26 common msync sys_msync
27 common mincore sys_mincore
28 common madvise sys_madvise
29 common shmget sys_shmget
30 common shmat sys_shmat
31 common shmctl sys_shmctl
32 common dup sys_dup
33 common dup2 sys_dup2
34 common pause sys_pause
35 common nanosleep sys_nanosleep
36 common getitimer sys_getitimer
37 common alarm sys_alarm
38 common setitimer sys_setitimer
39 common getpid sys_getpid
40 common sendfile sys_sendfile64
41 common socket sys_socket
42 common connect sys_connect
43 common accept sys_accept
44 common sendto sys_sendto
45 64 recvfrom sys_recvfrom
46 64 sendmsg sys_sendmsg
47 64 recvmsg sys_recvmsg
48 common shutdown sys_shutdown
49 common bind sys_bind
50 common listen sys_listen
51 common getsockname sys_getsockname
52 common getpeername sys_getpeername
53 common socketpair sys_socketpair
54 64 setsockopt sys_setsockopt
55 64 getsockopt sys_getsockopt
56 common clone sys_clone
57 common fork sys_fork
58 common vfork sys_vfork
59 64 execve sys_execve
60 common exit sys_exit
61 common wait4 sys_wait4
62 common kill sys_kill
63 common uname sys_newuname
64 common semget sys_semget
65 common semop sys_semop
66 common semctl sys_semctl
67 common shmdt sys_shmdt
68 common msgget sys_msgget
69 common msgsnd sys_msgsnd
70 common msgrcv sys_msgrcv
71 common msgctl sys_msgctl
72 common fcntl sys_fcntl
73 common flock sys_flock
74 common fsync sys_fsync
75 common fdatasync sys_fdatasync
76 common truncate sys_truncate
77 common ftruncate sys_ftruncate
78 common getdents sys_getdents
79 common getcwd sys_getcwd
80 common chdir sys_chdir
81 common fchdir sys_fchdir
82 common rename sys_rename
83 common mkdir sys_mkdir
84 common rmdir sys_rmdir
85 common creat sys_creat
86 common link sys_link
87 common unlink sys_unlink
88 common symlink sys_symlink
89 common readlink sys_readlink
90 common chmod sys_chmod
91 common fchmod sys_fchmod
92 common chown sys_chown
93 common fchown sys_fchown
94 common lchown sys_lchown
95 common umask sys_umask
96 common gettimeofday sys_gettimeofday
97 common getrlimit sys_getrlimit
98 common getrusage sys_getrusage
99 common sysinfo sys_sysinfo
100 common times sys_times
101 64 ptrace sys_ptrace
102 common getuid sys_getuid
103 common syslog sys_syslog
104 common getgid sys_getgid
105 common setuid sys_setuid
106 common setgid sys_setgid
107 common geteuid sys_geteuid
108 common getegid sys_getegid
109 common setpgid sys_setpgid
110 common getppid sys_getppid
111 common getpgrp sys_getpgrp
112 common setsid sys_setsid
113 common setreuid sys_setreuid
114 common setregid sys_setregid
115 common getgroups sys_getgroups
116 common setgroups sys_setgroups
117 common setresuid sys_setresuid
118 common getresuid sys_getresuid
119 common setresgid sys_setresgid
120 common getresgid sys_getresgid
121 common getpgid sys_getpgid
122 common setfsuid sys_setfsuid
123 common setfsgid sys_setfsgid
124 common getsid sys_getsid
125 common capget sys_capget
126 common capset sys_capset
127 64 rt_sigpending sys_rt_sigpending
128 64 rt_sigtimedwait sys_rt_sigtimedwait
129 64 rt_sigqueueinfo sys_rt_sigqueueinfo
130 common rt_sigsuspend sys_rt_sigsuspend
131 64 sigaltstack sys_sigaltstack
132 common utime sys_utime
133 common mknod sys_mknod
134 64 uselib
135 common personality sys_personality
136 common ustat sys_ustat
137 common statfs sys_statfs
138 common fstatfs sys_fstatfs
139 common sysfs sys_sysfs
140 common getpriority sys_getpriority
141 common setpriority sys_setpriority
142 common sched_setparam sys_sched_setparam
143 common sched_getparam sys_sched_getparam
144 common sched_setscheduler sys_sched_setscheduler
145 common sched_getscheduler sys_sched_getscheduler
146 common sched_get_priority_max sys_sched_get_priority_max
147 common sched_get_priority_min sys_sched_get_priority_min
148 common sched_rr_get_interval sys_sched_rr_get_interval
149 common mlock sys_mlock
150 common munlock sys_munlock
151 common mlockall sys_mlockall
152 common munlockall sys_munlockall
153 common vhangup sys_vhangup
154 common modify_ldt sys_modify_ldt
155 common pivot_root sys_pivot_root
156 64 _sysctl sys_sysctl
157 common prctl sys_prctl
158 common arch_prctl sys_arch_prctl
159 common adjtimex sys_adjtimex
160 common setrlimit sys_setrlimit
161 common chroot sys_chroot
162 common sync sys_sync
163 common acct sys_acct
164 common settimeofday sys_settimeofday
165 common mount sys_mount
166 common umount2 sys_umount
167 common swapon sys_swapon
168 common swapoff sys_swapoff
169 common reboot sys_reboot
170 common sethostname sys_sethostname
171 common setdomainname sys_setdomainname
172 common iopl sys_iopl
173 common ioperm sys_ioperm
174 64 create_module
175 common init_module sys_init_module
176 common delete_module sys_delete_module
177 64 get_kernel_syms
178 64 query_module
179 common quotactl sys_quotactl
180 64 nfsservctl
181 common getpmsg
182 common putpmsg
183 common afs_syscall
184 common tuxcall
185 common security
186 common gettid sys_gettid
187 common readahead sys_readahead
188 common setxattr sys_setxattr
189 common lsetxattr sys_lsetxattr
190 common fsetxattr sys_fsetxattr
191 common getxattr sys_getxattr
192 common lgetxattr sys_lgetxattr
193 common fgetxattr sys_fgetxattr
194 common listxattr sys_listxattr
195 common llistxattr sys_llistxattr
196 common flistxattr sys_flistxattr
197 common removexattr sys_removexattr
198 common lremovexattr sys_lremovexattr
199 common fremovexattr sys_fremovexattr
200 common tkill sys_tkill
201 common time sys_time
202 common futex sys_futex
203 common sched_setaffinity sys_sched_setaffinity
204 common sched_getaffinity sys_sched_getaffinity
205 64 set_thread_area
206 64 io_setup sys_io_setup
207 common io_destroy sys_io_destroy
208 common io_getevents sys_io_getevents
209 64 io_submit sys_io_submit
210 common io_cancel sys_io_cancel
211 64 get_thread_area
212 common lookup_dcookie sys_lookup_dcookie
213 common epoll_create sys_epoll_create
214 64 epoll_ctl_old
215 64 epoll_wait_old
216 common remap_file_pages sys_remap_file_pages
217 common getdents64 sys_getdents64
218 common set_tid_address sys_set_tid_address
219 common restart_syscall sys_restart_syscall
220 common semtimedop sys_semtimedop
221 common fadvise64 sys_fadvise64
222 64 timer_create sys_timer_create
223 common timer_settime sys_timer_settime
224 common timer_gettime sys_timer_gettime
225 common timer_getoverrun sys_timer_getoverrun
226 common timer_delete sys_timer_delete
227 common clock_settime sys_clock_settime
228 common clock_gettime sys_clock_gettime
229 common clock_getres sys_clock_getres
230 common clock_nanosleep sys_clock_nanosleep
231 common exit_group sys_exit_group
232 common epoll_wait sys_epoll_wait
233 common epoll_ctl sys_epoll_ctl
234 common tgkill sys_tgkill
235 common utimes sys_utimes
236 64 vserver
237 common mbind sys_mbind
238 common set_mempolicy sys_set_mempolicy
239 common get_mempolicy sys_get_mempolicy
240 common mq_open sys_mq_open
241 common mq_unlink sys_mq_unlink
242 common mq_timedsend sys_mq_timedsend
243 common mq_timedreceive sys_mq_timedreceive
244 64 mq_notify sys_mq_notify
245 common mq_getsetattr sys_mq_getsetattr
246 64 kexec_load sys_kexec_load
247 64 waitid sys_waitid
248 common add_key sys_add_key
249 common request_key sys_request_key
250 common keyctl sys_keyctl
251 common ioprio_set sys_ioprio_set
252 common ioprio_get sys_ioprio_get
253 common inotify_init sys_inotify_init
254 common inotify_add_watch sys_inotify_add_watch
255 common inotify_rm_watch sys_inotify_rm_watch
256 common migrate_pages sys_migrate_pages
257 common openat sys_openat
258 common mkdirat sys_mkdirat
259 common mknodat sys_mknodat
260 common fchownat sys_fchownat
261 common futimesat sys_futimesat
262 common newfstatat sys_newfstatat
263 common unlinkat sys_unlinkat
264 common renameat sys_renameat
265 common linkat sys_linkat
266 common symlinkat sys_symlinkat
267 common readlinkat sys_readlinkat
268 common fchmodat sys_fchmodat
269 common faccessat sys_faccessat
270 common pselect6 sys_pselect6
271 common ppoll sys_ppoll
272 common unshare sys_unshare
273 64 set_robust_list sys_set_robust_list
274 64 get_robust_list sys_get_robust_list
275 common splice sys_splice
276 common tee sys_tee
277 common sync_file_range sys_sync_file_range
278 64 vmsplice sys_vmsplice
279 64 move_pages sys_move_pages
280 common utimensat sys_utimensat
281 common epoll_pwait sys_epoll_pwait
282 common signalfd sys_signalfd
283 common timerfd_create sys_timerfd_create
284 common eventfd sys_eventfd
285 common fallocate sys_fallocate
286 common timerfd_settime sys_timerfd_settime
287 common timerfd_gettime sys_timerfd_gettime
288 common accept4 sys_accept4
289 common signalfd4 sys_signalfd4
290 common eventfd2 sys_eventfd2
291 common epoll_create1 sys_epoll_create1
292 common dup3 sys_dup3
293 common pipe2 sys_pipe2
294 common inotify_init1 sys_inotify_init1
295 64 preadv sys_preadv
296 64 pwritev sys_pwritev
297 64 rt_tgsigqueueinfo sys_rt_tgsigqueueinfo
298 common perf_event_open sys_perf_event_open
299 64 recvmmsg sys_recvmmsg
300 common fanotify_init sys_fanotify_init
301 common fanotify_mark sys_fanotify_mark
302 common prlimit64 sys_prlimit64
303 common name_to_handle_at sys_name_to_handle_at
304 common open_by_handle_at sys_open_by_handle_at
305 common clock_adjtime sys_clock_adjtime
306 common syncfs sys_syncfs
307 64 sendmmsg sys_sendmmsg
308 common setns sys_setns
309 common getcpu sys_getcpu
310 64 process_vm_readv sys_process_vm_readv
311 64 process_vm_writev sys_process_vm_writev
312 common kcmp sys_kcmp
313 common finit_module sys_finit_module
314 common sched_setattr sys_sched_setattr
315 common sched_getattr sys_sched_getattr
316 common renameat2 sys_renameat2
317 common seccomp sys_seccomp
318 common getrandom sys_getrandom
319 common memfd_create sys_memfd_create
320 common kexec_file_load sys_kexec_file_load
321 common bpf sys_bpf
322 64 execveat sys_execveat
#
# x32-specific system call numbers start at 512 to avoid cache impact
# for native 64-bit operation.
#
512 x32 rt_sigaction compat_sys_rt_sigaction
513 x32 rt_sigreturn sys_x32_rt_sigreturn
514 x32 ioctl compat_sys_ioctl
515 x32 readv compat_sys_readv
516 x32 writev compat_sys_writev
517 x32 recvfrom compat_sys_recvfrom
518 x32 sendmsg compat_sys_sendmsg
519 x32 recvmsg compat_sys_recvmsg
520 x32 execve sys_x32_execve
521 x32 ptrace compat_sys_ptrace
522 x32 rt_sigpending compat_sys_rt_sigpending
523 x32 rt_sigtimedwait compat_sys_rt_sigtimedwait
524 x32 rt_sigqueueinfo compat_sys_rt_sigqueueinfo
525 x32 sigaltstack compat_sys_sigaltstack
526 x32 timer_create compat_sys_timer_create
527 x32 mq_notify compat_sys_mq_notify
528 x32 kexec_load compat_sys_kexec_load
529 x32 waitid compat_sys_waitid
530 x32 set_robust_list compat_sys_set_robust_list
531 x32 get_robust_list compat_sys_get_robust_list
532 x32 vmsplice compat_sys_vmsplice
533 x32 move_pages compat_sys_move_pages
534 x32 preadv compat_sys_preadv64
535 x32 pwritev compat_sys_pwritev64
536 x32 rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
537 x32 recvmmsg compat_sys_recvmmsg
538 x32 sendmmsg compat_sys_sendmmsg
539 x32 process_vm_readv compat_sys_process_vm_readv
540 x32 process_vm_writev compat_sys_process_vm_writev
541 x32 setsockopt compat_sys_setsockopt
542 x32 getsockopt compat_sys_getsockopt
543 x32 io_setup compat_sys_io_setup
544 x32 io_submit compat_sys_io_submit
545 x32 execveat sys_x32_execveat

File diff suppressed because one or more lines are too long

105
x86/tests/ElfX64Linux.hs Normal file
View File

@ -0,0 +1,105 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DataKinds #-}
module ElfX64Linux (
elfX64LinuxTests
) where
import Control.Lens ( (^.) )
import qualified Control.Monad.Catch as C
import qualified Data.ByteString as B
import qualified Data.Foldable as F
import qualified Data.Map as M
import qualified Data.Set as S
import Data.Typeable ( Typeable )
import Data.Word ( Word64 )
import System.FilePath ( dropExtension, replaceExtension )
import qualified Test.Tasty as T
import qualified Test.Tasty.HUnit as T
import Text.Printf ( printf )
import Text.Read ( readMaybe )
import qualified Data.ElfEdit as E
import qualified Data.Parameterized.Some as PU
import qualified Data.Macaw.Memory as MM
import qualified Data.Macaw.Memory.ElfLoader as MM
import qualified Data.Macaw.Discovery as MD
import qualified Data.Macaw.Discovery.State as MD
import qualified Data.Macaw.X86 as RO
elfX64LinuxTests :: [FilePath] -> T.TestTree
elfX64LinuxTests = T.testGroup "ELF x64 Linux" . map mkTest
-- | The type of expected results for test cases
data ExpectedResult =
R { funcs :: [(Word64, [Word64])]
-- ^ The first element of the pair is the address of entry point
-- of the function. The list is a list of the addresses of the
-- basic blocks in the function (including the first block).
, ignoreBlocks :: [Word64]
-- ^ This is a list of discovered blocks to ignore. This is
-- basically just the address of the instruction after the exit
-- syscall, as macaw doesn't know that exit never returns and
-- discovers a false block after exit.
}
deriving (Read, Show, Eq)
mkTest :: FilePath -> T.TestTree
mkTest fp = T.testCase fp $ withELF exeFilename (testDiscovery fp)
where
asmFilename = dropExtension fp
exeFilename = replaceExtension asmFilename "exe"
-- | Run a test over a given expected result filename and the ELF file
-- associated with it
testDiscovery :: FilePath -> E.Elf 64 -> IO ()
testDiscovery expectedFilename elf =
withMemory MM.Addr64 elf $ \mem -> do
let Just entryPoint = MM.absoluteAddrSegment mem (fromIntegral (E.elfEntry elf))
di = MD.cfgFromAddrs RO.x86_64_linux_info mem MD.emptySymbolAddrMap [entryPoint] []
expectedString <- readFile expectedFilename
case readMaybe expectedString of
Nothing -> T.assertFailure ("Invalid expected result: " ++ show expectedString)
Just er -> do
let expectedEntries = M.fromList [ (entry, S.fromList starts) | (entry, starts) <- funcs er ]
ignoredBlocks = S.fromList (ignoreBlocks er)
F.forM_ (M.elems (di ^. MD.funInfo)) $ \(PU.Some dfi) -> do
let actualEntry = fromIntegral (MM.addrValue (MD.discoveredFunAddr dfi))
actualBlockStarts = S.fromList [ fromIntegral (MM.addrValue (MD.blockAddr pbr))
| pbr <- M.elems (dfi ^. MD.parsedBlocks)
]
case (S.member actualEntry ignoredBlocks, M.lookup actualEntry expectedEntries) of
(True, _) -> return ()
(_, Nothing) -> T.assertFailure (printf "Unexpected entry point: 0x%x" actualEntry)
(_, Just expectedBlockStarts) ->
T.assertEqual (printf "Block starts for 0x%x" actualEntry) expectedBlockStarts (actualBlockStarts `S.difference` ignoredBlocks)
withELF :: FilePath -> (E.Elf 64 -> IO ()) -> IO ()
withELF fp k = do
bytes <- B.readFile fp
case E.parseElf bytes of
E.ElfHeaderError off msg ->
error ("Error parsing ELF header at offset " ++ show off ++ ": " ++ msg)
E.Elf32Res [] _e32 -> error "ELF32 is unsupported in the test suite"
E.Elf64Res [] e64 -> k e64
E.Elf32Res errs _ -> error ("Errors while parsing ELF file: " ++ show errs)
E.Elf64Res errs _ -> error ("Errors while parsing ELF file: " ++ show errs)
withMemory :: forall w m a
. (C.MonadThrow m, MM.MemWidth w, Integral (E.ElfWordType w))
=> MM.AddrWidthRepr w
-> E.Elf w
-> (MM.Memory w -> m a)
-> m a
withMemory relaWidth e k =
case MM.memoryForElf (MM.LoadOptions MM.LoadBySegment False) e of
-- case MM.memoryForElfSegments relaWidth e of
Left err -> C.throwM (MemoryLoadError err)
Right (_sim, mem) -> k mem
data ElfException = MemoryLoadError String
deriving (Typeable, Show)
instance C.Exception ElfException

14
x86/tests/Main.hs Normal file
View File

@ -0,0 +1,14 @@
module Main ( main ) where
import System.FilePath.Glob ( namesMatching )
import qualified Test.Tasty as T
import qualified ElfX64Linux as T
main :: IO ()
main = do
x64AsmTests <- namesMatching "tests/x64/*.s.expected"
T.defaultMain $ T.testGroup "ReoptTests" [
T.elfX64LinuxTests x64AsmTests
]

27
x86/tests/README.rst Normal file
View File

@ -0,0 +1,27 @@
This directory contains some automated tests for macaw-x86_.
The macaw tests currently live in this repository because this is
where our x86_64 semantics are defined. Separating those semantics
out is difficult at this point. The tests currently cover the code
discovery implementation in macaw. Specifically, they check:
1) That the correct number of functions are found,
2) Each function starts at the expected address,
3) Each function contains the correct number of basic blocks,
4) Each basic block starts at the expected address
The ``Makefile`` in the tests directory rebuilds the test files from
source. The resulting binaries are checked in to the repository so
that Mac OS users can run the tests without having to have a Linux
build toolchain available. Additionally, having the binaries in the
repository keeps the code layout stable. Expected addresses are
hard-coded into the expected results of the test suite; regenerating
the binaries on a different system or with a different compiler could
change the offsets in the test binaries, which would require the
expected results to be tweaked. This is unfortunate, but difficult to
avoid in a robust way.
Note that the tests are bare-bones and do not link against libc. They
issue the exit system call directly to terminate. This lets us get
small and comprehensible test cases.
.. _macaw-86: https://gitlab-ext.galois.com/macaw/macaw-x86

20
x86/tests/x64/Makefile Normal file
View File

@ -0,0 +1,20 @@
all: $(patsubst %c,%exe, $(wildcard *.c))
# We have a special rule for the tail call test case because we need
# -O2 to convince gcc to emit a tail call, but we'd rather not have
# that much aggressive optimization for the other tests because it
# usually makes them trivial.
test-tail-call.exe: test-tail-call.c
gcc -fno-stack-protector -O2 -fno-inline -S -c $< -o test-tail-call.s
gcc -fno-stack-protector -O2 -fno-inline -nostdlib $< -o $@
%.exe: %.s
gcc -fno-stack-protector -nostdlib $< -o $@
%.s: %.c
gcc -fno-stack-protector -foptimize-sibling-calls -S -c $< -o $@
.PRECIOUS: %.s
clean:
rm *.s *.exe

View File

@ -0,0 +1,11 @@
#include "util.h"
int g = -11;
void _start() {
if(g > 0) {
g = g + 1;
}
EXIT();
}

Binary file not shown.

View File

@ -0,0 +1,42 @@
.file "test2.c"
.globl g
.data
.align 4
.type g, @object
.size g, 4
g:
.long -11
.text
.globl _start
.type _start, @function
_start:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl g(%rip), %eax
testl %eax, %eax
jle .L2
movl g(%rip), %eax
addl $1, %eax
movl %eax, g(%rip)
.L2:
#APP
# 10 "test2.c" 1
movq $60,%rax
movq $0,%rdi
syscall
# 0 "" 2
#NO_APP
nop
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size _start, .-_start
.ident "GCC: (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005"
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,3 @@
R { funcs = [(0x2b1, [0x2b1, 0x2ce, 0x2bf])]
, ignoreBlocks = [0x2de]
}

View File

@ -0,0 +1,27 @@
#include "util.h"
int g1;
int g2;
int g3;
int g4;
int f2() {
return (int)&g2;
}
int f1(long l1, long l2, long l3) {
long i1 = (long)&g1;
i1 = l1 + i1 + l2 + l3;
i1 += l3 * 2;
i1 = i1 / (l2 - 100 + f2());
return (int)i1;
}
void _start() {
long i1 = (long)&g1;
long i2 = (long)&g2;
long i3 = (long)&g3;
g1 = f1(i1, i2, i3);
EXIT();
}

Binary file not shown.

View File

@ -0,0 +1,111 @@
.file "shadow.c"
.comm g1,4,4
.comm g2,4,4
.comm g3,4,4
.comm g4,4,4
.text
.globl f2
.type f2, @function
f2:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq g2(%rip), %rax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size f2, .-f2
.globl f1
.type f1, @function
f1:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
pushq %rbx
subq $40, %rsp
.cfi_offset 3, -24
movq %rdi, -32(%rbp)
movq %rsi, -40(%rbp)
movq %rdx, -48(%rbp)
leaq g1(%rip), %rax
movq %rax, -16(%rbp)
movq -32(%rbp), %rdx
movq -16(%rbp), %rax
addq %rax, %rdx
movq -40(%rbp), %rax
addq %rax, %rdx
movq -48(%rbp), %rax
addq %rdx, %rax
movq %rax, -16(%rbp)
movq -48(%rbp), %rax
addq %rax, %rax
addq %rax, -16(%rbp)
movq -40(%rbp), %rax
leaq -100(%rax), %rbx
movl $0, %eax
call f2
cltq
leaq (%rbx,%rax), %rcx
movq -16(%rbp), %rax
cqto
idivq %rcx
movq %rax, -16(%rbp)
movq -16(%rbp), %rax
addq $40, %rsp
popq %rbx
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size f1, .-f1
.globl _start
.type _start, @function
_start:
.LFB2:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
leaq g1(%rip), %rax
movq %rax, -8(%rbp)
leaq g2(%rip), %rax
movq %rax, -16(%rbp)
leaq g3(%rip), %rax
movq %rax, -24(%rbp)
movq -24(%rbp), %rdx
movq -16(%rbp), %rcx
movq -8(%rbp), %rax
movq %rcx, %rsi
movq %rax, %rdi
call f1
movl %eax, g1(%rip)
#APP
# 25 "shadow.c" 1
movq $60,%rax
movq $0,%rdi
syscall
# 0 "" 2
#NO_APP
nop
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE2:
.size _start, .-_start
.ident "GCC: (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005"
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,6 @@
R { funcs = [ (0x336, [0x336, 0x376])
, (0x2be, [0x2be, 0x318])
, (0x2b1, [0x2b1])
]
, ignoreBlocks = [0x38c]
}

View File

@ -0,0 +1,16 @@
#include "util.h"
int g = -11;
int (*fptr)(int);
int callee(int x) {
return x * 2;
}
void _start() {
fptr = callee;
g = fptr(g);
EXIT();
}

Binary file not shown.

View File

@ -0,0 +1,62 @@
.file "test-indirect-call.c"
.globl g
.data
.align 4
.type g, @object
.size g, 4
g:
.long -11
.comm fptr,8,8
.text
.globl callee
.type callee, @function
callee:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
addl %eax, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size callee, .-callee
.globl _start
.type _start, @function
_start:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq callee(%rip), %rax
movq %rax, fptr(%rip)
movq fptr(%rip), %rax
movl g(%rip), %edx
movl %edx, %edi
call *%rax
movl %eax, g(%rip)
#APP
# 15 "test-indirect-call.c" 1
movq $60,%rax
movq $0,%rdi
syscall
# 0 "" 2
#NO_APP
nop
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size _start, .-_start
.ident "GCC: (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005"
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,5 @@
R { funcs = [ (0x2b1, [0x2b1])
, (0x2bf, [0x2bf, 0x2e2])
]
, ignoreBlocks = [0x2f8]
}

View File

@ -0,0 +1,5 @@
#include "util.h"
void _start() {
EXIT();
}

BIN
x86/tests/x64/test-just-exit.exe Executable file

Binary file not shown.

View File

@ -0,0 +1,28 @@
.file "test1.c"
.text
.globl _start
.type _start, @function
_start:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
#APP
# 4 "test1.c" 1
movq $60,%rax
movq $0,%rdi
syscall
# 0 "" 2
#NO_APP
nop
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size _start, .-_start
.ident "GCC: (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005"
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,3 @@
R { funcs = [(0x2b1, [0x2b1])]
, ignoreBlocks = [0x2c5]
}

View File

@ -0,0 +1,29 @@
/*
This test case makes sure that macaw can find functions only
reachable via tail call.
callee1 issues a tail call to callee2. Note that macaw identifies
callee2 as a function, but also includes its body as a block in
callee1 (so that block appears in two function definitions). That
seems fine.
*/
#include "util.h"
int g = -11;
void callee2(int x) {
g += x;
}
void callee1(int x) {
g += x * 2;
callee2(x);
}
void _start() {
callee1(g);
EXIT();
}

BIN
x86/tests/x64/test-tail-call.exe Executable file

Binary file not shown.

View File

@ -0,0 +1,53 @@
.file "test-tail-call.c"
.text
.p2align 4,,15
.globl callee2
.type callee2, @function
callee2:
.LFB0:
.cfi_startproc
addl %edi, g(%rip)
ret
.cfi_endproc
.LFE0:
.size callee2, .-callee2
.p2align 4,,15
.globl callee1
.type callee1, @function
callee1:
.LFB1:
.cfi_startproc
leal (%rdi,%rdi), %eax
addl %eax, g(%rip)
jmp callee2
.cfi_endproc
.LFE1:
.size callee1, .-callee1
.p2align 4,,15
.globl _start
.type _start, @function
_start:
.LFB2:
.cfi_startproc
movl g(%rip), %edi
call callee1
#APP
# 18 "test-tail-call.c" 1
movq $60,%rax
movq $0,%rdi
syscall
# 0 "" 2
#NO_APP
ret
.cfi_endproc
.LFE2:
.size _start, .-_start
.globl g
.data
.align 4
.type g, @object
.size g, 4
g:
.long -11
.ident "GCC: (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005"
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,6 @@
R { funcs = [ (0x2c0, [0x2c0])
, (0x2d0, [0x2d0, 0x2c0])
, (0x2e0, [0x2e0, 0x2eb])
]
, ignoreBlocks = [0x2fb]
}

4
x86/tests/x64/util.h Normal file
View File

@ -0,0 +1,4 @@
#define EXIT() \
asm("movq $60,%rax\n" \
"movq $0,%rdi\n" \
"syscall")