Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: rewrite some jump tables #30

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
cabal.project
stack.yaml
dist-newstyle
dist
*.DS_STORE
46 changes: 46 additions & 0 deletions refurbish/tests/binaries/test-switch-jump-table.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "util.h"

int gin = 1;
int g0 = 0;
int g1;
int g2;
int g3;
int g4;

int res;

long mod_5(long n, long i0, long i1, long i2, long i3, long i4){
beginning:
switch(n)
{
case 0: res = res + i0; break;
case 1: res = res + i1; break;
case 2: res = res + i2; break;
case 3: res = res + i3; break;
case 4: res = res + i4; break;
default: n = n - 5; goto beginning;
}
}


void entry() {
long in = (long)&gin;
long i0 = (long)&g0;
long i1 = (long)&g1;
long i2 = (long)&g2;
long i3 = (long)&g3;
long i4 = (long)&g4;
res = mod_5(gin, i0, i1, i2, i3, i4);
}

#if defined(NOSTDLIB)
void _start() {
entry();
EXIT(0);
}
#else
int main() {
entry();
return 0;
}
#endif
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
8 changes: 8 additions & 0 deletions renovate-ppc/src/Renovate/Arch/PPC/ISA.hs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ isa =
, R.isaMakeSymbolicJump = ppcMakeSymbolicJump
, R.isaConcretizeAddresses = ppcConcretizeAddresses
, R.isaSymbolizeAddresses = ppcSymbolizeAddresses
, R.isaSymbolizeLookupJump = ppcSymbolizeLookupJump
}

ppcPrettyInstruction :: Instruction a -> String
Expand Down Expand Up @@ -151,6 +152,13 @@ ppcMakeSymbolicJump symAddr = [R.tagInstruction (Just symAddr) i]
jmp = D.Instruction D.B (D.Directbrtarget (D.BT 0) D.:< D.Nil)
i = annotateInstr (fromInst jmp) NoAddress


ppcSymbolizeLookupJump ::
R.SymbolicLookupTableInfo arch
-> Maybe [R.TaggedInstruction arch (TargetAddress arch)]
ppcSymbolizeLookupJump _ = Nothing -- not implemented yet


-- | This function converts symbolic address references in operands back to
-- concrete values. As with 'ppcSymbolizeAddresses', it is a no-op on PowerPC.
ppcConcretizeAddresses :: (MM.MemWidth (MM.ArchAddrWidth arch))
Expand Down
1 change: 1 addition & 0 deletions renovate-x86/renovate-x86.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ library
-- other-extensions:
build-depends: base >=4.10 && <5,
bytestring,
vector,
flexdis86 >=0.1.4,
macaw-x86,
macaw-x86-symbolic,
Expand Down
46 changes: 45 additions & 1 deletion renovate-x86/src/Renovate/Arch/X86_64/ISA.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- | The 'ISA' for x86_64
module Renovate.Arch.X86_64.ISA (
isa,
Expand All @@ -13,6 +14,7 @@ import qualified GHC.Err.Located as L

import qualified Control.Monad.Catch as C
import Data.Bits ( bit )
import qualified Data.Vector as Vec
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy.Builder as B
import qualified Data.ByteString.Lazy as LB
Expand All @@ -23,10 +25,15 @@ import qualified Data.List.NonEmpty as DLN
import Data.Maybe
import Data.Parameterized.Some
import Data.Parameterized.NatRepr
import Data.Parameterized.Classes ( testEquality )
import Data.Parameterized.Pair ( Pair(..) )
import qualified Data.Parameterized.Map as MapF

import qualified Data.Text.Prettyprint.Doc as PD
import Data.Word ( Word8, Word64 )

import qualified Data.Macaw.Memory as MM
import qualified Data.Macaw.CFG as MC
import qualified Data.Macaw.Types as MT
import qualified Data.Macaw.X86 as X86
import qualified Flexdis86 as D
Expand Down Expand Up @@ -78,7 +85,8 @@ isa = R.ISA
, R.isaStoreImmediate = x86StoreImmediate
, R.isaAddImmediate = x86AddImmediate
, R.isaSubtractImmediate = x86SubtractImmediate
}
, R.isaSymbolizeLookupJump = x64SymbolizeLookupJump
}

x86StackAddress :: R.StackAddress X86.X86_64 -> (Some MT.TypeRepr) -> Value
x86StackAddress addr (Some tp) = do
Expand Down Expand Up @@ -432,6 +440,42 @@ x64SymbolizeAddresses mem _lookup insnAddr mSymbolicTarget xi@(XI ii)
jmpInstr = XI (jmpInstr0 { D.iiArgs = fmap (saveAbsoluteRipAddresses mem insnAddr xi) (D.iiArgs jmpInstr0) })



