378 lines · c
1//===-- ARMUtils.h ----------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H10#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H11 12#include "ARMDefines.h"13#include "InstructionUtils.h"14#include "llvm/ADT/bit.h"15#include "llvm/Support/MathExtras.h"16 17// Common utilities for the ARM/Thumb Instruction Set Architecture.18 19namespace lldb_private {20 21static inline uint32_t Align(uint32_t val, uint32_t alignment) {22 return alignment * (val / alignment);23}24 25static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5,26 ARM_ShifterType &shift_t) {27 switch (type) {28 default:29 assert(0 && "Invalid shift type");30 break;31 case 0:32 shift_t = SRType_LSL;33 return imm5;34 case 1:35 shift_t = SRType_LSR;36 return (imm5 == 0 ? 32 : imm5);37 case 2:38 shift_t = SRType_ASR;39 return (imm5 == 0 ? 32 : imm5);40 case 3:41 if (imm5 == 0) {42 shift_t = SRType_RRX;43 return 1;44 } else {45 shift_t = SRType_ROR;46 return imm5;47 }48 }49 shift_t = SRType_Invalid;50 return UINT32_MAX;51}52 53// A8.6.35 CMP (register) -- Encoding T354// Convenience function.55static inline uint32_t DecodeImmShiftThumb(const uint32_t opcode,56 ARM_ShifterType &shift_t) {57 return DecodeImmShift(Bits32(opcode, 5, 4),58 Bits32(opcode, 14, 12) << 2 | Bits32(opcode, 7, 6),59 shift_t);60}61 62// A8.6.35 CMP (register) -- Encoding A163// Convenience function.64static inline uint32_t DecodeImmShiftARM(const uint32_t opcode,65 ARM_ShifterType &shift_t) {66 return DecodeImmShift(Bits32(opcode, 6, 5), Bits32(opcode, 11, 7), shift_t);67}68 69static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t,70 const uint32_t imm5) {71 ARM_ShifterType dont_care;72 return DecodeImmShift(shift_t, imm5, dont_care);73}74 75static inline ARM_ShifterType DecodeRegShift(const uint32_t type) {76 switch (type) {77 default:78 // assert(0 && "Invalid shift type");79 return SRType_Invalid;80 case 0:81 return SRType_LSL;82 case 1:83 return SRType_LSR;84 case 2:85 return SRType_ASR;86 case 3:87 return SRType_ROR;88 }89}90 91static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount,92 uint32_t &carry_out, bool *success) {93 if (amount == 0) {94 *success = false;95 return 0;96 }97 *success = true;98 carry_out = amount <= 32 ? Bit32(value, 32 - amount) : 0;99 return value << amount;100}101 102static inline uint32_t LSL(const uint32_t value, const uint32_t amount,103 bool *success) {104 *success = true;105 if (amount == 0)106 return value;107 uint32_t dont_care;108 uint32_t result = LSL_C(value, amount, dont_care, success);109 if (*success)110 return result;111 else112 return 0;113}114 115static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount,116 uint32_t &carry_out, bool *success) {117 if (amount == 0) {118 *success = false;119 return 0;120 }121 *success = true;122 carry_out = amount <= 32 ? Bit32(value, amount - 1) : 0;123 return value >> amount;124}125 126static inline uint32_t LSR(const uint32_t value, const uint32_t amount,127 bool *success) {128 *success = true;129 if (amount == 0)130 return value;131 uint32_t dont_care;132 uint32_t result = LSR_C(value, amount, dont_care, success);133 if (*success)134 return result;135 else136 return 0;137}138 139static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount,140 uint32_t &carry_out, bool *success) {141 if (amount == 0 || amount > 32) {142 *success = false;143 return 0;144 }145 *success = true;146 bool negative = BitIsSet(value, 31);147 if (amount <= 32) {148 carry_out = Bit32(value, amount - 1);149 int64_t extended = llvm::SignExtend64<32>(value);150 return UnsignedBits(extended, amount + 31, amount);151 } else {152 carry_out = (negative ? 1 : 0);153 return (negative ? 0xffffffff : 0);154 }155}156 157static inline uint32_t ASR(const uint32_t value, const uint32_t amount,158 bool *success) {159 *success = true;160 if (amount == 0)161 return value;162 uint32_t dont_care;163 uint32_t result = ASR_C(value, amount, dont_care, success);164 if (*success)165 return result;166 else167 return 0;168}169 170static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount,171 uint32_t &carry_out, bool *success) {172 if (amount == 0) {173 *success = false;174 return 0;175 }176 *success = true;177 uint32_t result = llvm::rotr<uint32_t>(value, amount);178 carry_out = Bit32(value, 31);179 return result;180}181 182static inline uint32_t ROR(const uint32_t value, const uint32_t amount,183 bool *success) {184 *success = true;185 if (amount == 0)186 return value;187 uint32_t dont_care;188 uint32_t result = ROR_C(value, amount, dont_care, success);189 if (*success)190 return result;191 else192 return 0;193}194 195static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in,196 uint32_t &carry_out, bool *success) {197 *success = true;198 carry_out = Bit32(value, 0);199 return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);200}201 202static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in,203 bool *success) {204 *success = true;205 uint32_t dont_care;206 uint32_t result = RRX_C(value, carry_in, dont_care, success);207 if (*success)208 return result;209 else210 return 0;211}212 213static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type,214 const uint32_t amount, const uint32_t carry_in,215 uint32_t &carry_out, bool *success) {216 if (type == SRType_RRX && amount != 1) {217 *success = false;218 return 0;219 }220 *success = true;221 222 if (amount == 0) {223 carry_out = carry_in;224 return value;225 }226 uint32_t result;227 switch (type) {228 case SRType_LSL:229 result = LSL_C(value, amount, carry_out, success);230 break;231 case SRType_LSR:232 result = LSR_C(value, amount, carry_out, success);233 break;234 case SRType_ASR:235 result = ASR_C(value, amount, carry_out, success);236 break;237 case SRType_ROR:238 result = ROR_C(value, amount, carry_out, success);239 break;240 case SRType_RRX:241 result = RRX_C(value, carry_in, carry_out, success);242 break;243 default:244 *success = false;245 break;246 }247 if (*success)248 return result;249 else250 return 0;251}252 253static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type,254 const uint32_t amount, const uint32_t carry_in,255 bool *success) {256 // Don't care about carry out in this case.257 uint32_t dont_care;258 uint32_t result = Shift_C(value, type, amount, carry_in, dont_care, success);259 if (*success)260 return result;261 else262 return 0;263}264 265static inline uint32_t bits(const uint32_t val, const uint32_t msbit,266 const uint32_t lsbit) {267 return Bits32(val, msbit, lsbit);268}269 270static inline uint32_t bit(const uint32_t val, const uint32_t msbit) {271 return bits(val, msbit, msbit);272}273 274static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift) {275 uint32_t m = shift % N;276 return (val >> m) | (val << (N - m));277}278 279// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)280static inline uint32_t ARMExpandImm_C(uint32_t opcode, uint32_t carry_in,281 uint32_t &carry_out) {282 uint32_t imm32; // the expanded result283 uint32_t imm = bits(opcode, 7, 0); // immediate value284 uint32_t amt = 2 * bits(opcode, 11, 8); // rotate amount285 if (amt == 0) {286 imm32 = imm;287 carry_out = carry_in;288 } else {289 imm32 = ror(imm, 32, amt);290 carry_out = Bit32(imm32, 31);291 }292 return imm32;293}294 295static inline uint32_t ARMExpandImm(uint32_t opcode) {296 // 'carry_in' argument to following function call does not affect the imm32297 // result.298 uint32_t carry_in = 0;299 uint32_t carry_out;300 return ARMExpandImm_C(opcode, carry_in, carry_out);301}302 303// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)304static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in,305 uint32_t &carry_out) {306 uint32_t imm32 = 0; // the expanded result307 const uint32_t i = bit(opcode, 26);308 const uint32_t imm3 = bits(opcode, 14, 12);309 const uint32_t abcdefgh = bits(opcode, 7, 0);310 const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;311 312 if (bits(imm12, 11, 10) == 0) {313 switch (bits(imm12, 9, 8)) {314 default: // Keep static analyzer happy with a default case315 break;316 317 case 0:318 imm32 = abcdefgh;319 break;320 321 case 1:322 imm32 = abcdefgh << 16 | abcdefgh;323 break;324 325 case 2:326 imm32 = abcdefgh << 24 | abcdefgh << 8;327 break;328 329 case 3:330 imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;331 break;332 }333 carry_out = carry_in;334 } else {335 const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);336 imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));337 carry_out = Bit32(imm32, 31);338 }339 return imm32;340}341 342static inline uint32_t ThumbExpandImm(uint32_t opcode) {343 // 'carry_in' argument to following function call does not affect the imm32344 // result.345 uint32_t carry_in = 0;346 uint32_t carry_out;347 return ThumbExpandImm_C(opcode, carry_in, carry_out);348}349 350// imm32 = ZeroExtend(i:imm3:imm8, 32)351static inline uint32_t ThumbImm12(uint32_t opcode) {352 const uint32_t i = bit(opcode, 26);353 const uint32_t imm3 = bits(opcode, 14, 12);354 const uint32_t imm8 = bits(opcode, 7, 0);355 const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;356 return imm12;357}358 359// imm32 = ZeroExtend(imm7:'00', 32)360static inline uint32_t ThumbImm7Scaled(uint32_t opcode) {361 const uint32_t imm7 = bits(opcode, 6, 0);362 return imm7 * 4;363}364 365// imm32 = ZeroExtend(imm8:'00', 32)366static inline uint32_t ThumbImm8Scaled(uint32_t opcode) {367 const uint32_t imm8 = bits(opcode, 7, 0);368 return imm8 * 4;369}370 371// This function performs the check for the register numbers 13 and 15 that are372// not permitted for many Thumb register specifiers.373static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }374 375} // namespace lldb_private376 377#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H378