Merge branch 'master' of github.com:GaloisInc/macaw

This commit is contained in:
Iavor Diatchki 2018-01-26 14:43:50 -08:00
commit 5959bfc6f0
12 changed files with 93 additions and 24 deletions

View File

@ -260,6 +260,9 @@ data FoundAddr arch
-- ^ The abstract state formed from post-states that reach this address.
}
foundReasonL :: Lens' (FoundAddr arch) (CodeAddrReason (ArchAddrWidth arch))
foundReasonL = lens foundReason (\old new -> old { foundReason = new })
------------------------------------------------------------------------
-- FunState
@ -291,6 +294,27 @@ curFunBlocks = lens _curFunBlocks (\s v -> s { _curFunBlocks = v })
foundAddrs :: Simple Lens (FunState arch s ids) (Map (ArchSegmentOff arch) (FoundAddr arch))
foundAddrs = lens _foundAddrs (\s v -> s { _foundAddrs = v })
-- | Add a block to the current function blocks. If this overlaps with an
-- existing block, split them so that there's no overlap.
addFunBlock ::
MemWidth (RegAddrWidth (ArchReg arch)) =>
ArchSegmentOff arch ->
ParsedBlock arch ids ->
FunState arch s ids ->
FunState arch s ids
addFunBlock segment block s = case Map.lookupLT segment (s ^. curFunBlocks) of
Just (bSegment, bBlock)
-- very sneaky way to check that they are in the same segment (a
-- Nothing result from diffSegmentOff will never be greater than a
-- Just) and that they are overlapping (the block size is bigger than
-- you'd expect given the address difference)
| diffSegmentOff bSegment segment > Just (-toInteger (blockSize bBlock))
-- put the overlapped segment back in the frontier
-> s & curFunBlocks %~ (Map.insert segment block . Map.delete bSegment)
& foundAddrs.at bSegment._Just.foundReasonL %~ SplitAt segment
& frontier %~ Set.insert bSegment
_ -> s & curFunBlocks %~ Map.insert segment block
type ReverseEdgeMap arch = Map (ArchSegmentOff arch) (Set (ArchSegmentOff arch))
-- | Maps each code address to the list of predecessors that
@ -758,7 +782,8 @@ parseBlock ctx b regs = do
-- | This evalutes the statements in a block to expand the information known
-- about control flow targets of this block.
transferBlocks :: ArchSegmentOff arch
transferBlocks :: MemWidth (RegAddrWidth (ArchReg arch))
=> ArchSegmentOff arch
-- ^ Address of theze blocks
-> FoundAddr arch
-- ^ State leading to explore block
@ -801,7 +826,7 @@ transferBlocks src finfo sz block_map =
, blockAbstractState = foundAbstractState finfo
, blockStatementList = pblock
}
curFunBlocks %= Map.insert src pb
id %= addFunBlock src pb
curFunCtx %= markAddrsAsFunction (InWrite src) (ps^.writtenCodeAddrs)
. markAddrsAsFunction (CallTarget src) (ps^.newFunctionAddrs)
mapM_ (\(addr, abs_state) -> mergeIntraJump src abs_state addr) (ps^.intraJumpTargets)
@ -848,7 +873,7 @@ transfer addr = do
, blockAbstractState = foundAbstractState finfo
, blockStatementList = stmts
}
curFunBlocks %= Map.insert addr pb
id %= addFunBlock addr pb
else do
-- Rewrite returned blocks to simplify expressions

View File

@ -76,8 +76,8 @@ data CodeAddrReason w
-- ^ Identified as an entry point from initial information
| CodePointerInMem !(MemSegmentOff w)
-- ^ A code pointer that was stored at the given address.
| SplitAt !(MemAddr w)
-- ^ Added because the address split this block after it had been disassembled.
| SplitAt !(MemSegmentOff w) !(CodeAddrReason w)
-- ^ Added because the address split this block after it had been disassembled. Also includes the reason we thought the block should be there before we split it.
| UserRequest
-- ^ The user requested that we analyze this address as a function.
deriving (Eq, Show)

