1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "dex_instruction-inl.h"
18 
19 #include <inttypes.h>
20 
21 #include <iomanip>
22 #include <sstream>
23 
24 #include "base/stringprintf.h"
25 #include "dex_file-inl.h"
26 #include "utils.h"
27 
28 namespace art {
29 
30 const char* const Instruction::kInstructionNames[] = {
31 #define INSTRUCTION_NAME(o, c, pname, f, r, i, a, v) pname,
32 #include "dex_instruction_list.h"
33   DEX_INSTRUCTION_LIST(INSTRUCTION_NAME)
34 #undef DEX_INSTRUCTION_LIST
35 #undef INSTRUCTION_NAME
36 };
37 
38 Instruction::Format const Instruction::kInstructionFormats[] = {
39 #define INSTRUCTION_FORMAT(o, c, p, format, r, i, a, v) format,
40 #include "dex_instruction_list.h"
41   DEX_INSTRUCTION_LIST(INSTRUCTION_FORMAT)
42 #undef DEX_INSTRUCTION_LIST
43 #undef INSTRUCTION_FORMAT
44 };
45 
46 int const Instruction::kInstructionFlags[] = {
47 #define INSTRUCTION_FLAGS(o, c, p, f, r, i, flags, v) flags,
48 #include "dex_instruction_list.h"
49   DEX_INSTRUCTION_LIST(INSTRUCTION_FLAGS)
50 #undef DEX_INSTRUCTION_LIST
51 #undef INSTRUCTION_FLAGS
52 };
53 
54 int const Instruction::kInstructionVerifyFlags[] = {
55 #define INSTRUCTION_VERIFY_FLAGS(o, c, p, f, r, i, a, vflags) vflags,
56 #include "dex_instruction_list.h"
57   DEX_INSTRUCTION_LIST(INSTRUCTION_VERIFY_FLAGS)
58 #undef DEX_INSTRUCTION_LIST
59 #undef INSTRUCTION_VERIFY_FLAGS
60 };
61 
62 int const Instruction::kInstructionSizeInCodeUnits[] = {
63 #define INSTRUCTION_SIZE(opcode, c, p, format, r, i, a, v) \
64     ((opcode == NOP)                        ? -1 : \
65      ((format >= k10x) && (format <= k10t)) ?  1 : \
66      ((format >= k20t) && (format <= k22c)) ?  2 : \
67      ((format >= k32x) && (format <= k3rc)) ?  3 : \
68       (format == k51l)                      ?  5 : -1),
69 #include "dex_instruction_list.h"
70   DEX_INSTRUCTION_LIST(INSTRUCTION_SIZE)
71 #undef DEX_INSTRUCTION_LIST
72 #undef INSTRUCTION_SIZE
73 };
74 
GetTargetOffset() const75 int32_t Instruction::GetTargetOffset() const {
76   switch (FormatOf(Opcode())) {
77     // Cases for conditional branches follow.
78     case k22t: return VRegC_22t();
79     case k21t: return VRegB_21t();
80     // Cases for unconditional branches follow.
81     case k10t: return VRegA_10t();
82     case k20t: return VRegA_20t();
83     case k30t: return VRegA_30t();
84     default: LOG(FATAL) << "Tried to access the branch offset of an instruction " << Name() <<
85         " which does not have a target operand.";
86   }
87   return 0;
88 }
89 
CanFlowThrough() const90 bool Instruction::CanFlowThrough() const {
91   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
92   uint16_t insn = *insns;
93   Code opcode = static_cast<Code>(insn & 0xFF);
94   return  FlagsOf(opcode) & Instruction::kContinue;
95 }
96 
SizeInCodeUnitsComplexOpcode() const97 size_t Instruction::SizeInCodeUnitsComplexOpcode() const {
98   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
99   // Handle special NOP encoded variable length sequences.
100   switch (*insns) {
101     case kPackedSwitchSignature:
102       return (4 + insns[1] * 2);
103     case kSparseSwitchSignature:
104       return (2 + insns[1] * 4);
105     case kArrayDataSignature: {
106       uint16_t element_size = insns[1];
107       uint32_t length = insns[2] | (((uint32_t)insns[3]) << 16);
108       // The plus 1 is to round up for odd size and width.
109       return (4 + (element_size * length + 1) / 2);
110     }
111     default:
112       if ((*insns & 0xFF) == 0) {
113         return 1;  // NOP.
114       } else {
115         LOG(FATAL) << "Unreachable: " << DumpString(nullptr);
116         UNREACHABLE();
117       }
118   }
119 }
120 
DumpHex(size_t code_units) const121 std::string Instruction::DumpHex(size_t code_units) const {
122   size_t inst_length = SizeInCodeUnits();
123   if (inst_length > code_units) {
124     inst_length = code_units;
125   }
126   std::ostringstream os;
127   const uint16_t* insn = reinterpret_cast<const uint16_t*>(this);
128   for (size_t i = 0; i < inst_length; i++) {
129     os << StringPrintf("0x%04x", insn[i]) << " ";
130   }
131   for (size_t i = inst_length; i < code_units; i++) {
132     os << "       ";
133   }
134   return os.str();
135 }
136 
DumpHexLE(size_t instr_code_units) const137 std::string Instruction::DumpHexLE(size_t instr_code_units) const {
138   size_t inst_length = SizeInCodeUnits();
139   if (inst_length > instr_code_units) {
140     inst_length = instr_code_units;
141   }
142   std::ostringstream os;
143   const uint16_t* insn = reinterpret_cast<const uint16_t*>(this);
144   for (size_t i = 0; i < inst_length; i++) {
145     os << StringPrintf("%02x%02x", static_cast<uint8_t>(insn[i] & 0x00FF),
146                        static_cast<uint8_t>((insn[i] & 0xFF00) >> 8)) << " ";
147   }
148   for (size_t i = inst_length; i < instr_code_units; i++) {
149     os << "     ";
150   }
151   return os.str();
152 }
153 
DumpString(const DexFile * file) const154 std::string Instruction::DumpString(const DexFile* file) const {
155   std::ostringstream os;
156   const char* opcode = kInstructionNames[Opcode()];
157   switch (FormatOf(Opcode())) {
158     case k10x:  os << opcode; break;
159     case k12x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_12x(), VRegB_12x()); break;
160     case k11n:  os << StringPrintf("%s v%d, #%+d", opcode, VRegA_11n(), VRegB_11n()); break;
161     case k11x:  os << StringPrintf("%s v%d", opcode, VRegA_11x()); break;
162     case k10t:  os << StringPrintf("%s %+d", opcode, VRegA_10t()); break;
163     case k20t:  os << StringPrintf("%s %+d", opcode, VRegA_20t()); break;
164     case k22x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_22x(), VRegB_22x()); break;
165     case k21t:  os << StringPrintf("%s v%d, %+d", opcode, VRegA_21t(), VRegB_21t()); break;
166     case k21s:  os << StringPrintf("%s v%d, #%+d", opcode, VRegA_21s(), VRegB_21s()); break;
167     case k21h: {
168         // op vAA, #+BBBB0000[00000000]
169         if (Opcode() == CONST_HIGH16) {
170           uint32_t value = VRegB_21h() << 16;
171           os << StringPrintf("%s v%d, #int %+d // 0x%x", opcode, VRegA_21h(), value, value);
172         } else {
173           uint64_t value = static_cast<uint64_t>(VRegB_21h()) << 48;
174           os << StringPrintf("%s v%d, #long %+" PRId64 " // 0x%" PRIx64, opcode, VRegA_21h(),
175                              value, value);
176         }
177       }
178       break;
179     case k21c: {
180       switch (Opcode()) {
181         case CONST_STRING:
182           if (file != nullptr) {
183             uint32_t string_idx = VRegB_21c();
184             os << StringPrintf("const-string v%d, %s // string@%d", VRegA_21c(),
185                                PrintableString(file->StringDataByIdx(string_idx)).c_str(), string_idx);
186             break;
187           }
188           FALLTHROUGH_INTENDED;
189         case CHECK_CAST:
190         case CONST_CLASS:
191         case NEW_INSTANCE:
192           if (file != nullptr) {
193             uint32_t type_idx = VRegB_21c();
194             os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyType(type_idx, *file)
195                << " // type@" << type_idx;
196             break;
197           }
198           FALLTHROUGH_INTENDED;
199         case SGET:
200         case SGET_WIDE:
201         case SGET_OBJECT:
202         case SGET_BOOLEAN:
203         case SGET_BYTE:
204         case SGET_CHAR:
205         case SGET_SHORT:
206           if (file != nullptr) {
207             uint32_t field_idx = VRegB_21c();
208             os << opcode << "  v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
209                << " // field@" << field_idx;
210             break;
211           }
212           FALLTHROUGH_INTENDED;
213         case SPUT:
214         case SPUT_WIDE:
215         case SPUT_OBJECT:
216         case SPUT_BOOLEAN:
217         case SPUT_BYTE:
218         case SPUT_CHAR:
219         case SPUT_SHORT:
220           if (file != nullptr) {
221             uint32_t field_idx = VRegB_21c();
222             os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
223                << " // field@" << field_idx;
224             break;
225           }
226           FALLTHROUGH_INTENDED;
227         default:
228           os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c());
229           break;
230       }
231       break;
232     }
233     case k23x:  os << StringPrintf("%s v%d, v%d, v%d", opcode, VRegA_23x(), VRegB_23x(), VRegC_23x()); break;
234     case k22b:  os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22b(), VRegB_22b(), VRegC_22b()); break;
235     case k22t:  os << StringPrintf("%s v%d, v%d, %+d", opcode, VRegA_22t(), VRegB_22t(), VRegC_22t()); break;
236     case k22s:  os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22s(), VRegB_22s(), VRegC_22s()); break;
237     case k22c: {
238       switch (Opcode()) {
239         case IGET:
240         case IGET_WIDE:
241         case IGET_OBJECT:
242         case IGET_BOOLEAN:
243         case IGET_BYTE:
244         case IGET_CHAR:
245         case IGET_SHORT:
246           if (file != nullptr) {
247             uint32_t field_idx = VRegC_22c();
248             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
249                << PrettyField(field_idx, *file, true) << " // field@" << field_idx;
250             break;
251           }
252           FALLTHROUGH_INTENDED;
253         case IGET_QUICK:
254         case IGET_OBJECT_QUICK:
255           if (file != nullptr) {
256             uint32_t field_idx = VRegC_22c();
257             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
258                << "// offset@" << field_idx;
259             break;
260           }
261           FALLTHROUGH_INTENDED;
262         case IPUT:
263         case IPUT_WIDE:
264         case IPUT_OBJECT:
265         case IPUT_BOOLEAN:
266         case IPUT_BYTE:
267         case IPUT_CHAR:
268         case IPUT_SHORT:
269           if (file != nullptr) {
270             uint32_t field_idx = VRegC_22c();
271             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
272                << PrettyField(field_idx, *file, true) << " // field@" << field_idx;
273             break;
274           }
275           FALLTHROUGH_INTENDED;
276         case IPUT_QUICK:
277         case IPUT_OBJECT_QUICK:
278           if (file != nullptr) {
279             uint32_t field_idx = VRegC_22c();
280             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
281                << "// offset@" << field_idx;
282             break;
283           }
284           FALLTHROUGH_INTENDED;
285         case INSTANCE_OF:
286           if (file != nullptr) {
287             uint32_t type_idx = VRegC_22c();
288             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
289                << PrettyType(type_idx, *file) << " // type@" << type_idx;
290             break;
291           }
292           FALLTHROUGH_INTENDED;
293         case NEW_ARRAY:
294           if (file != nullptr) {
295             uint32_t type_idx = VRegC_22c();
296             os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
297                << PrettyType(type_idx, *file) << " // type@" << type_idx;
298             break;
299           }
300           FALLTHROUGH_INTENDED;
301         default:
302           os << StringPrintf("%s v%d, v%d, thing@%d", opcode, VRegA_22c(), VRegB_22c(), VRegC_22c());
303           break;
304       }
305       break;
306     }
307     case k32x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break;
308     case k30t:  os << StringPrintf("%s %+d", opcode, VRegA_30t()); break;
309     case k31t:  os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break;
310     case k31i:  os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break;
311     case k31c:
312       if (Opcode() == CONST_STRING_JUMBO) {
313         uint32_t string_idx = VRegB_31c();
314         if (file != nullptr) {
315           os << StringPrintf("%s v%d, %s // string@%d", opcode, VRegA_31c(),
316                              PrintableString(file->StringDataByIdx(string_idx)).c_str(),
317                              string_idx);
318         } else {
319           os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx);
320         }
321       } else {
322         os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break;
323       }
324       break;
325     case k35c: {
326       uint32_t arg[5];
327       GetVarArgs(arg);
328       switch (Opcode()) {
329         case FILLED_NEW_ARRAY:
330         {
331           const int32_t a = VRegA_35c();
332           os << opcode << " {";
333           for (int i = 0; i < a; ++i) {
334             if (i > 0) {
335               os << ", ";
336             }
337             os << "v" << arg[i];
338           }
339           os << "}, type@" << VRegB_35c();
340         }
341         break;
342 
343         case INVOKE_VIRTUAL:
344         case INVOKE_SUPER:
345         case INVOKE_DIRECT:
346         case INVOKE_STATIC:
347         case INVOKE_INTERFACE:
348           if (file != nullptr) {
349             os << opcode << " {";
350             uint32_t method_idx = VRegB_35c();
351             for (size_t i = 0; i < VRegA_35c(); ++i) {
352               if (i != 0) {
353                 os << ", ";
354               }
355               os << "v" << arg[i];
356             }
357             os << "}, " << PrettyMethod(method_idx, *file) << " // method@" << method_idx;
358             break;
359           }
360           FALLTHROUGH_INTENDED;
361         case INVOKE_VIRTUAL_QUICK:
362           if (file != nullptr) {
363             os << opcode << " {";
364             uint32_t method_idx = VRegB_35c();
365             for (size_t i = 0; i < VRegA_35c(); ++i) {
366               if (i != 0) {
367                 os << ", ";
368               }
369               os << "v" << arg[i];
370             }
371             os << "},  // vtable@" << method_idx;
372             break;
373           }
374           FALLTHROUGH_INTENDED;
375         default:
376           os << opcode << " {v" << arg[0] << ", v" << arg[1] << ", v" << arg[2]
377                        << ", v" << arg[3] << ", v" << arg[4] << "}, thing@" << VRegB_35c();
378           break;
379       }
380       break;
381     }
382     case k3rc: {
383       switch (Opcode()) {
384         case INVOKE_VIRTUAL_RANGE:
385         case INVOKE_SUPER_RANGE:
386         case INVOKE_DIRECT_RANGE:
387         case INVOKE_STATIC_RANGE:
388         case INVOKE_INTERFACE_RANGE:
389           if (file != nullptr) {
390             uint32_t method_idx = VRegB_3rc();
391             os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1))
392                << PrettyMethod(method_idx, *file) << " // method@" << method_idx;
393             break;
394           }
395           FALLTHROUGH_INTENDED;
396         case INVOKE_VIRTUAL_RANGE_QUICK:
397           if (file != nullptr) {
398             uint32_t method_idx = VRegB_3rc();
399             os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1))
400                << "// vtable@" << method_idx;
401             break;
402           }
403           FALLTHROUGH_INTENDED;
404         default:
405           os << StringPrintf("%s, {v%d .. v%d}, thing@%d", opcode, VRegC_3rc(),
406                              (VRegC_3rc() + VRegA_3rc() - 1), VRegB_3rc());
407           break;
408       }
409       break;
410     }
411     case k51l: os << StringPrintf("%s v%d, #%+" PRId64, opcode, VRegA_51l(), VRegB_51l()); break;
412     default: os << " unknown format (" << DumpHex(5) << ")"; break;
413   }
414   return os.str();
415 }
416 
operator <<(std::ostream & os,const Instruction::Code & code)417 std::ostream& operator<<(std::ostream& os, const Instruction::Code& code) {
418   return os << Instruction::Name(code);
419 }
420 
421 }  // namespace art
422