x64SymbolizeLookupJump ::
R.SymbolicLookupTableInfo X86.X86_64
-> Maybe [R.TaggedInstruction X86.X86_64 TargetAddress]
x64SymbolizeLookupJump R.SymbolicLookupTableInfo
{ R.symbolicLookupRegs = regState
, R.symbolicLookupIdx = rawIdx
, R.symbolicLookupAddrs = tgts
} =
case mapMaybe computeJumpInsns regs of
[insns] -> Just insns
_ -> Nothing
where
regs = MapF.toList $ MC.regStateMap regState
n = Vec.length tgts
computeJumpInsns (Pair idxReg v)
| Just Refl <- testEquality v rawIdx
, X86.X86_GP idxGpReg <- idxReg =
Just $ concat $
[ [ cmpIdx -- cmp i idx
, jmpTgt -- je target[i]
]
| i <- [0..n-2]
, let iTgt = tgts Vec.! i
cmpIdx =
R.tagInstruction Nothing
$ noAddr
$ makeInstr
"cmp" [ D.QWordReg idxGpReg
, D.DWordSignedImm (fromIntegral i)
]
jmpTgt = x64MakeSymbolicJumpOrCall "je" iTgt
] -- otherwise just jump to the final target
++ [[x64MakeSymbolicJumpOrCall "jmp" (tgts Vec.! (n-1))]]
| otherwise = Nothing

