mirror of
https://github.com/GaloisInc/macaw.git
synced 2024-12-25 07:02:59 +03:00
Merge remote-tracking branch 'origin/master' into mem-model
# Conflicts: # base/src/Data/Macaw/Memory/ElfLoader.hs
This commit is contained in:
commit
2e21856afe
@ -82,6 +82,9 @@ data App (f :: Type -> *) (tp :: Type) where
|
|||||||
-- Multiply two numbers
|
-- Multiply two numbers
|
||||||
BVMul :: (1 <= n) => !(NatRepr n) -> !(f (BVType n)) -> !(f (BVType n)) -> App f (BVType n)
|
BVMul :: (1 <= n) => !(NatRepr n) -> !(f (BVType n)) -> !(f (BVType n)) -> App f (BVType n)
|
||||||
|
|
||||||
|
-- Divide two numbers and get the remainder (i.e. mod)
|
||||||
|
BVUrem :: (1 <= n) => !(NatRepr n) -> !(f (BVType n)) -> !(f (BVType n)) -> App f (BVType n)
|
||||||
|
|
||||||
-- Unsigned less than or equal.
|
-- Unsigned less than or equal.
|
||||||
BVUnsignedLe :: (1 <= n) => !(f (BVType n)) -> !(f (BVType n)) -> App f BoolType
|
BVUnsignedLe :: (1 <= n) => !(f (BVType n)) -> !(f (BVType n)) -> App f BoolType
|
||||||
|
|
||||||
@ -261,6 +264,7 @@ ppAppA pp a0 =
|
|||||||
BVSub _ x y -> sexprA "bv_sub" [ pp x, pp y ]
|
BVSub _ x y -> sexprA "bv_sub" [ pp x, pp y ]
|
||||||
BVSbb _ x y b -> sexprA "bv_sbb" [ pp x, pp y, pp b ]
|
BVSbb _ x y b -> sexprA "bv_sbb" [ pp x, pp y, pp b ]
|
||||||
BVMul _ x y -> sexprA "bv_mul" [ pp x, pp y ]
|
BVMul _ x y -> sexprA "bv_mul" [ pp x, pp y ]
|
||||||
|
BVUrem _ x y -> sexprA "bv_urem" [ pp x, pp y ]
|
||||||
BVUnsignedLt x y -> sexprA "bv_ult" [ pp x, pp y ]
|
BVUnsignedLt x y -> sexprA "bv_ult" [ pp x, pp y ]
|
||||||
BVUnsignedLe x y -> sexprA "bv_ule" [ pp x, pp y ]
|
BVUnsignedLe x y -> sexprA "bv_ule" [ pp x, pp y ]
|
||||||
BVSignedLt x y -> sexprA "bv_slt" [ pp x, pp y ]
|
BVSignedLt x y -> sexprA "bv_slt" [ pp x, pp y ]
|
||||||
@ -312,6 +316,7 @@ instance HasRepr (App f) TypeRepr where
|
|||||||
BVSub w _ _ -> BVTypeRepr w
|
BVSub w _ _ -> BVTypeRepr w
|
||||||
BVSbb w _ _ _ -> BVTypeRepr w
|
BVSbb w _ _ _ -> BVTypeRepr w
|
||||||
BVMul w _ _ -> BVTypeRepr w
|
BVMul w _ _ -> BVTypeRepr w
|
||||||
|
BVUrem w _ _ -> BVTypeRepr w
|
||||||
|
|
||||||
BVUnsignedLt{} -> knownRepr
|
BVUnsignedLt{} -> knownRepr
|
||||||
BVUnsignedLe{} -> knownRepr
|
BVUnsignedLe{} -> knownRepr
|
||||||
|
@ -608,7 +608,13 @@ ppLit w i
|
|||||||
-- | Pretty print a value.
|
-- | Pretty print a value.
|
||||||
ppValue :: RegisterInfo (ArchReg arch) => Prec -> Value arch ids tp -> Doc
|
ppValue :: RegisterInfo (ArchReg arch) => Prec -> Value arch ids tp -> Doc
|
||||||
ppValue _ (BoolValue b) = text $ if b then "true" else "false"
|
ppValue _ (BoolValue b) = text $ if b then "true" else "false"
|
||||||
ppValue p (BVValue w i) = assert (i >= 0) $ parenIf (p > colonPrec) $ ppLit w i
|
ppValue p (BVValue w i)
|
||||||
|
| i >= 0 = parenIf (p > colonPrec) $ ppLit w i
|
||||||
|
| otherwise =
|
||||||
|
-- TODO: We may want to report an error here.
|
||||||
|
parenIf (p > colonPrec) $
|
||||||
|
text (show i) <+> text "::" <+> brackets (text (show w))
|
||||||
|
|
||||||
ppValue p (RelocatableValue _ a) = parenIf (p > plusPrec) $ text (show a)
|
ppValue p (RelocatableValue _ a) = parenIf (p > plusPrec) $ text (show a)
|
||||||
ppValue _ (AssignedValue a) = ppAssignId (assignId a)
|
ppValue _ (AssignedValue a) = ppAssignId (assignId a)
|
||||||
ppValue _ (Initial r) = text (showF r) PP.<> text "_0"
|
ppValue _ (Initial r) = text (showF r) PP.<> text "_0"
|
||||||
|
@ -39,6 +39,12 @@ module Data.Macaw.Discovery
|
|||||||
, Data.Macaw.Discovery.analyzeFunction
|
, Data.Macaw.Discovery.analyzeFunction
|
||||||
, Data.Macaw.Discovery.exploreMemPointers
|
, Data.Macaw.Discovery.exploreMemPointers
|
||||||
, Data.Macaw.Discovery.analyzeDiscoveredFunctions
|
, Data.Macaw.Discovery.analyzeDiscoveredFunctions
|
||||||
|
-- * Top level utilities
|
||||||
|
, Data.Macaw.Discovery.completeDiscoveryState
|
||||||
|
, DiscoveryOptions(..)
|
||||||
|
, defaultDiscoveryOptions
|
||||||
|
, DiscoveryEvent(..)
|
||||||
|
, discoveryLogFn
|
||||||
-- * DiscoveryFunInfo
|
-- * DiscoveryFunInfo
|
||||||
, State.DiscoveryFunInfo
|
, State.DiscoveryFunInfo
|
||||||
, State.discoveredFunAddr
|
, State.discoveredFunAddr
|
||||||
@ -73,6 +79,8 @@ import qualified Data.Set as Set
|
|||||||
import qualified Data.Text as Text
|
import qualified Data.Text as Text
|
||||||
import qualified Data.Vector as V
|
import qualified Data.Vector as V
|
||||||
import Data.Word
|
import Data.Word
|
||||||
|
import GHC.IO (ioToST, stToIO)
|
||||||
|
import System.IO
|
||||||
|
|
||||||
import Debug.Trace
|
import Debug.Trace
|
||||||
|
|
||||||
@ -298,12 +306,12 @@ foundAddrs = lens _foundAddrs (\s v -> s { _foundAddrs = v })
|
|||||||
|
|
||||||
-- | Add a block to the current function blocks. If this overlaps with an
|
-- | Add a block to the current function blocks. If this overlaps with an
|
||||||
-- existing block, split them so that there's no overlap.
|
-- existing block, split them so that there's no overlap.
|
||||||
addFunBlock ::
|
addFunBlock
|
||||||
MemWidth (RegAddrWidth (ArchReg arch)) =>
|
:: MemWidth (RegAddrWidth (ArchReg arch))
|
||||||
ArchSegmentOff arch ->
|
=> ArchSegmentOff arch
|
||||||
ParsedBlock arch ids ->
|
-> ParsedBlock arch ids
|
||||||
FunState arch s ids ->
|
-> FunState arch s ids
|
||||||
FunState arch s ids
|
-> FunState arch s ids
|
||||||
addFunBlock segment block s = case Map.lookupLT segment (s ^. curFunBlocks) of
|
addFunBlock segment block s = case Map.lookupLT segment (s ^. curFunBlocks) of
|
||||||
Just (bSegment, bBlock)
|
Just (bSegment, bBlock)
|
||||||
-- very sneaky way to check that they are in the same segment (a
|
-- very sneaky way to check that they are in the same segment (a
|
||||||
@ -350,7 +358,8 @@ liftST = FunM . lift
|
|||||||
|
|
||||||
-- | Joins in the new abstract state and returns the locations for
|
-- | Joins in the new abstract state and returns the locations for
|
||||||
-- which the new state is changed.
|
-- which the new state is changed.
|
||||||
mergeIntraJump :: ArchSegmentOff arch
|
mergeIntraJump :: MemWidth (ArchAddrWidth arch)
|
||||||
|
=> ArchSegmentOff arch
|
||||||
-- ^ Source label that we are jumping from.
|
-- ^ Source label that we are jumping from.
|
||||||
-> AbsBlockState (ArchReg arch)
|
-> AbsBlockState (ArchReg arch)
|
||||||
-- ^ The state of the system after jumping to new block.
|
-- ^ The state of the system after jumping to new block.
|
||||||
@ -358,6 +367,7 @@ mergeIntraJump :: ArchSegmentOff arch
|
|||||||
-- ^ Address we are trying to reach.
|
-- ^ Address we are trying to reach.
|
||||||
-> FunM arch s ids ()
|
-> FunM arch s ids ()
|
||||||
mergeIntraJump src ab tgt = do
|
mergeIntraJump src ab tgt = do
|
||||||
|
-- trace ("mergeIntraJump " ++ show src ++ " " ++ show tgt) $ do
|
||||||
info <- uses curFunCtx archInfo
|
info <- uses curFunCtx archInfo
|
||||||
withArchConstraints info $ do
|
withArchConstraints info $ do
|
||||||
when (not (absStackHasReturnAddr ab)) $ do
|
when (not (absStackHasReturnAddr ab)) $ do
|
||||||
@ -1006,7 +1016,7 @@ cfgFromAddrs, cfgFromAddrsTrustFns ::
|
|||||||
-> Memory (ArchAddrWidth arch)
|
-> Memory (ArchAddrWidth arch)
|
||||||
-- ^ Memory to use when decoding instructions.
|
-- ^ Memory to use when decoding instructions.
|
||||||
-> AddrSymMap (ArchAddrWidth arch)
|
-> AddrSymMap (ArchAddrWidth arch)
|
||||||
-- ^ Ma1p from addresses to the associated symbol name.
|
-- ^ Map from addresses to the associated symbol name.
|
||||||
-> [ArchSegmentOff arch]
|
-> [ArchSegmentOff arch]
|
||||||
-- ^ Initial function entry points.
|
-- ^ Initial function entry points.
|
||||||
-> [(ArchSegmentOff arch, ArchSegmentOff arch)]
|
-> [(ArchSegmentOff arch, ArchSegmentOff arch)]
|
||||||
@ -1031,3 +1041,133 @@ cfgFromAddrsWorker initial_state init_addrs mem_words =
|
|||||||
& analyzeDiscoveredFunctions
|
& analyzeDiscoveredFunctions
|
||||||
& exploreMemPointers mem_words
|
& exploreMemPointers mem_words
|
||||||
& analyzeDiscoveredFunctions
|
& analyzeDiscoveredFunctions
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- Resolve functions with logging
|
||||||
|
|
||||||
|
resolveFuns :: MemWidth (RegAddrWidth (ArchReg arch))
|
||||||
|
=> (ArchSegmentOff arch -> CodeAddrReason (ArchAddrWidth arch) -> ST s Bool)
|
||||||
|
-- ^ Callback for discovered functions
|
||||||
|
--
|
||||||
|
-- Should return true if we should analyze the function and false otherwise.
|
||||||
|
-> (ArchSegmentOff arch -> ArchSegmentOff arch -> ST s ())
|
||||||
|
-- ^ Callback for logging blocks discovered within function
|
||||||
|
-- Arguments include the address of function and address of block.
|
||||||
|
-> DiscoveryState arch
|
||||||
|
-> ST s (DiscoveryState arch)
|
||||||
|
resolveFuns analyzeFun analyzeBlock info = seq info $
|
||||||
|
case Map.minViewWithKey (info^.unexploredFunctions) of
|
||||||
|
Nothing -> pure info
|
||||||
|
Just ((addr, rsn), rest) -> do
|
||||||
|
p <- analyzeFun addr rsn
|
||||||
|
if p then do
|
||||||
|
(info',_) <- analyzeFunction (analyzeBlock addr) addr rsn info
|
||||||
|
resolveFuns analyzeFun analyzeBlock info'
|
||||||
|
else
|
||||||
|
resolveFuns analyzeFun analyzeBlock (info & unexploredFunctions .~ rest)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- Top-level discovery
|
||||||
|
|
||||||
|
-- | Options controlling 'completeDiscoveryState'.
|
||||||
|
data DiscoveryOptions
|
||||||
|
= DiscoveryOptions { exploreFunctionSymbols :: !Bool
|
||||||
|
-- ^ If @True@, 'completeDiscoveryState'
|
||||||
|
-- should automatically explore all addresses
|
||||||
|
-- in the address-to-symbol map.
|
||||||
|
, exploreCodeAddrInMem :: !Bool
|
||||||
|
-- ^ If @True@, 'completeDiscoveryState' will
|
||||||
|
-- explore all potential code addresses in
|
||||||
|
-- memory after exploring other potnetial
|
||||||
|
-- functions.
|
||||||
|
, logAtAnalyzeFunction :: !Bool
|
||||||
|
-- ^ Print a message each time we apply
|
||||||
|
-- discovery analysis to a new function.
|
||||||
|
, logAtAnalyzeBlock :: !Bool
|
||||||
|
-- ^ Print a message each time we analyze a
|
||||||
|
-- block within a function.
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultDiscoveryOptions :: DiscoveryOptions
|
||||||
|
defaultDiscoveryOptions =
|
||||||
|
DiscoveryOptions { exploreFunctionSymbols = True
|
||||||
|
, exploreCodeAddrInMem = False
|
||||||
|
, logAtAnalyzeFunction = True
|
||||||
|
, logAtAnalyzeBlock = False
|
||||||
|
}
|
||||||
|
|
||||||
|
ppSymbol :: MemWidth w => MemSegmentOff w -> AddrSymMap w -> String
|
||||||
|
ppSymbol addr sym_map =
|
||||||
|
case Map.lookup addr sym_map of
|
||||||
|
Just fnName -> show addr ++ " (" ++ BSC.unpack fnName ++ ")"
|
||||||
|
Nothing -> show addr
|
||||||
|
|
||||||
|
-- | Event for logging function
|
||||||
|
data DiscoveryEvent w
|
||||||
|
= AnalyzeFunction !(MemSegmentOff w)
|
||||||
|
| AnalyzeBlock !(MemSegmentOff w)
|
||||||
|
|
||||||
|
{-# DEPRECATED discoveryLogFn "02/17/2018 Stop using this" #-}
|
||||||
|
|
||||||
|
-- | Print out discovery event using options and address to symbol map.
|
||||||
|
discoveryLogFn :: MemWidth w
|
||||||
|
=> DiscoveryOptions
|
||||||
|
-> AddrSymMap w
|
||||||
|
-> DiscoveryEvent w
|
||||||
|
-> ST RealWorld ()
|
||||||
|
discoveryLogFn disOpt symMap (AnalyzeFunction addr) = ioToST $ do
|
||||||
|
when (logAtAnalyzeFunction disOpt) $ do
|
||||||
|
hPutStrLn stderr $ "Analyzing function: " ++ ppSymbol addr symMap
|
||||||
|
hFlush stderr
|
||||||
|
discoveryLogFn disOpt _ (AnalyzeBlock addr) = ioToST $ do
|
||||||
|
when (logAtAnalyzeBlock disOpt) $ do
|
||||||
|
hPutStrLn stderr $ " Analyzing block: " ++ show addr
|
||||||
|
|
||||||
|
hFlush stderr
|
||||||
|
|
||||||
|
-- | Explore until we have found all functions we can.
|
||||||
|
--
|
||||||
|
-- This function is intended to make it easy to explore functions, and
|
||||||
|
-- can be controlled via 'DiscoveryOptions'.
|
||||||
|
completeDiscoveryState :: forall arch
|
||||||
|
. ArchitectureInfo arch
|
||||||
|
-> DiscoveryOptions
|
||||||
|
-- ^ Options controlling discovery
|
||||||
|
-> Memory (ArchAddrWidth arch)
|
||||||
|
-- ^ Memory state used for static code discovery.
|
||||||
|
-> [MemSegmentOff (ArchAddrWidth arch)]
|
||||||
|
-- ^ Initial entry points to explore
|
||||||
|
-> AddrSymMap (ArchAddrWidth arch)
|
||||||
|
-- ^ The map from addresses to symbols
|
||||||
|
-> (ArchSegmentOff arch -> Bool)
|
||||||
|
-- ^ Predicate to check if we should explore a function
|
||||||
|
--
|
||||||
|
-- Return true to explore all functions.
|
||||||
|
-> IO (DiscoveryState arch)
|
||||||
|
completeDiscoveryState ainfo disOpt mem initEntries symMap funPred = stToIO $ withArchConstraints ainfo $ do
|
||||||
|
let initState
|
||||||
|
= emptyDiscoveryState mem symMap ainfo
|
||||||
|
& markAddrsAsFunction InitAddr initEntries
|
||||||
|
-- Add symbol table entries to discovery state if requested
|
||||||
|
let postSymState
|
||||||
|
| exploreFunctionSymbols disOpt =
|
||||||
|
initState & markAddrsAsFunction InitAddr (Map.keys symMap)
|
||||||
|
| otherwise = initState
|
||||||
|
let analyzeFn addr _rsn = ioToST $ do
|
||||||
|
let b = funPred addr
|
||||||
|
when (b && logAtAnalyzeFunction disOpt) $ do
|
||||||
|
hPutStrLn stderr $ "Analyzing function: " ++ ppSymbol addr symMap
|
||||||
|
hFlush stderr
|
||||||
|
pure $! b
|
||||||
|
let analyzeBlock _ addr = ioToST $ do
|
||||||
|
when (logAtAnalyzeBlock disOpt) $ do
|
||||||
|
hPutStrLn stderr $ " Analyzing block: " ++ show addr
|
||||||
|
hFlush stderr
|
||||||
|
-- Discover functions
|
||||||
|
postPhase1Discovery <- resolveFuns analyzeFn analyzeBlock postSymState
|
||||||
|
-- Discovery functions from memory
|
||||||
|
if exploreCodeAddrInMem disOpt then do
|
||||||
|
let mem_contents = withArchConstraints ainfo $ memAsAddrPairs mem LittleEndian
|
||||||
|
resolveFuns analyzeFn analyzeBlock $ postPhase1Discovery & exploreMemPointers mem_contents
|
||||||
|
else
|
||||||
|
return postPhase1Discovery
|
||||||
|
@ -320,13 +320,13 @@ emptyDiscoveryState mem symbols info =
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- | Map each jump table start to the address just after the end.
|
-- | Map each jump table start to the address just after the end.
|
||||||
globalDataMap :: Simple Lens (DiscoveryState arch)
|
globalDataMap
|
||||||
(Map (ArchMemAddr arch) (GlobalDataInfo (ArchMemAddr arch)))
|
:: Simple Lens (DiscoveryState arch) (Map (ArchMemAddr arch) (GlobalDataInfo (ArchMemAddr arch)))
|
||||||
globalDataMap = lens _globalDataMap (\s v -> s { _globalDataMap = v })
|
globalDataMap = lens _globalDataMap (\s v -> s { _globalDataMap = v })
|
||||||
|
|
||||||
-- | List of functions to explore next.
|
-- | List of functions to explore next.
|
||||||
unexploredFunctions :: Simple Lens (DiscoveryState arch)
|
unexploredFunctions
|
||||||
(Map (ArchSegmentOff arch) (CodeAddrReason (ArchAddrWidth arch)))
|
:: Simple Lens (DiscoveryState arch) (Map (ArchSegmentOff arch) (CodeAddrReason (ArchAddrWidth arch)))
|
||||||
unexploredFunctions = lens _unexploredFunctions (\s v -> s { _unexploredFunctions = v })
|
unexploredFunctions = lens _unexploredFunctions (\s v -> s { _unexploredFunctions = v })
|
||||||
|
|
||||||
-- | Get information for specific functions
|
-- | Get information for specific functions
|
||||||
|
@ -69,6 +69,7 @@ module Data.Macaw.Memory
|
|||||||
, memAsAddrPairs
|
, memAsAddrPairs
|
||||||
-- * Symbols
|
-- * Symbols
|
||||||
, SymbolRef(..)
|
, SymbolRef(..)
|
||||||
|
, SymbolVisibility(..)
|
||||||
, SymbolVersion(..)
|
, SymbolVersion(..)
|
||||||
-- * General purposes addrs
|
-- * General purposes addrs
|
||||||
, MemAddr
|
, MemAddr
|
||||||
@ -287,6 +288,9 @@ instance MemWidth w => Integral (MemWord w) where
|
|||||||
where (q,r) = x `quotRem` y
|
where (q,r) = x `quotRem` y
|
||||||
toInteger (MemWord x) = toInteger x
|
toInteger (MemWord x) = toInteger x
|
||||||
|
|
||||||
|
instance MemWidth w => Bounded (MemWord w) where
|
||||||
|
minBound = 0
|
||||||
|
maxBound = MemWord (addrWidthMod (Proxy :: Proxy w))
|
||||||
|
|
||||||
instance MemWidth 32 where
|
instance MemWidth 32 where
|
||||||
addrWidthRepr _ = Addr32
|
addrWidthRepr _ = Addr32
|
||||||
@ -325,9 +329,19 @@ data SymbolVersion = SymbolVersion { symbolVersionFile :: !BS.ByteString
|
|||||||
, symbolVersionName :: !BS.ByteString
|
, symbolVersionName :: !BS.ByteString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- | Information about the visibility of a symbol within a binary.
|
||||||
|
data SymbolVisibility
|
||||||
|
= LocalSymbol
|
||||||
|
-- ^ Th symbol is only visible within the module
|
||||||
|
| GlobalSymbol
|
||||||
|
-- ^ The symbol is globally visible to all modules
|
||||||
|
| VersionedSymbol !SymbolVersion
|
||||||
|
-- ^ The symbol is visible with the specific version associated
|
||||||
|
|
||||||
|
|
||||||
-- | The name of a symbol along with optional version information.
|
-- | The name of a symbol along with optional version information.
|
||||||
data SymbolRef = SymbolRef { symbolName :: !BS.ByteString
|
data SymbolRef = SymbolRef { symbolName :: !BS.ByteString
|
||||||
, symbolVersion :: !(Maybe SymbolVersion)
|
, symbolVisibility :: !SymbolVisibility
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | Defines a portion of a segment.
|
-- | Defines a portion of a segment.
|
||||||
@ -352,37 +366,6 @@ instance Show (SegmentRange w) where
|
|||||||
showList [] = id
|
showList [] = id
|
||||||
showList (h : r) = showsPrec 10 h . showList r
|
showList (h : r) = showsPrec 10 h . showList r
|
||||||
|
|
||||||
data DropError
|
|
||||||
= DropUnexpectedRelocation
|
|
||||||
| DropInvalidAddr
|
|
||||||
|
|
||||||
dropErrorAsMemError :: MemAddr w -> DropError -> MemoryError w
|
|
||||||
dropErrorAsMemError a DropUnexpectedRelocation = UnexpectedRelocation a
|
|
||||||
dropErrorAsMemError a DropInvalidAddr = InvalidAddr a
|
|
||||||
|
|
||||||
-- | Given a contiguous list of segment ranges and a number of bytes to drop, this
|
|
||||||
-- returns the remaining segment ranges or throws an error.
|
|
||||||
dropSegmentRangeListBytes :: forall w
|
|
||||||
. MemWidth w
|
|
||||||
=> [SegmentRange w]
|
|
||||||
-> Int
|
|
||||||
-> Either DropError [SegmentRange w]
|
|
||||||
dropSegmentRangeListBytes ranges 0 = Right ranges
|
|
||||||
dropSegmentRangeListBytes (ByteRegion bs : rest) cnt = do
|
|
||||||
let sz = BS.length bs
|
|
||||||
if sz > cnt then
|
|
||||||
Right $ ByteRegion (BS.drop cnt bs) : rest
|
|
||||||
else
|
|
||||||
dropSegmentRangeListBytes rest (cnt - sz)
|
|
||||||
dropSegmentRangeListBytes (SymbolicRef _:rest) cnt = do
|
|
||||||
let sz = addrSize (error "rangeSize nat evaluated" :: NatRepr w)
|
|
||||||
if sz > cnt then
|
|
||||||
Left DropUnexpectedRelocation
|
|
||||||
else
|
|
||||||
dropSegmentRangeListBytes rest (cnt - sz)
|
|
||||||
dropSegmentRangeListBytes [] _ =
|
|
||||||
Left DropInvalidAddr
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- SegmentContents
|
-- SegmentContents
|
||||||
|
|
||||||
@ -441,7 +424,7 @@ data MemSegment w
|
|||||||
--
|
--
|
||||||
-- N.B. 0 indicates a fixed base address of zero.
|
-- N.B. 0 indicates a fixed base address of zero.
|
||||||
, segmentOffset :: !(MemWord w)
|
, segmentOffset :: !(MemWord w)
|
||||||
-- ^ Offset of segment to base
|
-- ^ Offset of segment relative to segmentBase
|
||||||
, segmentFlags :: !Perm.Flags
|
, segmentFlags :: !Perm.Flags
|
||||||
-- ^ Permisison flags
|
-- ^ Permisison flags
|
||||||
, segmentContents :: !(SegmentContents w)
|
, segmentContents :: !(SegmentContents w)
|
||||||
@ -450,10 +433,11 @@ data MemSegment w
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- | Create a memory segment with the given values.
|
-- | Create a memory segment with the given values.
|
||||||
memSegment :: MemWidth w
|
memSegment :: forall w
|
||||||
|
. MemWidth w
|
||||||
=> RegionIndex
|
=> RegionIndex
|
||||||
-- ^ Index of base (0=absolute address)
|
-- ^ Index of base (0=absolute address)
|
||||||
-> MemWord w
|
-> Integer
|
||||||
-- ^ Offset of segment
|
-- ^ Offset of segment
|
||||||
-> Perm.Flags
|
-> Perm.Flags
|
||||||
-- ^ Flags if defined
|
-- ^ Flags if defined
|
||||||
@ -462,11 +446,11 @@ memSegment :: MemWidth w
|
|||||||
-> MemSegment w
|
-> MemSegment w
|
||||||
memSegment base off flags contentsl
|
memSegment base off flags contentsl
|
||||||
-- Check for overflow in contents end
|
-- Check for overflow in contents end
|
||||||
| off + contentsSize contents < off =
|
| off + toInteger (contentsSize contents) > toInteger (maxBound :: MemWord w) =
|
||||||
error "Contents two large for base."
|
error "Contents two large for base."
|
||||||
| otherwise =
|
| otherwise =
|
||||||
MemSegment { segmentBase = base
|
MemSegment { segmentBase = base
|
||||||
, segmentOffset = off
|
, segmentOffset = fromInteger off
|
||||||
, segmentFlags = flags
|
, segmentFlags = flags
|
||||||
, segmentContents = contents
|
, segmentContents = contents
|
||||||
}
|
}
|
||||||
@ -599,9 +583,10 @@ resolveSegmentOff seg off
|
|||||||
|
|
||||||
-- | Return the absolute address associated with the segment offset pair (if any)
|
-- | Return the absolute address associated with the segment offset pair (if any)
|
||||||
msegAddr :: MemWidth w => MemSegmentOff w -> Maybe (MemWord w)
|
msegAddr :: MemWidth w => MemSegmentOff w -> Maybe (MemWord w)
|
||||||
msegAddr (MemSegmentOff seg off) =
|
msegAddr mseg = do
|
||||||
if segmentBase seg == 0 then
|
let seg = msegSegment mseg
|
||||||
Just (segmentOffset seg + off)
|
in if segmentBase seg == 0 then
|
||||||
|
Just (segmentOffset seg + msegOffset mseg)
|
||||||
else
|
else
|
||||||
Nothing
|
Nothing
|
||||||
|
|
||||||
@ -680,13 +665,13 @@ data MemAddr w
|
|||||||
|
|
||||||
-- | Given an absolute address, this returns a segment and offset into the segment.
|
-- | Given an absolute address, this returns a segment and offset into the segment.
|
||||||
absoluteAddr :: MemWord w -> MemAddr w
|
absoluteAddr :: MemWord w -> MemAddr w
|
||||||
absoluteAddr = MemAddr 0
|
absoluteAddr o = MemAddr { addrBase = 0, addrOffset = o }
|
||||||
|
|
||||||
-- | Construct an address relative to an existing memory segment.
|
-- | Construct an address relative to an existing memory segment.
|
||||||
relativeAddr :: MemWidth w => MemSegment w -> MemWord w -> MemAddr w
|
relativeAddr :: MemWidth w => MemSegment w -> MemWord w -> MemAddr w
|
||||||
relativeAddr seg off = MemAddr (segmentBase seg) (segmentOffset seg + off)
|
relativeAddr seg off = MemAddr { addrBase = segmentBase seg, addrOffset = segmentOffset seg + off }
|
||||||
|
|
||||||
-- | Return the address associated with a memory segment.
|
-- | Convert the segment offset to an address.
|
||||||
relativeSegmentAddr :: MemWidth w => MemSegmentOff w -> MemAddr w
|
relativeSegmentAddr :: MemWidth w => MemSegmentOff w -> MemAddr w
|
||||||
relativeSegmentAddr (MemSegmentOff seg off) = relativeAddr seg off
|
relativeSegmentAddr (MemSegmentOff seg off) = relativeAddr seg off
|
||||||
|
|
||||||
@ -735,6 +720,41 @@ instance MemWidth w => Pretty (MemAddr w) where
|
|||||||
-- | Maps code addresses to the associated symbol name if any.
|
-- | Maps code addresses to the associated symbol name if any.
|
||||||
type AddrSymMap w = Map.Map (MemSegmentOff w) BSC.ByteString
|
type AddrSymMap w = Map.Map (MemSegmentOff w) BSC.ByteString
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- DropError
|
||||||
|
|
||||||
|
-- | An error that occured when droping byes.
|
||||||
|
data DropError
|
||||||
|
= DropUnexpectedRelocation
|
||||||
|
| DropInvalidAddr
|
||||||
|
|
||||||
|
dropErrorAsMemError :: MemAddr w -> DropError -> MemoryError w
|
||||||
|
dropErrorAsMemError a DropUnexpectedRelocation = UnexpectedRelocation a
|
||||||
|
dropErrorAsMemError a DropInvalidAddr = InvalidAddr a
|
||||||
|
|
||||||
|
-- | Given a contiguous list of segment ranges and a number of bytes to drop, this
|
||||||
|
-- returns the remaining segment ranges or throws an error.
|
||||||
|
dropSegmentRangeListBytes :: forall w
|
||||||
|
. MemWidth w
|
||||||
|
=> [SegmentRange w]
|
||||||
|
-> Int
|
||||||
|
-> Either DropError [SegmentRange w]
|
||||||
|
dropSegmentRangeListBytes ranges 0 = Right ranges
|
||||||
|
dropSegmentRangeListBytes (ByteRegion bs : rest) cnt = do
|
||||||
|
let sz = BS.length bs
|
||||||
|
if sz > cnt then
|
||||||
|
Right $ ByteRegion (BS.drop cnt bs) : rest
|
||||||
|
else
|
||||||
|
dropSegmentRangeListBytes rest (cnt - sz)
|
||||||
|
dropSegmentRangeListBytes (SymbolicRef _:rest) cnt = do
|
||||||
|
let sz = addrSize (error "rangeSize nat evaluated" :: NatRepr w)
|
||||||
|
if sz > cnt then
|
||||||
|
Left DropUnexpectedRelocation
|
||||||
|
else
|
||||||
|
dropSegmentRangeListBytes rest (cnt - sz)
|
||||||
|
dropSegmentRangeListBytes [] _ =
|
||||||
|
Left DropInvalidAddr
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- MemoryError
|
-- MemoryError
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ import Data.Map.Strict (Map)
|
|||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import qualified Data.Vector as V
|
import qualified Data.Vector as V
|
||||||
|
import Numeric (showHex)
|
||||||
|
|
||||||
import Data.Macaw.Memory
|
import Data.Macaw.Memory
|
||||||
import Data.Macaw.Memory.LoadCommon
|
import Data.Macaw.Memory.LoadCommon
|
||||||
@ -114,6 +115,19 @@ flagsForSectionFlags f =
|
|||||||
where flagIf :: ElfSectionFlags w -> Perm.Flags -> Perm.Flags
|
where flagIf :: ElfSectionFlags w -> Perm.Flags -> Perm.Flags
|
||||||
flagIf ef pf = if f `Elf.hasPermissions` ef then pf else Perm.none
|
flagIf ef pf = if f `Elf.hasPermissions` ef then pf else Perm.none
|
||||||
|
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
-- RegionAdjust
|
||||||
|
|
||||||
|
-- | This captures how to translate addresses in the Elf file to
|
||||||
|
-- regions in the memory object.
|
||||||
|
data RegionAdjust
|
||||||
|
= RegionAdjust { regionIndex :: !RegionIndex
|
||||||
|
-- ^ Region index for new segments
|
||||||
|
, regionOffset :: !Integer
|
||||||
|
-- ^ Offset from region to automatically add to
|
||||||
|
-- segment/sections during loading.
|
||||||
|
}
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- Loading by segment
|
-- Loading by segment
|
||||||
|
|
||||||
@ -157,7 +171,7 @@ padBSSData incBSS dta sz
|
|||||||
|
|
||||||
-- | Return a memory segment for elf segment if it loadable.
|
-- | Return a memory segment for elf segment if it loadable.
|
||||||
memSegmentForElfSegment :: (MemWidth w, Integral (ElfWordType w))
|
memSegmentForElfSegment :: (MemWidth w, Integral (ElfWordType w))
|
||||||
=> RegionIndex -- ^ Index for segment
|
=> RegionAdjust -- ^ Index for segment
|
||||||
-> IncludeBSS -- ^ Flag to control wheter we include BSS
|
-> IncludeBSS -- ^ Flag to control wheter we include BSS
|
||||||
-> L.ByteString
|
-> L.ByteString
|
||||||
-- ^ Complete contents of Elf file.
|
-- ^ Complete contents of Elf file.
|
||||||
@ -166,14 +180,16 @@ memSegmentForElfSegment :: (MemWidth w, Integral (ElfWordType w))
|
|||||||
-> Elf.Phdr w
|
-> Elf.Phdr w
|
||||||
-- ^ Program header entry
|
-- ^ Program header entry
|
||||||
-> MemSegment w
|
-> MemSegment w
|
||||||
memSegmentForElfSegment regIdx incBSS contents relocMap phdr = mseg
|
memSegmentForElfSegment regAdj incBSS contents relocMap phdr = mseg
|
||||||
where seg = Elf.phdrSegment phdr
|
where seg = Elf.phdrSegment phdr
|
||||||
dta = sliceL (Elf.phdrFileRange phdr) contents
|
dta = sliceL (Elf.phdrFileRange phdr) contents
|
||||||
sz = fromIntegral $ Elf.phdrMemSize phdr
|
sz = fromIntegral $ Elf.phdrMemSize phdr
|
||||||
fixedData = padBSSData incBSS dta sz
|
fixedData = padBSSData incBSS dta sz
|
||||||
addr = fromIntegral $ elfSegmentVirtAddr seg
|
addr = regionOffset regAdj + toInteger (elfSegmentVirtAddr seg)
|
||||||
flags = flagsForSegmentFlags (elfSegmentFlags seg)
|
flags = flagsForSegmentFlags (elfSegmentFlags seg)
|
||||||
mseg = memSegment regIdx addr flags (byteSegments relocMap addr fixedData)
|
segContents = byteSegments relocMap (fromInteger addr) fixedData
|
||||||
|
mseg = memSegment (regionIndex regAdj) addr flags segContents
|
||||||
|
|
||||||
|
|
||||||
-- | Create memory segment from elf section.
|
-- | Create memory segment from elf section.
|
||||||
--
|
--
|
||||||
@ -196,8 +212,7 @@ memSegmentForElfSection regIdx incBSS s
|
|||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- MemLoader
|
-- MemLoader
|
||||||
|
|
||||||
data MemLoaderState w = MLS { mlsRegionIndex :: !RegionIndex
|
data MemLoaderState w = MLS { mlsRegionAdjust :: !RegionAdjust
|
||||||
-- ^ Region index for new segments
|
|
||||||
, mlsIncludeBSS :: !Bool
|
, mlsIncludeBSS :: !Bool
|
||||||
-- ^ Flag whether to include BSS
|
-- ^ Flag whether to include BSS
|
||||||
, _mlsMemory :: !(Memory w)
|
, _mlsMemory :: !(Memory w)
|
||||||
@ -216,9 +231,9 @@ memLoaderPair mls = (mls^.mlsIndexMap, mls^.mlsMemory)
|
|||||||
|
|
||||||
type MemLoader w = StateT (MemLoaderState w) (Except String)
|
type MemLoader w = StateT (MemLoaderState w) (Except String)
|
||||||
|
|
||||||
runMemLoader :: RegionIndex -> Bool -> Memory w -> MemLoader w () -> Either String (SectionIndexMap w, Memory w)
|
runMemLoader :: RegionAdjust -> Bool -> Memory w -> MemLoader w () -> Either String (SectionIndexMap w, Memory w)
|
||||||
runMemLoader regIdx incBSS mem m = fmap memLoaderPair $ runExcept $ execStateT m s
|
runMemLoader regAdj incBSS mem m = fmap memLoaderPair $ runExcept $ execStateT m s
|
||||||
where s = MLS { mlsRegionIndex = regIdx
|
where s = MLS { mlsRegionAdjust = regAdj
|
||||||
, mlsIncludeBSS = incBSS
|
, mlsIncludeBSS = incBSS
|
||||||
, _mlsMemory = mem
|
, _mlsMemory = mem
|
||||||
, _mlsIndexMap = Map.empty
|
, _mlsIndexMap = Map.empty
|
||||||
@ -250,7 +265,11 @@ mkSymbolVersion ver = SymbolVersion { symbolVersionFile = Elf.verFile ver
|
|||||||
mkSymbolRef :: Elf.VersionedSymbol tp -> SymbolRef
|
mkSymbolRef :: Elf.VersionedSymbol tp -> SymbolRef
|
||||||
mkSymbolRef (sym, mverId) =
|
mkSymbolRef (sym, mverId) =
|
||||||
SymbolRef { symbolName = Elf.steName sym
|
SymbolRef { symbolName = Elf.steName sym
|
||||||
, symbolVersion = mkSymbolVersion <$> mverId
|
, symbolVisibility =
|
||||||
|
case mverId of
|
||||||
|
Elf.VersionLocal -> LocalSymbol
|
||||||
|
Elf.VersionGlobal -> GlobalSymbol
|
||||||
|
Elf.VersionSpecific verId -> VersionedSymbol (mkSymbolVersion verId)
|
||||||
}
|
}
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
@ -273,13 +292,13 @@ relaSymbol symtab rel =
|
|||||||
Nothing -> Left $ "Could not find symbol at index " ++ show (Elf.r_sym rel) ++ "."
|
Nothing -> Left $ "Could not find symbol at index " ++ show (Elf.r_sym rel) ++ "."
|
||||||
Just sym -> Right sym
|
Just sym -> Right sym
|
||||||
|
|
||||||
|
-- | Creates a map that forwards addresses to be relocated to their appropriate target.
|
||||||
|
type RelaTargetFn tp = V.Vector SymbolRef -> Elf.RelaEntry tp -> Either String (Maybe SymbolRef)
|
||||||
|
|
||||||
-- | Given a relocation entry, this returns either @Left msg@ if the relocation
|
-- | Given a relocation entry, this returns either @Left msg@ if the relocation
|
||||||
-- cannot be resolved, @Right Nothing@ if
|
-- cannot be resolved, @Right Nothing@ if
|
||||||
relaTarget :: V.Vector SymbolRef
|
relaTargetX86_64 :: RelaTargetFn Elf.X86_64_RelocationType
|
||||||
-- ^ Get c
|
relaTargetX86_64 symtab rel =
|
||||||
-> Elf.RelaEntry Elf.X86_64_RelocationType
|
|
||||||
-> Either String (Maybe SymbolRef)
|
|
||||||
relaTarget symtab rel =
|
|
||||||
case Elf.r_type rel of
|
case Elf.r_type rel of
|
||||||
Elf.R_X86_64_GLOB_DAT -> do
|
Elf.R_X86_64_GLOB_DAT -> do
|
||||||
checkZeroAddend rel
|
checkZeroAddend rel
|
||||||
@ -290,13 +309,28 @@ relaTarget symtab rel =
|
|||||||
Just <$> relaSymbol symtab rel
|
Just <$> relaSymbol symtab rel
|
||||||
tp -> Left $ "Do not yet support relocation type: " ++ show tp
|
tp -> Left $ "Do not yet support relocation type: " ++ show tp
|
||||||
|
|
||||||
relocEntry :: V.Vector SymbolRef
|
relaTargetARM :: RelaTargetFn Elf.ARM_RelocationType
|
||||||
-> Elf.RelaEntry Elf.X86_64_RelocationType
|
relaTargetARM symtab rel =
|
||||||
-> Either String (Maybe (MemWord 64, SymbolRef))
|
case Elf.r_type rel of
|
||||||
relocEntry symtab rel = fmap (fmap f) $ relaTarget symtab rel
|
Elf.R_ARM_GLOB_DAT -> do
|
||||||
where f :: SymbolRef -> (MemWord 64, SymbolRef)
|
checkZeroAddend rel
|
||||||
f tgt = (memWord (Elf.r_offset rel), tgt)
|
Just <$> relaSymbol symtab rel
|
||||||
|
Elf.R_ARM_COPY -> Right Nothing
|
||||||
|
Elf.R_ARM_JUMP_SLOT -> do
|
||||||
|
checkZeroAddend rel
|
||||||
|
Just <$> relaSymbol symtab rel
|
||||||
|
tp -> Left $ "Do not yet support relocation type: " ++ show tp
|
||||||
|
|
||||||
|
--(Elf.IsRelocationType tp, MemWidth (Elf.RelocationWidth tp), Integral (Elf.RelocationWord tp))
|
||||||
|
-- =>
|
||||||
|
-- | Creates a map that forwards addresses to be relocated to their appropriate target.
|
||||||
|
relocEntry :: (MemWidth (Elf.RelocationWidth tp), Integral (Elf.RelocationWord tp))
|
||||||
|
=> RelaTargetFn tp
|
||||||
|
-> V.Vector SymbolRef
|
||||||
|
-> Elf.RelaEntry tp
|
||||||
|
-> Either String (Maybe (MemWord (Elf.RelocationWidth tp), SymbolRef))
|
||||||
|
relocEntry relaTarget symtab rel = fmap (fmap f) $ relaTarget symtab rel
|
||||||
|
where f tgt = (memWord (fromIntegral (Elf.r_offset rel)), tgt)
|
||||||
|
|
||||||
-- Given a list returns a map mapping keys to their associated values, or
|
-- Given a list returns a map mapping keys to their associated values, or
|
||||||
-- a key that appears in multiple elements.
|
-- a key that appears in multiple elements.
|
||||||
@ -308,33 +342,46 @@ mapFromListUnique = foldlM f Map.empty
|
|||||||
Just _ -> Left k
|
Just _ -> Left k
|
||||||
|
|
||||||
-- | Creates a map that forwards addresses to be relocated to their appropriate target.
|
-- | Creates a map that forwards addresses to be relocated to their appropriate target.
|
||||||
mkRelocMap :: V.Vector SymbolRef
|
mkRelocMap :: ( Elf.IsRelocationType tp
|
||||||
-> [Elf.RelaEntry Elf.X86_64_RelocationType]
|
, MemWidth (Elf.RelocationWidth tp)
|
||||||
-> Either String (RelocMap (MemWord 64))
|
, Integral (Elf.RelocationWord tp)
|
||||||
mkRelocMap symtab l = do
|
)
|
||||||
mentries <- traverse (relocEntry symtab) l
|
=> RelaTargetFn tp
|
||||||
|
-> V.Vector SymbolRef
|
||||||
|
-> [Elf.RelaEntry tp]
|
||||||
|
-> Either String (RelocMap (MemWord (Elf.RelocationWidth tp)))
|
||||||
|
mkRelocMap relaTarget symtab l = do
|
||||||
|
mentries <- traverse (relocEntry relaTarget symtab) l
|
||||||
let errMsg w = show w ++ " appears in multiple relocations."
|
let errMsg w = show w ++ " appears in multiple relocations."
|
||||||
case mapFromListUnique $ catMaybes mentries of
|
case mapFromListUnique $ catMaybes mentries of
|
||||||
Left dup -> Left (errMsg dup)
|
Left dup -> Left (errMsg dup)
|
||||||
Right v -> Right v
|
Right v -> Right v
|
||||||
|
|
||||||
-- | Creates a relocation map from the contents of a dynamic section.
|
-- | Creates a relocation map from the contents of a dynamic section.
|
||||||
relocMapOfDynamic :: Elf.ElfHeader w
|
relocMapOfDynamic :: forall w
|
||||||
|
. (MemWidth w, Integral (ElfWordType w))
|
||||||
|
=> Elf.ElfHeader w
|
||||||
-> Elf.VirtAddrMap w
|
-> Elf.VirtAddrMap w
|
||||||
-> L.ByteString -- ^ Contents of .dynamic section
|
-> L.ByteString -- ^ Contents of .dynamic section
|
||||||
-> MemLoader w (RelocMap (MemWord w))
|
-> MemLoader w (RelocMap (MemWord w))
|
||||||
relocMapOfDynamic hdr virtMap dynContents =
|
relocMapOfDynamic hdr virtMap dynContents =
|
||||||
case (Elf.headerClass hdr, Elf.headerMachine hdr) of
|
case (Elf.headerClass hdr, Elf.headerMachine hdr) of
|
||||||
(Elf.ELFCLASS64, Elf.EM_X86_64) -> do
|
(Elf.ELFCLASS64, Elf.EM_X86_64) -> go relaTargetX86_64
|
||||||
|
(Elf.ELFCLASS32, Elf.EM_ARM) -> go relaTargetARM
|
||||||
|
(_,mach) -> throwError $ "Dynamic libraries are not supported on " ++ show mach ++ "."
|
||||||
|
where go :: forall tp
|
||||||
|
. (Elf.IsRelocationType tp, w ~ Elf.RelocationWidth tp)
|
||||||
|
=> RelaTargetFn tp
|
||||||
|
-> MemLoader (Elf.RelocationWidth tp) (RelocMap (MemWord (Elf.RelocationWidth tp)))
|
||||||
|
go relaTarget = do
|
||||||
dynSection <- either (throwError . show) pure $
|
dynSection <- either (throwError . show) pure $
|
||||||
Elf.dynamicEntries (Elf.headerData hdr) Elf.ELFCLASS64 virtMap dynContents
|
Elf.dynamicEntries (Elf.headerData hdr) (Elf.headerClass hdr) virtMap dynContents
|
||||||
relocs <- either (throwError . show) pure $
|
relocs <- either (throwError . show) pure $
|
||||||
Elf.dynRelocations (dynSection :: Elf.DynamicSection Elf.X86_64_RelocationType)
|
Elf.dynRelocations dynSection
|
||||||
syms <- either (throwError . show) pure $
|
syms <- either (throwError . show) pure $
|
||||||
Elf.dynSymTable dynSection
|
Elf.dynSymTable dynSection
|
||||||
either throwError pure $
|
either throwError pure $
|
||||||
mkRelocMap (mkSymbolRef <$> syms) relocs
|
mkRelocMap relaTarget (mkSymbolRef <$> syms) relocs
|
||||||
(_,mach) -> throwError $ "Dynamic libraries are not supported on " ++ show mach ++ "."
|
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- Elf segment loading
|
-- Elf segment loading
|
||||||
@ -353,11 +400,11 @@ insertElfSegment :: ElfFileSectionMap (ElfWordType w)
|
|||||||
-> Elf.Phdr w
|
-> Elf.Phdr w
|
||||||
-> MemLoader w ()
|
-> MemLoader w ()
|
||||||
insertElfSegment shdrMap contents relocMap phdr = do
|
insertElfSegment shdrMap contents relocMap phdr = do
|
||||||
regIdx <- gets mlsRegionIndex
|
regAdj <- gets mlsRegionAdjust
|
||||||
incBSS <- gets mlsIncludeBSS
|
incBSS <- gets mlsIncludeBSS
|
||||||
w <- uses mlsMemory memAddrWidth
|
w <- uses mlsMemory memAddrWidth
|
||||||
reprConstraints w $ do
|
reprConstraints w $ do
|
||||||
let seg = memSegmentForElfSegment regIdx incBSS contents relocMap phdr
|
let seg = memSegmentForElfSegment regAdj incBSS contents relocMap phdr
|
||||||
let seg_idx = elfSegmentIndex (Elf.phdrSegment phdr)
|
let seg_idx = elfSegmentIndex (Elf.phdrSegment phdr)
|
||||||
loadMemSegment ("Segment " ++ show seg_idx) seg
|
loadMemSegment ("Segment " ++ show seg_idx) seg
|
||||||
let phdr_offset = Elf.fromFileOffset (Elf.phdrFileStart phdr)
|
let phdr_offset = Elf.fromFileOffset (Elf.phdrFileStart phdr)
|
||||||
@ -413,13 +460,14 @@ memoryForElfSegments e = do
|
|||||||
insertElfSection :: ElfSection (ElfWordType w)
|
insertElfSection :: ElfSection (ElfWordType w)
|
||||||
-> MemLoader w ()
|
-> MemLoader w ()
|
||||||
insertElfSection sec = do
|
insertElfSection sec = do
|
||||||
regIdx <- gets mlsRegionIndex
|
regAdj <- mlsRegionAdjust <$> get
|
||||||
incBSS <- gets mlsIncludeBSS
|
incBSS <- gets mlsIncludeBSS
|
||||||
w <- uses mlsMemory memAddrWidth
|
w <- uses mlsMemory memAddrWidth
|
||||||
reprConstraints w $ do
|
reprConstraints w $ do
|
||||||
-- Check if we should load section
|
-- Check if we should load section
|
||||||
let doLoad = elfSectionFlags sec `Elf.hasPermissions` Elf.shf_alloc
|
let doLoad = elfSectionFlags sec `Elf.hasPermissions` Elf.shf_alloc
|
||||||
&& elfSectionName sec /= ".eh_frame"
|
&& elfSectionName sec /= ".eh_frame"
|
||||||
|
let regIdx = regionIndex regAdj
|
||||||
case memSegmentForElfSection regIdx incBSS sec of
|
case memSegmentForElfSection regIdx incBSS sec of
|
||||||
Just seg | doLoad -> do
|
Just seg | doLoad -> do
|
||||||
loadMemSegment ("Section " ++ BSC.unpack (elfSectionName sec) ++ " " ++ show (Elf.elfSectionSize sec)) seg
|
loadMemSegment ("Section " ++ BSC.unpack (elfSectionName sec) ++ " " ++ show (Elf.elfSectionSize sec)) seg
|
||||||
@ -473,8 +521,10 @@ memoryForElf :: LoadOptions
|
|||||||
-> Elf w
|
-> Elf w
|
||||||
-> Either String (SectionIndexMap w, Memory w)
|
-> Either String (SectionIndexMap w, Memory w)
|
||||||
memoryForElf opt e = do
|
memoryForElf opt e = do
|
||||||
let regIdx = adjustedLoadRegionIndex e opt
|
let regAdj = RegionAdjust { regionIndex = adjustedLoadRegionIndex e opt
|
||||||
runMemLoader regIdx (includeBSS opt) (emptyMemory (elfAddrWidth (elfClass e))) $ do
|
, regionOffset = loadRegionBaseOffset opt
|
||||||
|
}
|
||||||
|
runMemLoader regAdj (includeBSS opt) (emptyMemory (elfAddrWidth (elfClass e))) $ do
|
||||||
case adjustedLoadStyle e opt of
|
case adjustedLoadStyle e opt of
|
||||||
LoadBySection -> memoryForElfSections e
|
LoadBySection -> memoryForElfSections e
|
||||||
LoadBySegment -> memoryForElfSegments e
|
LoadBySegment -> memoryForElfSegments e
|
||||||
@ -559,12 +609,17 @@ resolveElfFuncSymbols mem secMap e =
|
|||||||
-- initElfDiscoveryInfo
|
-- initElfDiscoveryInfo
|
||||||
|
|
||||||
-- | Return the segment offset of the elf file entry point or fail if undefined.
|
-- | Return the segment offset of the elf file entry point or fail if undefined.
|
||||||
getElfEntry :: Memory w -> Elf w -> Either String (MemSegmentOff w)
|
getElfEntry :: LoadOptions -> Memory w -> Elf w -> ([String], Maybe (MemSegmentOff w))
|
||||||
getElfEntry mem e = addrWidthClass (memAddrWidth mem) $ do
|
getElfEntry loadOpts mem e = addrWidthClass (memAddrWidth mem) $ do
|
||||||
Elf.elfClassInstances (Elf.elfClass e) $ do
|
Elf.elfClassInstances (Elf.elfClass e) $ do
|
||||||
case resolveAbsoluteAddr mem (fromIntegral (Elf.elfEntry e)) of
|
let regIdx = adjustedLoadRegionIndex e loadOpts
|
||||||
Nothing -> Left "Could not resolve entry"
|
let adjAddr = loadRegionBaseOffset loadOpts + toInteger (Elf.elfEntry e)
|
||||||
Just v -> Right v
|
case resolveAddr mem regIdx (fromInteger adjAddr) of
|
||||||
|
Nothing ->
|
||||||
|
( ["Could not resolve entry point: " ++ showHex (Elf.elfEntry e) ""]
|
||||||
|
, Nothing
|
||||||
|
)
|
||||||
|
Just v -> ([], Just v)
|
||||||
|
|
||||||
-- | This interprets the Elf file to construct the initial memory,
|
-- | This interprets the Elf file to construct the initial memory,
|
||||||
-- entry points, and functions symbols.
|
-- entry points, and functions symbols.
|
||||||
@ -592,14 +647,14 @@ initElfDiscoveryInfo loadOpts e = do
|
|||||||
pure (show <$> symErrs, mem, Nothing, funcSymbols)
|
pure (show <$> symErrs, mem, Nothing, funcSymbols)
|
||||||
Elf.ET_EXEC -> do
|
Elf.ET_EXEC -> do
|
||||||
(secMap, mem) <- memoryForElf loadOpts e
|
(secMap, mem) <- memoryForElf loadOpts e
|
||||||
entry <- getElfEntry mem e
|
let (entryWarn, mentry) = getElfEntry loadOpts mem e
|
||||||
let (symErrs, funcSymbols) = resolveElfFuncSymbols mem secMap e
|
let (symErrs, funcSymbols) = resolveElfFuncSymbols mem secMap e
|
||||||
Right (show <$> symErrs, mem, Just entry, funcSymbols)
|
Right (entryWarn ++ fmap show symErrs, mem, mentry, funcSymbols)
|
||||||
Elf.ET_DYN -> do
|
Elf.ET_DYN -> do
|
||||||
(secMap, mem) <- memoryForElf loadOpts e
|
(secMap, mem) <- memoryForElf loadOpts e
|
||||||
entry <- getElfEntry mem e
|
let (entryWarn, mentry) = getElfEntry loadOpts mem e
|
||||||
let (symErrs, funcSymbols) = resolveElfFuncSymbols mem secMap e
|
let (symErrs, funcSymbols) = resolveElfFuncSymbols mem secMap e
|
||||||
pure (show <$> symErrs, mem, Just entry, funcSymbols)
|
pure (entryWarn ++ fmap show symErrs, mem, mentry, funcSymbols)
|
||||||
Elf.ET_CORE -> do
|
Elf.ET_CORE -> do
|
||||||
Left $ "Reopt does not support loading core files."
|
Left $ "Reopt does not support loading core files."
|
||||||
tp -> do
|
tp -> do
|
||||||
|
@ -6,6 +6,7 @@ Common datatypes for creating a memory from a binary file.
|
|||||||
-}
|
-}
|
||||||
module Data.Macaw.Memory.LoadCommon
|
module Data.Macaw.Memory.LoadCommon
|
||||||
( LoadOptions(..)
|
( LoadOptions(..)
|
||||||
|
, defaultLoadOptions
|
||||||
, LoadStyle(..)
|
, LoadStyle(..)
|
||||||
) where
|
) where
|
||||||
|
|
||||||
@ -34,6 +35,12 @@ data LoadOptions
|
|||||||
--
|
--
|
||||||
-- If 'Nothing' then static executables have region index 0 and other
|
-- If 'Nothing' then static executables have region index 0 and other
|
||||||
-- files have region index 1.
|
-- files have region index 1.
|
||||||
|
, loadRegionBaseOffset :: !Integer
|
||||||
|
-- ^ Increment to automatically add to segment/section memory offsets
|
||||||
|
-- when loading.
|
||||||
|
--
|
||||||
|
-- This defaults to '0', and is primarily intended to allow loading
|
||||||
|
-- relocatable files at specific hard-coded offsets.
|
||||||
, loadStyleOverride :: !(Maybe LoadStyle)
|
, loadStyleOverride :: !(Maybe LoadStyle)
|
||||||
-- ^ Controls whether to load by section or segment
|
-- ^ Controls whether to load by section or segment
|
||||||
--
|
--
|
||||||
@ -41,3 +48,12 @@ data LoadOptions
|
|||||||
, includeBSS :: !Bool
|
, includeBSS :: !Bool
|
||||||
-- ^ Include data not backed by file when creating memory segments.
|
-- ^ Include data not backed by file when creating memory segments.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- | Default options for loading
|
||||||
|
defaultLoadOptions :: LoadOptions
|
||||||
|
defaultLoadOptions =
|
||||||
|
LoadOptions { loadRegionIndex = Nothing
|
||||||
|
, loadRegionBaseOffset = 0
|
||||||
|
, loadStyleOverride = Nothing
|
||||||
|
, includeBSS = False
|
||||||
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit b3f95f1da846bb6f6b44ed5f033d07b6fb1759a6
|
Subproject commit 8c4fe6e4e625d5c98b31dd79a31a5b391f7a738f
|
Loading…
Reference in New Issue
Block a user