Skip to content

Commit

Permalink
Implement macaw-loader-riscv
Browse files Browse the repository at this point in the history
Fixes #13.
  • Loading branch information
RyanGlScott committed Jul 26, 2024
1 parent 78fdab8 commit e9eec71
Show file tree
Hide file tree
Showing 12 changed files with 219 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ jobs:
with:
ghc-version: ${{ matrix.ghc-ver }}
cabal-version: ${{ matrix.cabal }}
- name: System Dependencies
run: |
# Softfloat repo needs to be recursively cloned
cd submodules/softfloat-hs
git submodule update --init --recursive
cd ../..
- uses: actions/cache/restore@v3
name: Restore cabal store cache
with:
Expand Down
12 changes: 12 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,15 @@
[submodule "submodules/llvm-pretty-bc-parser"]
path = submodules/llvm-pretty-bc-parser
url = https://github.com/GaloisInc/llvm-pretty-bc-parser
[submodule "submodules/grift"]
path = submodules/grift
url = https://github.com/GaloisInc/grift.git
[submodule "submodules/bv-sized"]
path = submodules/bv-sized
url = https://github.com/GaloisInc/bv-sized.git
[submodule "submodules/bv-sized-float"]
path = submodules/bv-sized-float
url = https://github.com/GaloisInc/bv-sized-float.git
[submodule "submodules/softfloat-hs"]
path = submodules/softfloat-hs
url = https://github.com/GaloisInc/softfloat-hs.git
6 changes: 6 additions & 0 deletions cabal.project.dist
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ packages:
macaw-loader-x86
macaw-loader-ppc
macaw-loader-aarch32
macaw-loader-riscv
submodules/elf-edit
submodules/dwarf
submodules/flexdis86
Expand All @@ -24,9 +25,14 @@ packages:
submodules/macaw/x86
submodules/macaw/macaw-ppc
submodules/macaw/macaw-aarch32
submodules/macaw/macaw-riscv
submodules/macaw/macaw-semmc
submodules/crucible/crucible
submodules/crucible/crucible-llvm
submodules/crucible/crucible-symio
submodules/llvm-pretty
submodules/llvm-pretty-bc-parser
submodules/grift/grift/
submodules/bv-sized/
submodules/bv-sized-float/
submodules/softfloat-hs/
5 changes: 5 additions & 0 deletions macaw-loader-riscv/ChangeLog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Revision history for macaw-loader-riscv

## 0.1.0.0 -- YYYY-mm-dd

* First version. Released on an unsuspecting world.
30 changes: 30 additions & 0 deletions macaw-loader-riscv/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Copyright (c) 2024, 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 other
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.
2 changes: 2 additions & 0 deletions macaw-loader-riscv/Setup.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain
29 changes: 29 additions & 0 deletions macaw-loader-riscv/macaw-loader-riscv.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: macaw-loader-riscv
version: 0.1.0.0
synopsis: Library to load RISC-V binary images and get macaw Memory and entry points.
-- description:
homepage: https://github.com/GaloisInc/macaw-loader/macaw-loader-riscv
license: BSD3
license-file: LICENSE
author: Galois, Inc.
maintainer: [email protected]
copyright: 2024, Galois Inc.
category: Development
build-type: Simple
extra-source-files: ChangeLog.md
cabal-version: >=1.10

library
exposed-modules: Data.Macaw.BinaryLoader.RISCV
build-depends: base >=4.9 && <5,
bytestring,
containers,
elf-edit >= 0.39,
exceptions,
grift,
macaw-base,
macaw-loader,
macaw-riscv
hs-source-dirs: src
default-language: Haskell2010
ghc-options: -Wall -Wcompat
125 changes: 125 additions & 0 deletions macaw-loader-riscv/src/Data/Macaw/BinaryLoader/RISCV.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Data.Macaw.BinaryLoader.RISCV (
RISCVLoadException(..)
) where

import qualified Control.Monad.Catch as X
import qualified Data.ByteString as BS
import qualified Data.ElfEdit as EE
import qualified Data.Foldable as F
import qualified Data.List.NonEmpty as DLN
import qualified Data.Macaw.BinaryLoader as MBL
import qualified Data.Macaw.BinaryLoader.ELF as BLE
import qualified Data.Macaw.Memory as MM
import qualified Data.Macaw.Memory.ElfLoader as EL
import qualified Data.Macaw.Memory.LoadCommon as LC
import qualified Data.Map.Strict as Map
import Data.Maybe ( fromMaybe, mapMaybe )
import qualified GRIFT.Types as G

import qualified Data.Macaw.RISCV as MR

data RISCVElfData w =
RISCVElfData { elf :: EE.ElfHeaderInfo w
, memSymbols :: [EL.MemSymbol w]
, symbolIndex :: Map.Map (MM.MemAddr w) BS.ByteString
}