saveAbsoluteRipAddresses :: MM.Memory 64 -> R.ConcreteAddress X86.X86_64 -> Instruction () -> AnnotatedOperand () -> AnnotatedOperand TargetAddress
saveAbsoluteRipAddresses mem insnAddr i AnnotatedOperand { aoOperand = (v, ty) } =
AnnotatedOperand { aoOperand = (I.runIdentity (mapAddrRef promoteRipDisp8 I.Identity v), ty)
Expand Down
1 change: 1 addition & 0 deletions renovate/src/Renovate.hs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ module Renovate
A.concreteFromAbsolute,
A.addressAddOffset,
A.addressDiff,
A.SymbolicLookupTableInfo(..),
-- * Analysis
-- ** Function Recovery
FR.recoverFunctions,
Expand Down
16 changes: 15 additions & 1 deletion renovate/src/Renovate/Address.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ExistentialQuantification #-}
-- | This module defines opaque concrete and symbolic address types.
module Renovate.Address (
SymbolicAddress(..),
Expand All @@ -11,13 +12,15 @@ module Renovate.Address (
concreteAsSegmentOff,
absoluteAddress,
addressAddOffset,
addressDiff
addressDiff,
SymbolicLookupTableInfo(..)
) where

import qualified GHC.Err.Located as L

import qualified Data.Text.Prettyprint.Doc as PD
import Data.Word ( Word64 )
import Data.Vector ( Vector )
import qualified Numeric as N

import qualified Data.Macaw.Memory as MM
Expand Down Expand Up @@ -126,3 +129,14 @@ addressDiff :: (MM.MemWidth (MM.ArchAddrWidth arch)) => ConcreteAddress arch ->
addressDiff (ConcreteAddress memAddr1) (ConcreteAddress memAddr2) = diff
where
Just diff = MM.diffAddr memAddr1 memAddr2


-- | Stores the jump-table lookup info found in Macaw's
-- @ParsedLookupTable@ so we can unpack in each backend and
-- rewrite the jumps.
data SymbolicLookupTableInfo arch =
forall ids . SymbolicLookupTableInfo
{ symbolicLookupRegs :: MM.RegState (MM.ArchReg arch) (MM.Value arch ids)
, symbolicLookupIdx :: MM.ArchAddrValue arch ids
, symbolicLookupAddrs :: Vector (SymbolicAddress arch)
}
1 change: 1 addition & 0 deletions renovate/src/Renovate/BasicBlock/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import qualified SemMC.Architecture as SA

import Renovate.Address


-- | The type of instructions for an architecture
--
-- Instructions are parameterized by an annotation type that is usually either
Expand Down
19 changes: 18 additions & 1 deletion renovate/src/Renovate/ISA.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ import qualified Data.Macaw.CFG as MM
import qualified Data.Macaw.Types as MT

import Renovate.Address
import Renovate.BasicBlock.Types ( ConcreteFallthrough, Instruction, InstructionAnnotation, RegisterType, TaggedInstruction )
import Renovate.BasicBlock.Types ( ConcreteFallthrough
, Instruction
, InstructionAnnotation
, RegisterType
, TaggedInstruction
)

-- | The variety of a jump: either conditional or unconditional. This
-- is used as a tag for 'JumpType's. One day, we could model the type
Expand Down Expand Up @@ -98,6 +103,18 @@ data ISA arch = ISA
-- has the worst case size behavior.
, isaConcretizeAddresses :: MM.Memory (MM.ArchAddrWidth arch) -> ConcreteAddress arch -> Instruction arch (InstructionAnnotation arch) -> Instruction arch ()
-- ^ Remove the annotation, with possible post-processing.


, isaSymbolizeLookupJump ::
SymbolicLookupTableInfo arch
-> Maybe [TaggedInstruction arch (InstructionAnnotation arch)]
-- ^ Attempts to return a series of instructions which
-- mimic a jump-table-lookup indirect jump (described by
-- the given @SymbolicLookupTableInfo@) via a series of
-- comparisons and direct jumps. This allows the related
-- blocks to be safely relocated and the corresponding
-- jumps can be updated to reflect the new location(s).

, isaJumpType :: forall t . Instruction arch t -> MM.Memory (MM.ArchAddrWidth arch) -> ConcreteAddress arch -> JumpType arch
-- ^ Test if an instruction is a jump; if it is, return some
-- metadata about the jump (destination or offset).
Expand Down
32 changes: 24 additions & 8 deletions renovate/src/Renovate/Redirect.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
-- | This module is the entry point for binary code redirection
module Renovate.Redirect (
redirect,
Expand Down Expand Up @@ -31,10 +32,13 @@ import qualified Data.List as L
import qualified Data.List.NonEmpty as DLN
import Data.Ord ( comparing )
import qualified Data.Traversable as T
import Data.Parameterized.Some

import Prelude

import qualified Data.Macaw.CFG as MM
import qualified Data.Macaw.CFG as MC
import qualified Data.Macaw.Discovery.State as MDS

import Renovate.Address
import Renovate.BasicBlock
Expand Down Expand Up @@ -67,7 +71,11 @@ import Renovate.Rewrite ( HasInjectedFunctions, getInjectedFunctions )
-- The function runs in an arbitrary 'Monad' to allow instrumentors to
-- carry around their own state.
--
redirect :: (MonadIO m, InstructionConstraints arch, HasInjectedFunctions m arch)
redirect :: (MonadIO m
, InstructionConstraints arch
, HasInjectedFunctions m arch
, MC.ArchConstraints arch
)
=> ISA arch
-- ^ Information about the ISA in use
-> BlockInfo arch
Expand Down Expand Up @@ -102,7 +110,7 @@ redirect isa blockInfo (textStart, textEnd) instrumentor mem strat layoutAddr ba
-- Also, see Note [PIC Jump Tables]
case and [ textStart <= concreteBlockAddress cb
, concreteBlockAddress cb < textEnd
, isRelocatableTerminatorType (terminatorType isa mem cb)
, hasRelocatableTerminatorType isa mem cb
, not (isIncompleteBlockAddress blockInfo (concreteBlockAddress cb))
, disjoint isa (biOverlap blockInfo) cb
] of
Expand All @@ -116,7 +124,7 @@ redirect isa blockInfo (textStart, textEnd) instrumentor mem strat layoutAddr ba
Nothing ->
return $! WithProvenance cb sb Unmodified
False -> do
when (not (isRelocatableTerminatorType (terminatorType isa mem cb))) $ do
when (not (hasRelocatableTerminatorType isa mem cb)) $ do
RM.recordUnrelocatableTermBlock
when (isIncompleteBlockAddress blockInfo (concreteBlockAddress cb)) $ do
RM.recordIncompleteBlock
Expand Down Expand Up @@ -152,11 +160,19 @@ toBlockMapping wps =
, let concBlock = withoutProvenance wp
]

isRelocatableTerminatorType :: JumpType arch -> Bool
isRelocatableTerminatorType jt =
case jt of
IndirectJump {} -> False
_ -> True
hasRelocatableTerminatorType ::
(MC.ArchConstraints arch)
=> ISA arch
-> MC.Memory (MC.ArchAddrWidth arch)
-> ConcreteBlock arch
-> Bool
hasRelocatableTerminatorType isa mem cb
| isRelocatableTerminatorType (terminatorType isa mem cb) = True
| Some parsedBlock <- concreteDiscoveryBlock cb
, MDS.ParsedLookupTable{} <- MDS.pblockTermStmt parsedBlock = True
| otherwise = False
where isRelocatableTerminatorType IndirectJump{} = False
isRelocatableTerminatorType _ = True

{- Note [Redirection]

Expand Down
Loading