View File

@ -27,6 +27,7 @@ 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
@ -34,7 +35,7 @@ elfX64LinuxTests = T.testGroup "ELF x64 Linux" . map mkTest
-- | The type of expected results for test cases
data ExpectedResult =
R { funcs :: [(Word64, [Word64])]
R { funcs :: [(Word64, [(Word64, Integer)])]
-- ^ 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).
@ -57,7 +58,7 @@ mkTest fp = T.testCase fp $ withELF exeFilename (testDiscovery fp)
testDiscovery :: FilePath -> E.Elf 64 -> IO ()
testDiscovery expectedFilename elf =
withMemory MM.Addr64 elf $ \mem -> do
let Just entryPoint = MM.asSegmentOff mem (MM.absoluteAddr (MM.memWord (fromIntegral (E.elfEntry elf))))
let Just entryPoint = MM.asSegmentOff mem (MM.absoluteAddr (MM.memWord (E.elfEntry elf)))
di = MD.cfgFromAddrs RO.x86_64_linux_info mem M.empty [entryPoint] []
expectedString <- readFile expectedFilename
case readMaybe expectedString of
@ -65,17 +66,23 @@ testDiscovery expectedFilename elf =
Just er -> do
let expectedEntries = M.fromList [ (entry, S.fromList starts) | (entry, starts) <- funcs er ]
ignoredBlocks = S.fromList (ignoreBlocks er)
absoluteFromSegOff = fromIntegral . fromJust . MM.asAbsoluteAddr . MM.relativeSegmentAddr
T.assertEqual "Collection of discovered function starting points"
(M.keysSet expectedEntries `S.difference` ignoredBlocks)
(S.map absoluteFromSegOff (M.keysSet (di ^. MD.funInfo)))
F.forM_ (M.elems (di ^. MD.funInfo)) $ \(PU.Some dfi) -> do
let actualEntry = fromIntegral (fromJust (MM.asAbsoluteAddr (MM.relativeSegmentAddr (MD.discoveredFunAddr dfi))))
let actualEntry = absoluteFromSegOff (MD.discoveredFunAddr dfi)
-- actualEntry = fromIntegral (MM.addrValue (MD.discoveredFunAddr dfi))
actualBlockStarts = S.fromList [ fromIntegral (fromJust (MM.asAbsoluteAddr (MM.relativeSegmentAddr (MD.pblockAddr pbr))))
actualBlockStarts = S.fromList [ (addr, toInteger (MD.blockSize pbr))
| pbr <- M.elems (dfi ^. MD.parsedBlocks)
, let addr = absoluteFromSegOff (MD.pblockAddr pbr)
, addr `S.notMember` ignoredBlocks
]
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)
T.assertEqual (printf "Block starts for 0x%x" actualEntry) expectedBlockStarts actualBlockStarts
withELF :: FilePath -> (E.Elf 64 -> IO ()) -> IO ()
withELF fp k = do

View File

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

View File

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

View File

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

View File

@ -0,0 +1,13 @@
#include "util.h"
void _start() {
long long x;
here:
// This makes an instruction with a short 0x90 nop slide.
x = 0x9090909090909090;
// The +4 is completely ignored by gcc. You have to modify the assembly by
// hand after compiling to make this jump into the middle of an emitted
// instruction.
goto *(&&here + 4);
EXIT();
}

Binary file not shown.

View File

@ -0,0 +1,22 @@
.file "test-jump-into-instruction.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
.L2:
movabsq $-8029759185026510704, %rax
movq %rax, -8(%rbp)
nop
jmp .L2+4
.cfi_endproc
.LFE0:
.size _start, .-_start
.ident "GCC: (GNU) 7.2.1 20170915 (Red Hat 7.2.1-2)"
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,3 @@
R { funcs = [(0x400144, [(0x400144, 14), (0x40014c, 6), (0x400152, 7)])]
, ignoreBlocks = []
}

View File

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

View File

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