diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,9 @@
+0.3.1
+=====
+* GHC 9.0.1 and 9.2.1 support
+* Add `HasCallStack` to unsafe* functions.
+* Banish `String` on `readMaybe` and `readEither`.
+
 0.3.0
 =====
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
 Protolude
 =========
 
-[![Build Status](https://travis-ci.org/protolude/protolude.svg?branch=master)](https://travis-ci.org/sdiehl/protolude)
 [![Build Status](https://github.com/protolude/protolude/workflows/Cabal%20CI/badge.svg)](https://github.com/protolude/protolude/actions)
 [![Build Status](https://github.com/protolude/protolude/workflows/Stack%20CI/badge.svg)](https://github.com/protolude/protolude/actions)
 [![Build Status](https://github.com/protolude/protolude/workflows/Nix%20CI/badge.svg)](https://github.com/protolude/protolude/actions)
@@ -31,31 +30,23 @@
 
 Supports:
 
- * GHC 7.6.1
- * GHC 7.6.2
  * GHC 7.6.3
- * GHC 7.8.1
- * GHC 7.8.2
- * GHC 7.8.3
  * GHC 7.8.4
- * GHC 7.10.1
- * GHC 7.10.2
  * GHC 7.10.3
- * GHC 8.0.1
  * GHC 8.0.2
- * GHC 8.2.1
+ * GHC 8.2.2
  * GHC 8.4.1
+ * GHC 8.4.4
  * GHC 8.6.1
+ * GHC 8.6.4
+ * GHC 8.6.5
  * GHC 8.8.1
  * GHC 8.10.1
+ * GHC 9.0.1
+ * GHC 9.2.1
 
 Stack LTS:
 
-* lts-4.x
-* lts-5.x
-* lts-6.x
-* lts-7.x
-* lts-8.x
 * lts-9.x
 * lts-10.x
 * lts-11.x
@@ -63,6 +54,8 @@
 * lts-13.x
 * lts-14.x
 * lts-15.x
+* lts-16.x
+* lts-17.x
 
 Usage
 -----
@@ -108,7 +101,7 @@
 | -----------         |   -------- |  -------- |
 | array               |        0.4 |       0.6 |
 | async               |        2.0 |       2.3 |
-| base                |        4.6 |      4.15 |
+| base                |        4.6 |      4.16 |
 | bytestring          |       0.10 |      0.11 |
 | containers          |        0.5 |       0.7 |
 | deepseq             |        1.3 |       1.5 |
@@ -147,11 +140,10 @@
 
 * **How do I write manual Show instances if ``show`` isn't provided?**
 
-Generally speaking writing manual instances of Show is a [Haskell antipattern](
-http://www.stephendiehl.com/posts/strings.html) because it produces
-law-violating instances of Show. You probably want to use a [pretty
-printer](https://hackage.haskell.org/package/wl-pprint-text) library for custom
-printing.
+Generally speaking writing manual instances of Show is a
+[Haskell antipattern](http://www.stephendiehl.com/posts/strings.html) because it produces
+law-violating instances of Show. You probably want to use a
+[pretty printer](https://hackage.haskell.org/package/wl-pprint-text) library for custom printing.
 
 If backwards compatibility is needed then the base library can be imported
 manually.
@@ -211,7 +203,7 @@
 
 There is a massive test suite that tests all versions of GHC 7.6 - GHC HEAD
 alongside all Stack resolvers to ensure no regressions. Any pull requests or
-patch has to pass the 40 integrity checks before being considered. Any pull
+patch has to pass the 47 integrity checks before being considered. Any pull
 request must keep the export list consistent across GHC and Base version and not
 have any accidental symbol dropping or drift without updating the export golden
 tests.
@@ -220,4 +212,4 @@
 -------
 
 Released under the MIT License.
-Copyright (c) 2016-2020, Stephen Diehl
+Copyright (c) 2016-2022, Stephen Diehl
diff --git a/protolude.cabal b/protolude.cabal
--- a/protolude.cabal
+++ b/protolude.cabal
@@ -1,27 +1,20 @@
 name:               protolude
-version:            0.3.0
+version:            0.3.1
 synopsis:           A small prelude.
 description:        A sensible set of defaults for writing custom Preludes.
 homepage:           https://github.com/sdiehl/protolude
 license:            MIT
 license-file:       LICENSE
 author:             Stephen Diehl
-maintainer:         stephen.m.diehl@gmail.com
-copyright:          2016-2020 Stephen Diehl
+maintainer:         adamwespiser@gmail.com, stephen.m.diehl@gmail.com
+copyright:          2016-2022 Stephen Diehl
 category:           Prelude
 build-type:         Simple
 cabal-version:      >=1.10
 bug-reports:        https://github.com/sdiehl/protolude/issues
 tested-with:
-  GHC ==7.6.1
-   || ==7.6.2
-   || ==7.6.3
-   || ==7.8.1
-   || ==7.8.2
-   || ==7.8.3
+  GHC ==7.6.3
    || ==7.8.4
-   || ==7.10.1
-   || ==7.10.2
    || ==7.10.3
    || ==8.0.1
    || ==8.2.1
@@ -29,6 +22,8 @@
    || ==8.6.1
    || ==8.8.1
    || ==8.10.1
+   || ==9.0.1
+   || ==9.2.1
 
 extra-source-files:
   README.md
@@ -77,18 +72,18 @@
   build-depends:
       array                >=0.4  && <0.6
     , async                >=2.0  && <2.3
-    , base                 >=4.6  && <4.15
-    , bytestring           >=0.10 && <0.11
+    , base                 >=4.6  && <4.17
+    , bytestring           >=0.10 && <0.11.4
     , containers           >=0.5  && <0.7
     , deepseq              >=1.3  && <1.5
-    , ghc-prim             >=0.3  && <0.7
-    , hashable             >=1.2  && <1.4
+    , ghc-prim             >=0.3  && <0.9
+    , hashable             >=1.2  && <1.5
     , mtl                  >=2.1  && <2.3
     , mtl-compat           >=0.2  && <0.3
     , stm                  >=2.4  && <2.6
-    , text                 >=1.2  && <1.3
+    , text                 >=1.2  && <2.1
     , transformers         >=0.2  && <0.6
-    , transformers-compat  >=0.4  && <0.7
+    , transformers-compat  >=0.4  && <0.8
 
   if !impl(ghc >=8.0)
     build-depends: fail ==4.9.*
diff --git a/src/Protolude.hs b/src/Protolude.hs
--- a/src/Protolude.hs
+++ b/src/Protolude.hs
@@ -128,6 +128,8 @@
 
   -- * Read functions
   module Read,
+  readMaybe,
+  readEither,
 
   -- * System functions
   module System,
@@ -153,6 +155,7 @@
 import Protolude.Panic as Panic
 import Protolude.Exceptions as Exception
 import Protolude.Semiring as Semiring
+import qualified Protolude.Conv as Conv
 
 import Protolude.Base as Base hiding (
     putStr           -- Overriden by Show.putStr
@@ -267,8 +270,6 @@
 import Data.Semigroup as Semigroup (
     Semigroup(sconcat, stimes)
   , WrappedMonoid
-  , Option(..)
-  , option
   , diff
   , cycle1
   , stimesMonoid
@@ -278,6 +279,13 @@
   )
 #endif
 
+#if MIN_VERSION_base(4,9,0) && !MIN_VERSION_base(4,16,0)
+import Data.Semigroup as Semigroup (
+    Option(..)
+  , option
+  )
+#endif
+
 import Data.Monoid as Monoid
 
 #if !MIN_VERSION_base(4,8,0)
@@ -308,6 +316,8 @@
   , break
   , intercalate
   , isPrefixOf
+  , isInfixOf
+  , isSuffixOf
   , drop
   , filter
   , reverse
@@ -908,11 +918,10 @@
 import Foreign.StablePtr as Foreign (StablePtr)
 
 -- Read instances hiding unsafe builtins (read)
+import qualified Text.Read as Read
 import Text.Read as Read (
     Read
   , reads
-  , readMaybe
-  , readEither
   )
 
 -- Type synonymss for lazy texts
@@ -949,6 +958,29 @@
 applyN :: Int -> (a -> a) -> a -> a
 applyN n f = Foldable.foldr (.) identity (List.replicate n f)
 
+-- | Parse a string using the 'Read' instance.
+-- Succeeds if there is exactly one valid result.
+--
+-- >>> readMaybe ("123" :: Text) :: Maybe Int
+-- Just 123
+--
+-- >>> readMaybe ("hello" :: Text) :: Maybe Int
+-- Nothing
+readMaybe :: (Read b, Conv.StringConv a String) => a -> Maybe b
+readMaybe = Read.readMaybe . Conv.toS
+
+-- | Parse a string using the 'Read' instance.
+-- Succeeds if there is exactly one valid result.
+-- A 'Left' value indicates a parse error.
+--
+-- >>> readEither "123" :: Either Text Int
+-- Right 123
+--
+-- >>> readEither "hello" :: Either Text Int
+-- Left "Prelude.read: no parse"
+readEither :: (Read a, Conv.StringConv String e, Conv.StringConv e String) => e -> Either e a
+readEither = first Conv.toS . Read.readEither . Conv.toS
+
 -- | The print function outputs a value of any printable type to the standard
 -- output device. Printable types are those that are instances of class Show;
 -- print converts values to strings for output using the show operation and adds
@@ -982,8 +1014,8 @@
 liftIO2 :: MonadIO m => (a -> b -> IO c) -> a -> b -> m c
 liftIO2 = ((.).(.)) liftIO
 
-show :: (Show a, ConvertText String b) => a -> b
-show x = ConvertText.toS (PBase.show x)
+show :: (Show a, Conv.StringConv String b) => a -> b
+show x = Conv.toS (PBase.show x)
 {-# SPECIALIZE show :: Show  a => a -> Text  #-}
 {-# SPECIALIZE show :: Show  a => a -> LText  #-}
 {-# SPECIALIZE show :: Show  a => a -> String  #-}
diff --git a/src/Protolude/Base.hs b/src/Protolude/Base.hs
--- a/src/Protolude/Base.hs
+++ b/src/Protolude/Base.hs
@@ -67,9 +67,11 @@
   , fromIntegral
   , fromRational
   , gcd
-#if MIN_VERSION_base(4,9,0)
+#if MIN_VERSION_base(4,9,0) && !MIN_VERSION_base(4,15,0)
+#if defined(MIN_VERSION_integer_gmp)
   , gcdInt'
   , gcdWord'
+#endif
 #endif
   , infinity
   , integralEnumFrom
diff --git a/src/Protolude/ConvertText.hs b/src/Protolude/ConvertText.hs
--- a/src/Protolude/ConvertText.hs
+++ b/src/Protolude/ConvertText.hs
@@ -35,6 +35,12 @@
 instance ConvertText LT.Text T.Text where toS = LT.toStrict
 instance ConvertText LT.Text LT.Text where toS = id
 
+instance ConvertText LB.ByteString B.ByteString where toS = LB.toStrict
+instance ConvertText LB.ByteString LB.ByteString where toS = id
+
+instance ConvertText B.ByteString B.ByteString where toS = id
+instance ConvertText B.ByteString LB.ByteString where toS = LB.fromStrict
+
 toUtf8 :: ConvertText a T.Text => a -> B.ByteString
 toUtf8 =
   encodeUtf8 . toS
diff --git a/src/Protolude/Unsafe.hs b/src/Protolude/Unsafe.hs
--- a/src/Protolude/Unsafe.hs
+++ b/src/Protolude/Unsafe.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE Unsafe #-}
 {-# LANGUAGE NoImplicitPrelude #-}
 
@@ -13,12 +14,44 @@
 ) where
 
 import Protolude.Base (Int)
+
+#if ( __GLASGOW_HASKELL__ >= 800 )
+import Protolude.Base (HasCallStack)
+#endif
 import Data.Char (Char)
 import Text.Read (Read, read)
 import qualified Data.List as List
 import qualified Data.Maybe as Maybe
 import qualified Control.Exception as Exc
 
+unsafeThrow :: Exc.Exception e => e -> a
+unsafeThrow = Exc.throw
+
+#if ( __GLASGOW_HASKELL__ >= 800 )
+unsafeHead :: HasCallStack => [a] -> a
+unsafeHead = List.head
+
+unsafeTail :: HasCallStack => [a] -> [a]
+unsafeTail = List.tail
+
+unsafeInit :: HasCallStack => [a] -> [a]
+unsafeInit = List.init
+
+unsafeLast :: HasCallStack => [a] -> a
+unsafeLast = List.last
+
+unsafeFromJust :: HasCallStack => Maybe.Maybe a -> a
+unsafeFromJust = Maybe.fromJust
+
+unsafeIndex :: HasCallStack => [a] -> Int -> a
+unsafeIndex = (List.!!)
+
+unsafeRead :: (HasCallStack, Read a) => [Char] -> a
+unsafeRead = Text.Read.read
+#endif
+
+
+#if ( __GLASGOW_HASKELL__ < 800 )
 unsafeHead :: [a] -> a
 unsafeHead = List.head
 
@@ -37,8 +70,6 @@
 unsafeIndex :: [a] -> Int -> a
 unsafeIndex = (List.!!)
 
-unsafeThrow :: Exc.Exception e => e -> a
-unsafeThrow = Exc.throw
-
 unsafeRead :: Read a => [Char] -> a
 unsafeRead = Text.Read.read
+#endif
