mirror of
https://github.com/GaloisInc/macaw.git
synced 2024-12-29 00:59:09 +03:00
Remove flexdis86 dependency; use macaw-x86
This commit is contained in:
parent
6e10aaa447
commit
88c4017c3f
@ -1,4 +1,9 @@
|
||||
The macaw library implements architecture-independent binary code discovery. Support for specific architectures is provided by implementing the semantics of that architecture. The library is written in terms of an abstract interface to memory, for which an ELF backend is provided (via the elf-edit_ library). There is also a dependency on flexdis86_, which is an x86_64 disassembler, but that does not tie the discovery algorithm to x86_64. The basic code discovery is based on a variant of Value Set Analysis (VSA).
|
||||
The macaw library implements architecture-independent binary code
|
||||
discovery. Support for specific architectures is provided by
|
||||
implementing the semantics of that architecture. The library is
|
||||
written in terms of an abstract interface to memory, for which an ELF
|
||||
backend is provided (via the elf-edit_ library). The basic code
|
||||
discovery is based on a variant of Value Set Analysis (VSA).
|
||||
|
||||
The most important user-facing abstractions are:
|
||||
|
||||
@ -7,6 +12,8 @@ The most important user-facing abstractions are:
|
||||
* The ``cfgFromAddrs`` function, defined in ``Data.Macaw.Discovery``, which performs code discovery on a ``Memory`` given some initial parameters (semantics to use via ``ArchitectureInfo`` and some entry points.
|
||||
* The ``DiscoveryInfo`` type, which is the result of ``cfgFromAddrs``; it contains a collection of ``DiscoveryFunInfo`` records, each of which represents a discovered function. Every basic block is assigned to at least one function.
|
||||
|
||||
Architecture-specific code goes into separate libraries. X86-specific code is in the macaw-x86 repo.
|
||||
|
||||
An abbreviated example of using macaw on an ELF file looks like::
|
||||
|
||||
import qualified Data.Map as M
|
||||
|
@ -13,7 +13,6 @@ library
|
||||
bytestring,
|
||||
containers >= 0.5.8.1,
|
||||
elf-edit >= 0.28,
|
||||
flexdis86 >= 0.1.1,
|
||||
galois-dwarf,
|
||||
IntervalMap >= 0.5,
|
||||
lens >= 4.7,
|
||||
@ -39,7 +38,6 @@ library
|
||||
Data.Macaw.Dwarf
|
||||
Data.Macaw.Memory
|
||||
Data.Macaw.Memory.ElfLoader
|
||||
Data.Macaw.Memory.Flexdis86
|
||||
Data.Macaw.Memory.Permissions
|
||||
Data.Macaw.Types
|
||||
|
||||
|
@ -1,136 +0,0 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
module Data.Macaw.Memory.Flexdis86
|
||||
( MemoryByteReader
|
||||
, runMemoryByteReader
|
||||
, readInstruction
|
||||
) where
|
||||
|
||||
import Control.Lens
|
||||
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 :: MemStream w -> SegmentedAddr w
|
||||
msStartAddr ms = SegmentedAddr (msSegment ms) (msStart ms)
|
||||
|
||||
msAddr :: MemStream w -> SegmentedAddr w
|
||||
msAddr ms = SegmentedAddr (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 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 :: Integral (MemWord w)
|
||||
=> Perm.Flags
|
||||
-- ^ Permissions that memory accesses are expected to
|
||||
-- satisfy.
|
||||
-- Added so we can check for read and/or execute permission.
|
||||
-> Memory w -- ^ Memory to read from.
|
||||
-> SegmentedAddr w -- ^ Starting address.
|
||||
-> MemoryByteReader w a -- ^ Byte reader to read values from.
|
||||
-> Either (MemoryError w) (a, SegmentedAddr w)
|
||||
runMemoryByteReader reqPerm _mem addr (MBR m) = do
|
||||
let seg = addrSegment addr
|
||||
if not (segmentFlags seg `Perm.hasPerm` reqPerm) then
|
||||
Left $ PermissionsError addr
|
||||
else do
|
||||
contents <- addrContentsAfter addr
|
||||
let ms0 = MS { msSegment = seg
|
||||
, msStart = addr^.addrOffset
|
||||
, msPrev = emptyPrevData
|
||||
, msOffset = addr^.addrOffset
|
||||
, msNext = contents
|
||||
}
|
||||
case runState (runExceptT m) ms0 of
|
||||
(Left e, _) -> Left e
|
||||
(Right v, s) -> Right (v, msAddr s)
|
||||
|
||||
instance Num (MemWord w) => ByteReader (MemoryByteReader w) where
|
||||
readByte = do
|
||||
ms <- MBR get
|
||||
-- If remaining bytes are empty
|
||||
case msNext ms of
|
||||
[] ->
|
||||
MBR $ throwError $ AccessViolation (msAddr ms)
|
||||
RelocatableAddr{}:_ -> do
|
||||
MBR $ throwError $ UnalignedRelocation (msAddr ms)
|
||||
-- Throw error if we try to read a relocation as a symbolic reference
|
||||
SymbolicRef{}:_ -> do
|
||||
MBR $ throwError $ UnalignedRelocation (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 -- Memory to read.
|
||||
-> SegmentedAddr 64 -- Address to read from.
|
||||
-> Either (MemoryError 64)
|
||||
(Flexdis.InstructionInstance, SegmentedAddr 64)
|
||||
readInstruction mem addr = runMemoryByteReader Perm.execute mem addr m
|
||||
where m = Flexdis.disassembleInstruction
|
12
stack.yaml
12
stack.yaml
@ -1,12 +0,0 @@
|
||||
flags: {}
|
||||
packages:
|
||||
- '.'
|
||||
- 'deps/elf-edit'
|
||||
- 'deps/flexdis86'
|
||||
- 'deps/galois-dwarf'
|
||||
- 'deps/parameterized-utils'
|
||||
extra-deps:
|
||||
- containers-0.5.8.1
|
||||
- kan-extensions-5.0.1
|
||||
- lens-4.15.1
|
||||
resolver: lts-6.23
|
Loading…
Reference in New Issue
Block a user