instance (w ~ G.RVWidth rv, MR.RISCVConstraints rv)
=> MBL.BinaryLoader (MR.RISCV rv) (EE.ElfHeaderInfo w) where
type ArchBinaryData (MR.RISCV rv) (EE.ElfHeaderInfo w) = ()
type BinaryFormatData (MR.RISCV rv) (EE.ElfHeaderInfo w) = RISCVElfData w
type Diagnostic (MR.RISCV rv) (EE.ElfHeaderInfo w) = EL.MemLoadWarning
loadBinary = loadRiscvBinary
entryPoints = riscvEntryPoints
symbolFor = riscvLookupSymbol

riscvLookupSymbol :: (X.MonadThrow m)
=> MBL.LoadedBinary (MR.RISCV rv) (EE.ElfHeaderInfo (G.RVWidth rv))
-> MM.MemAddr (G.RVWidth rv)
-> m BS.ByteString
riscvLookupSymbol loadedBinary addr =
case Map.lookup addr (symbolIndex (MBL.binaryFormatData loadedBinary)) of
Just sym -> return sym
Nothing -> X.throwM (MissingSymbolFor addr)

riscvEntryPoints :: forall m rv
. (X.MonadThrow m, MR.RISCVConstraints rv)
=> MBL.LoadedBinary (MR.RISCV rv) (EE.ElfHeaderInfo (G.RVWidth rv))
-> m (DLN.NonEmpty (MM.MemSegmentOff (G.RVWidth rv)))
riscvEntryPoints loadedBinary =
EE.elfClassInstances elfClass $
let addr = MM.memWord (offset + fromIntegral (EE.headerEntry (EE.header (elf (MBL.binaryFormatData loadedBinary))))) in
let symbols = [ MM.memWord (offset + fromIntegral (EE.steValue entry))
| entry <- staticSyms ++ dynSyms
, EE.steType entry == EE.STT_FUNC
] in
case BLE.resolveAbsoluteAddress mem addr of
Nothing -> X.throwM (InvalidEntryPoint addr)
Just entryPoint ->
return (entryPoint DLN.:| mapMaybe (BLE.resolveAbsoluteAddress mem) symbols)
where
offset = fromMaybe 0 (LC.loadOffset (MBL.loadOptions loadedBinary))
mem = MBL.memoryImage loadedBinary
elfData = elf (MBL.binaryFormatData loadedBinary)
elfHeader = EE.header elfData
elfClass = EE.headerClass elfHeader
staticSyms = symtabEntriesList $ EE.decodeHeaderSymtab elfData
dynSyms = symtabEntriesList $ EE.decodeHeaderDynsym elfData

symtabEntriesList :: Maybe (Either EE.SymtabError (EE.Symtab (G.RVWidth rv)))
-> [EE.SymtabEntry BS.ByteString (EE.ElfWordType (G.RVWidth rv))]
symtabEntriesList symtab =
case symtab of
Nothing -> []
Just (Left _) -> []
Just (Right st) -> F.toList (EE.symtabEntries st)

loadRiscvBinary :: forall m rv
. (X.MonadThrow m)
=> LC.LoadOptions
-> EE.ElfHeaderInfo (G.RVWidth rv)
-> m (MBL.LoadedBinary (MR.RISCV rv) (EE.ElfHeaderInfo (G.RVWidth rv)))
loadRiscvBinary lopts e =
case EL.memoryForElf lopts e of
Left err -> X.throwM (RISCVElfLoadError err)
Right (mem, symbols, warnings, _) ->
return MBL.LoadedBinary { MBL.memoryImage = mem
, MBL.memoryEndianness = MM.LittleEndian
, MBL.archBinaryData = ()
, MBL.binaryFormatData =
RISCVElfData { elf = e
, memSymbols = symbols
, symbolIndex = indexSymbols symbols
}
, MBL.loadDiagnostics = warnings
, MBL.binaryRepr =
case EE.headerClass (EE.header e) of
EE.ELFCLASS32 -> MBL.Elf32Repr
EE.ELFCLASS64 -> MBL.Elf64Repr
, MBL.originalBinary = e
, MBL.loadOptions = lopts
}

indexSymbols :: [EL.MemSymbol w] -> Map.Map (MM.MemAddr w) BS.ByteString
indexSymbols = F.foldl' doIndex Map.empty
where
doIndex m memSym =
Map.insert (MM.segoffAddr (EL.memSymbolStart memSym)) (EL.memSymbolName memSym) m

data RISCVLoadException = RISCVElfLoadError String
| forall w. InvalidEntryPoint (MM.MemWord w)
| forall w. MissingSymbolFor (MM.MemAddr w)

deriving instance Show RISCVLoadException

instance X.Exception RISCVLoadException
1 change: 1 addition & 0 deletions submodules/bv-sized
Submodule bv-sized added at 854601
1 change: 1 addition & 0 deletions submodules/bv-sized-float
Submodule bv-sized-float added at 69ebb2
1 change: 1 addition & 0 deletions submodules/grift
Submodule grift added at cc3efa
1 change: 1 addition & 0 deletions submodules/softfloat-hs
Submodule softfloat-hs added at a74bb9

0 comments on commit e9eec71

Please sign in to comment.