Bug 1552362: Ensure that the DLL Interceptor's ADRP decoding treats its immediate operand as signed; r=handyman
authorAaron Klotz <aklotz@mozilla.com>
Mon, 20 May 2019 19:01:00 +0000
changeset 474812 592cf72930939b956c6a11311d500b330b5323e3
parent 474811 723d1a2c81e8bfb8dfce985e6e9fffa3716a1c7b
child 474813 167dbfcf5251e0af024f481ffe1670b0d826ab29
push id36046
push useraiakab@mozilla.com
push dateTue, 21 May 2019 21:45:52 +0000
treeherdermozilla-central@257f2c96cef5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershandyman
bugs1552362
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1552362: Ensure that the DLL Interceptor's ADRP decoding treats its immediate operand as signed; r=handyman Differential Revision: https://phabricator.services.mozilla.com/D31550
mozglue/misc/interceptor/Arm64.cpp
mozglue/misc/interceptor/Arm64.h
--- a/mozglue/misc/interceptor/Arm64.cpp
+++ b/mozglue/misc/interceptor/Arm64.cpp
@@ -21,18 +21,20 @@ struct PCRelativeLoadTest {
 };
 
 static LoadInfo ADRPDecode(const uintptr_t aPC, const uint32_t aInst) {
   // Keep in mind that on Windows aarch64, uint32_t is little-endian
   const uint32_t kMaskDataProcImmPcRelativeImmLo = 0x60000000;
   const uint32_t kMaskDataProcImmPcRelativeImmHi = 0x00FFFFE0;
 
   uintptr_t base = aPC;
-  uintptr_t offset = ((aInst & kMaskDataProcImmPcRelativeImmHi) >> 3) |
-                     ((aInst & kMaskDataProcImmPcRelativeImmLo) >> 29);
+  intptr_t offset = SignExtend<intptr_t>(
+      ((aInst & kMaskDataProcImmPcRelativeImmHi) >> 3) |
+          ((aInst & kMaskDataProcImmPcRelativeImmLo) >> 29),
+      21);
   base &= ~0xFFFULL;
   offset <<= 12;
 
   uint8_t reg = aInst & 0x1F;
 
   return LoadInfo(base + offset, reg);
 }
 
--- a/mozglue/misc/interceptor/Arm64.h
+++ b/mozglue/misc/interceptor/Arm64.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_interceptor_Arm64_h
 #define mozilla_interceptor_Arm64_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Result.h"
 #include "mozilla/Types.h"
+#include "mozilla/TypeTraits.h"
 
 namespace mozilla {
 namespace interceptor {
 namespace arm64 {
 
 // This currently only handles loads, not branches
 struct LoadInfo {
   LoadInfo(const uintptr_t aAbsAddress, const uint8_t aDestReg)
@@ -31,16 +32,51 @@ struct LoadInfo {
 enum class PCRelCheckError {
   InstructionNotPCRel,
   NoDecoderAvailable,
 };
 
 MFBT_API Result<LoadInfo, PCRelCheckError> CheckForPCRel(const uintptr_t aPC,
                                                          const uint32_t aInst);
 
+/**
+ * Casts |aValue| to a |ResultT| via sign extension.
+ *
+ * This function should be used when extracting signed immediate values from
+ * an instruction.
+ *
+ * @param aValue The value to be sign extended. This value should already be
+ *               isolated from the remainder of the instruction's bits and
+ *               shifted all the way to the right.
+ * @param aNumValidBits The number of bits in |aValue| that contain the
+ *                      immediate signed value, including the sign bit.
+ */
+template <typename ResultT>
+inline ResultT SignExtend(const uint32_t aValue, const uint8_t aNumValidBits) {
+  static_assert(IsIntegral<ResultT>::value && IsSigned<ResultT>::value,
+                "ResultT must be a signed integral type");
+  MOZ_ASSERT(aNumValidBits < 32U && aNumValidBits > 1);
+
+  using UnsignedResultT =
+      typename Decay<typename MakeUnsigned<ResultT>::Type>::Type;
+
+  const uint8_t kResultWidthBits = sizeof(ResultT) * 8;
+
+  // Shift left unsigned
+  const uint8_t shiftAmt = kResultWidthBits - aNumValidBits;
+  UnsignedResultT shiftedLeft = static_cast<UnsignedResultT>(aValue)
+                                << shiftAmt;
+
+  // Now shift right signed
+  auto result = static_cast<ResultT>(shiftedLeft);
+  result >>= shiftAmt;
+
+  return result;
+}
+
 inline static uint32_t BuildUnconditionalBranchToRegister(const uint32_t aReg) {
   MOZ_ASSERT(aReg < 32);
   // BR aReg
   return 0xD61F0000 | (aReg << 5);
 }
 
 }  // namespace arm64
 }  // namespace interceptor