1*9880d681SAndroid Build Coastguard Worker //===-- ARMUnwindOpAsm.cpp - ARM Unwind Opcodes Assembler -------*- C++ -*-===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker // The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker // This file implements the unwind opcode assmebler for ARM exception handling
11*9880d681SAndroid Build Coastguard Worker // table.
12*9880d681SAndroid Build Coastguard Worker //
13*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
14*9880d681SAndroid Build Coastguard Worker
15*9880d681SAndroid Build Coastguard Worker #include "ARMUnwindOpAsm.h"
16*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/ARMEHABI.h"
17*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/ErrorHandling.h"
18*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/LEB128.h"
19*9880d681SAndroid Build Coastguard Worker
20*9880d681SAndroid Build Coastguard Worker using namespace llvm;
21*9880d681SAndroid Build Coastguard Worker
22*9880d681SAndroid Build Coastguard Worker namespace {
23*9880d681SAndroid Build Coastguard Worker /// UnwindOpcodeStreamer - The simple wrapper over SmallVector to emit bytes
24*9880d681SAndroid Build Coastguard Worker /// with MSB to LSB per uint32_t ordering. For example, the first byte will
25*9880d681SAndroid Build Coastguard Worker /// be placed in Vec[3], and the following bytes will be placed in 2, 1, 0,
26*9880d681SAndroid Build Coastguard Worker /// 7, 6, 5, 4, 11, 10, 9, 8, and so on.
27*9880d681SAndroid Build Coastguard Worker class UnwindOpcodeStreamer {
28*9880d681SAndroid Build Coastguard Worker private:
29*9880d681SAndroid Build Coastguard Worker SmallVectorImpl<uint8_t> &Vec;
30*9880d681SAndroid Build Coastguard Worker size_t Pos;
31*9880d681SAndroid Build Coastguard Worker
32*9880d681SAndroid Build Coastguard Worker public:
UnwindOpcodeStreamer(SmallVectorImpl<uint8_t> & V)33*9880d681SAndroid Build Coastguard Worker UnwindOpcodeStreamer(SmallVectorImpl<uint8_t> &V) : Vec(V), Pos(3) {
34*9880d681SAndroid Build Coastguard Worker }
35*9880d681SAndroid Build Coastguard Worker
36*9880d681SAndroid Build Coastguard Worker /// Emit the byte in MSB to LSB per uint32_t order.
EmitByte(uint8_t elem)37*9880d681SAndroid Build Coastguard Worker inline void EmitByte(uint8_t elem) {
38*9880d681SAndroid Build Coastguard Worker Vec[Pos] = elem;
39*9880d681SAndroid Build Coastguard Worker Pos = (((Pos ^ 0x3u) + 1) ^ 0x3u);
40*9880d681SAndroid Build Coastguard Worker }
41*9880d681SAndroid Build Coastguard Worker
42*9880d681SAndroid Build Coastguard Worker /// Emit the size prefix.
EmitSize(size_t Size)43*9880d681SAndroid Build Coastguard Worker inline void EmitSize(size_t Size) {
44*9880d681SAndroid Build Coastguard Worker size_t SizeInWords = (Size + 3) / 4;
45*9880d681SAndroid Build Coastguard Worker assert(SizeInWords <= 0x100u &&
46*9880d681SAndroid Build Coastguard Worker "Only 256 additional words are allowed for unwind opcodes");
47*9880d681SAndroid Build Coastguard Worker EmitByte(static_cast<uint8_t>(SizeInWords - 1));
48*9880d681SAndroid Build Coastguard Worker }
49*9880d681SAndroid Build Coastguard Worker
50*9880d681SAndroid Build Coastguard Worker /// Emit the personality index prefix.
EmitPersonalityIndex(unsigned PI)51*9880d681SAndroid Build Coastguard Worker inline void EmitPersonalityIndex(unsigned PI) {
52*9880d681SAndroid Build Coastguard Worker assert(PI < ARM::EHABI::NUM_PERSONALITY_INDEX &&
53*9880d681SAndroid Build Coastguard Worker "Invalid personality prefix");
54*9880d681SAndroid Build Coastguard Worker EmitByte(ARM::EHABI::EHT_COMPACT | PI);
55*9880d681SAndroid Build Coastguard Worker }
56*9880d681SAndroid Build Coastguard Worker
57*9880d681SAndroid Build Coastguard Worker /// Fill the rest of bytes with FINISH opcode.
FillFinishOpcode()58*9880d681SAndroid Build Coastguard Worker inline void FillFinishOpcode() {
59*9880d681SAndroid Build Coastguard Worker while (Pos < Vec.size())
60*9880d681SAndroid Build Coastguard Worker EmitByte(ARM::EHABI::UNWIND_OPCODE_FINISH);
61*9880d681SAndroid Build Coastguard Worker }
62*9880d681SAndroid Build Coastguard Worker };
63*9880d681SAndroid Build Coastguard Worker }
64*9880d681SAndroid Build Coastguard Worker
EmitRegSave(uint32_t RegSave)65*9880d681SAndroid Build Coastguard Worker void UnwindOpcodeAssembler::EmitRegSave(uint32_t RegSave) {
66*9880d681SAndroid Build Coastguard Worker if (RegSave == 0u)
67*9880d681SAndroid Build Coastguard Worker return;
68*9880d681SAndroid Build Coastguard Worker
69*9880d681SAndroid Build Coastguard Worker // One byte opcode to save register r14 and r11-r4
70*9880d681SAndroid Build Coastguard Worker if (RegSave & (1u << 4)) {
71*9880d681SAndroid Build Coastguard Worker // The one byte opcode will always save r4, thus we can't use the one byte
72*9880d681SAndroid Build Coastguard Worker // opcode when r4 is not in .save directive.
73*9880d681SAndroid Build Coastguard Worker
74*9880d681SAndroid Build Coastguard Worker // Compute the consecutive registers from r4 to r11.
75*9880d681SAndroid Build Coastguard Worker uint32_t Mask = RegSave & 0xff0u;
76*9880d681SAndroid Build Coastguard Worker uint32_t Range = countTrailingOnes(Mask >> 5); // Exclude r4.
77*9880d681SAndroid Build Coastguard Worker // Mask off non-consecutive registers. Keep r4.
78*9880d681SAndroid Build Coastguard Worker Mask &= ~(0xffffffe0u << Range);
79*9880d681SAndroid Build Coastguard Worker
80*9880d681SAndroid Build Coastguard Worker // Emit this opcode when the mask covers every registers.
81*9880d681SAndroid Build Coastguard Worker uint32_t UnmaskedReg = RegSave & 0xfff0u & (~Mask);
82*9880d681SAndroid Build Coastguard Worker if (UnmaskedReg == 0u) {
83*9880d681SAndroid Build Coastguard Worker // Pop r[4 : (4 + n)]
84*9880d681SAndroid Build Coastguard Worker EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4 | Range);
85*9880d681SAndroid Build Coastguard Worker RegSave &= 0x000fu;
86*9880d681SAndroid Build Coastguard Worker } else if (UnmaskedReg == (1u << 14)) {
87*9880d681SAndroid Build Coastguard Worker // Pop r[14] + r[4 : (4 + n)]
88*9880d681SAndroid Build Coastguard Worker EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4_R14 | Range);
89*9880d681SAndroid Build Coastguard Worker RegSave &= 0x000fu;
90*9880d681SAndroid Build Coastguard Worker }
91*9880d681SAndroid Build Coastguard Worker }
92*9880d681SAndroid Build Coastguard Worker
93*9880d681SAndroid Build Coastguard Worker // Two bytes opcode to save register r15-r4
94*9880d681SAndroid Build Coastguard Worker if ((RegSave & 0xfff0u) != 0)
95*9880d681SAndroid Build Coastguard Worker EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK_R4 | (RegSave >> 4));
96*9880d681SAndroid Build Coastguard Worker
97*9880d681SAndroid Build Coastguard Worker // Opcode to save register r3-r0
98*9880d681SAndroid Build Coastguard Worker if ((RegSave & 0x000fu) != 0)
99*9880d681SAndroid Build Coastguard Worker EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK | (RegSave & 0x000fu));
100*9880d681SAndroid Build Coastguard Worker }
101*9880d681SAndroid Build Coastguard Worker
102*9880d681SAndroid Build Coastguard Worker /// Emit unwind opcodes for .vsave directives
EmitVFPRegSave(uint32_t VFPRegSave)103*9880d681SAndroid Build Coastguard Worker void UnwindOpcodeAssembler::EmitVFPRegSave(uint32_t VFPRegSave) {
104*9880d681SAndroid Build Coastguard Worker // We only have 4 bits to save the offset in the opcode so look at the lower
105*9880d681SAndroid Build Coastguard Worker // and upper 16 bits separately.
106*9880d681SAndroid Build Coastguard Worker for (uint32_t Regs : {VFPRegSave & 0xffff0000u, VFPRegSave & 0x0000ffffu}) {
107*9880d681SAndroid Build Coastguard Worker while (Regs) {
108*9880d681SAndroid Build Coastguard Worker // Now look for a run of set bits. Remember the MSB and LSB of the run.
109*9880d681SAndroid Build Coastguard Worker auto RangeMSB = 32 - countLeadingZeros(Regs);
110*9880d681SAndroid Build Coastguard Worker auto RangeLen = countLeadingOnes(Regs << (32 - RangeMSB));
111*9880d681SAndroid Build Coastguard Worker auto RangeLSB = RangeMSB - RangeLen;
112*9880d681SAndroid Build Coastguard Worker
113*9880d681SAndroid Build Coastguard Worker int Opcode = RangeLSB >= 16
114*9880d681SAndroid Build Coastguard Worker ? ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD_D16
115*9880d681SAndroid Build Coastguard Worker : ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD;
116*9880d681SAndroid Build Coastguard Worker
117*9880d681SAndroid Build Coastguard Worker EmitInt16(Opcode | ((RangeLSB % 16) << 4) | (RangeLen - 1));
118*9880d681SAndroid Build Coastguard Worker
119*9880d681SAndroid Build Coastguard Worker // Zero out bits we're done with.
120*9880d681SAndroid Build Coastguard Worker Regs &= ~(-1u << RangeLSB);
121*9880d681SAndroid Build Coastguard Worker }
122*9880d681SAndroid Build Coastguard Worker }
123*9880d681SAndroid Build Coastguard Worker }
124*9880d681SAndroid Build Coastguard Worker
125*9880d681SAndroid Build Coastguard Worker /// Emit unwind opcodes to copy address from source register to $sp.
EmitSetSP(uint16_t Reg)126*9880d681SAndroid Build Coastguard Worker void UnwindOpcodeAssembler::EmitSetSP(uint16_t Reg) {
127*9880d681SAndroid Build Coastguard Worker EmitInt8(ARM::EHABI::UNWIND_OPCODE_SET_VSP | Reg);
128*9880d681SAndroid Build Coastguard Worker }
129*9880d681SAndroid Build Coastguard Worker
130*9880d681SAndroid Build Coastguard Worker /// Emit unwind opcodes to add $sp with an offset.
EmitSPOffset(int64_t Offset)131*9880d681SAndroid Build Coastguard Worker void UnwindOpcodeAssembler::EmitSPOffset(int64_t Offset) {
132*9880d681SAndroid Build Coastguard Worker if (Offset > 0x200) {
133*9880d681SAndroid Build Coastguard Worker uint8_t Buff[16];
134*9880d681SAndroid Build Coastguard Worker Buff[0] = ARM::EHABI::UNWIND_OPCODE_INC_VSP_ULEB128;
135*9880d681SAndroid Build Coastguard Worker size_t ULEBSize = encodeULEB128((Offset - 0x204) >> 2, Buff + 1);
136*9880d681SAndroid Build Coastguard Worker EmitBytes(Buff, ULEBSize + 1);
137*9880d681SAndroid Build Coastguard Worker } else if (Offset > 0) {
138*9880d681SAndroid Build Coastguard Worker if (Offset > 0x100) {
139*9880d681SAndroid Build Coastguard Worker EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP | 0x3fu);
140*9880d681SAndroid Build Coastguard Worker Offset -= 0x100;
141*9880d681SAndroid Build Coastguard Worker }
142*9880d681SAndroid Build Coastguard Worker EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP |
143*9880d681SAndroid Build Coastguard Worker static_cast<uint8_t>((Offset - 4) >> 2));
144*9880d681SAndroid Build Coastguard Worker } else if (Offset < 0) {
145*9880d681SAndroid Build Coastguard Worker while (Offset < -0x100) {
146*9880d681SAndroid Build Coastguard Worker EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP | 0x3fu);
147*9880d681SAndroid Build Coastguard Worker Offset += 0x100;
148*9880d681SAndroid Build Coastguard Worker }
149*9880d681SAndroid Build Coastguard Worker EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP |
150*9880d681SAndroid Build Coastguard Worker static_cast<uint8_t>(((-Offset) - 4) >> 2));
151*9880d681SAndroid Build Coastguard Worker }
152*9880d681SAndroid Build Coastguard Worker }
153*9880d681SAndroid Build Coastguard Worker
Finalize(unsigned & PersonalityIndex,SmallVectorImpl<uint8_t> & Result)154*9880d681SAndroid Build Coastguard Worker void UnwindOpcodeAssembler::Finalize(unsigned &PersonalityIndex,
155*9880d681SAndroid Build Coastguard Worker SmallVectorImpl<uint8_t> &Result) {
156*9880d681SAndroid Build Coastguard Worker
157*9880d681SAndroid Build Coastguard Worker UnwindOpcodeStreamer OpStreamer(Result);
158*9880d681SAndroid Build Coastguard Worker
159*9880d681SAndroid Build Coastguard Worker if (HasPersonality) {
160*9880d681SAndroid Build Coastguard Worker // User-specifed personality routine: [ SIZE , OP1 , OP2 , ... ]
161*9880d681SAndroid Build Coastguard Worker PersonalityIndex = ARM::EHABI::NUM_PERSONALITY_INDEX;
162*9880d681SAndroid Build Coastguard Worker size_t TotalSize = Ops.size() + 1;
163*9880d681SAndroid Build Coastguard Worker size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
164*9880d681SAndroid Build Coastguard Worker Result.resize(RoundUpSize);
165*9880d681SAndroid Build Coastguard Worker OpStreamer.EmitSize(RoundUpSize);
166*9880d681SAndroid Build Coastguard Worker } else {
167*9880d681SAndroid Build Coastguard Worker // If no personalityindex is specified, select ane
168*9880d681SAndroid Build Coastguard Worker if (PersonalityIndex == ARM::EHABI::NUM_PERSONALITY_INDEX)
169*9880d681SAndroid Build Coastguard Worker PersonalityIndex = (Ops.size() <= 3) ? ARM::EHABI::AEABI_UNWIND_CPP_PR0
170*9880d681SAndroid Build Coastguard Worker : ARM::EHABI::AEABI_UNWIND_CPP_PR1;
171*9880d681SAndroid Build Coastguard Worker if (PersonalityIndex == ARM::EHABI::AEABI_UNWIND_CPP_PR0) {
172*9880d681SAndroid Build Coastguard Worker // __aeabi_unwind_cpp_pr0: [ 0x80 , OP1 , OP2 , OP3 ]
173*9880d681SAndroid Build Coastguard Worker assert(Ops.size() <= 3 && "too many opcodes for __aeabi_unwind_cpp_pr0");
174*9880d681SAndroid Build Coastguard Worker Result.resize(4);
175*9880d681SAndroid Build Coastguard Worker OpStreamer.EmitPersonalityIndex(PersonalityIndex);
176*9880d681SAndroid Build Coastguard Worker } else {
177*9880d681SAndroid Build Coastguard Worker // __aeabi_unwind_cpp_pr{1,2}: [ {0x81,0x82} , SIZE , OP1 , OP2 , ... ]
178*9880d681SAndroid Build Coastguard Worker size_t TotalSize = Ops.size() + 2;
179*9880d681SAndroid Build Coastguard Worker size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
180*9880d681SAndroid Build Coastguard Worker Result.resize(RoundUpSize);
181*9880d681SAndroid Build Coastguard Worker OpStreamer.EmitPersonalityIndex(PersonalityIndex);
182*9880d681SAndroid Build Coastguard Worker OpStreamer.EmitSize(RoundUpSize);
183*9880d681SAndroid Build Coastguard Worker }
184*9880d681SAndroid Build Coastguard Worker }
185*9880d681SAndroid Build Coastguard Worker
186*9880d681SAndroid Build Coastguard Worker // Copy the unwind opcodes
187*9880d681SAndroid Build Coastguard Worker for (size_t i = OpBegins.size() - 1; i > 0; --i)
188*9880d681SAndroid Build Coastguard Worker for (size_t j = OpBegins[i - 1], end = OpBegins[i]; j < end; ++j)
189*9880d681SAndroid Build Coastguard Worker OpStreamer.EmitByte(Ops[j]);
190*9880d681SAndroid Build Coastguard Worker
191*9880d681SAndroid Build Coastguard Worker // Emit the padding finish opcodes if the size is not multiple of 4.
192*9880d681SAndroid Build Coastguard Worker OpStreamer.FillFinishOpcode();
193*9880d681SAndroid Build Coastguard Worker
194*9880d681SAndroid Build Coastguard Worker // Reset the assembler state
195*9880d681SAndroid Build Coastguard Worker Reset();
196*9880d681SAndroid Build Coastguard Worker }
197