• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 "slicer/code_ir.h"
18 
19 #include "slicer/bytecode_encoder.h"
20 #include "slicer/common.h"
21 #include "slicer/debuginfo_encoder.h"
22 #include "slicer/dex_bytecode.h"
23 #include "slicer/dex_format.h"
24 #include "slicer/dex_ir.h"
25 #include "slicer/dex_leb128.h"
26 #include "slicer/tryblocks_encoder.h"
27 
28 #include <algorithm>
29 #include <iomanip>
30 #include <sstream>
31 #include <vector>
32 
33 namespace lir {
34 
Assemble()35 void CodeIr::Assemble() {
36   auto ir_code = ir_method->code;
37   SLICER_CHECK_NE(ir_code, nullptr);
38 
39   // new .dex bytecode
40   //
41   // NOTE: this must be done before the debug information and
42   //   try/catch blocks since here is where we update the final offsets
43   //
44   BytecodeEncoder bytecode_encoder(instructions);
45   bytecode_encoder.Encode(ir_code, dex_ir);
46 
47   // debug information
48   if (ir_code->debug_info != nullptr) {
49     DebugInfoEncoder dbginfo_encoder(instructions);
50     dbginfo_encoder.Encode(ir_method, dex_ir);
51   }
52 
53   // try/catch blocks
54   TryBlocksEncoder try_blocks_encoder(instructions);
55   try_blocks_encoder.Encode(ir_code, dex_ir);
56 }
57 
DisassembleTryBlocks(const ir::Code * ir_code)58 void CodeIr::DisassembleTryBlocks(const ir::Code* ir_code) {
59   int nextTryBlockId = 1;
60   for (const auto& tryBlock : ir_code->try_blocks) {
61     auto try_block_begin = Alloc<TryBlockBegin>();
62     try_block_begin->id = nextTryBlockId++;
63     try_block_begin->offset = tryBlock.start_addr;
64 
65     auto try_block_end = Alloc<TryBlockEnd>();
66     try_block_end->try_begin = try_block_begin;
67     try_block_end->offset = tryBlock.start_addr + tryBlock.insn_count;
68 
69     // parse the catch handlers
70     const dex::u1* ptr =
71         ir_code->catch_handlers.ptr<dex::u1>() + tryBlock.handler_off;
72     int catchCount = dex::ReadSLeb128(&ptr);
73 
74     for (int catchIndex = 0; catchIndex < std::abs(catchCount); ++catchIndex) {
75       CatchHandler handler = {};
76 
77       // type
78       dex::u4 type_index = dex::ReadULeb128(&ptr);
79       handler.ir_type = dex_ir->types_map[type_index];
80       SLICER_CHECK_NE(handler.ir_type, nullptr);
81 
82       // address
83       dex::u4 address = dex::ReadULeb128(&ptr);
84       handler.label = GetLabel(address);
85 
86       try_block_end->handlers.push_back(handler);
87     }
88 
89     // catch_all handler?
90     //
91     // NOTE: this is used to generate code for the "finally" blocks
92     //  (see Java Virtual Machine Specification - 3.13 "Compiling finally")
93     //
94     if (catchCount < 1) {
95       dex::u4 address = dex::ReadULeb128(&ptr);
96       try_block_end->catch_all = GetLabel(address);
97     }
98 
99     // we should have at least one handler
100     SLICER_CHECK(!try_block_end->handlers.empty() ||
101           try_block_end->catch_all != nullptr);
102 
103     try_begins_.push_back(try_block_begin);
104     try_ends_.push_back(try_block_end);
105   }
106 }
107 
DisassembleDebugInfo(const ir::DebugInfo * ir_debug_info)108 void CodeIr::DisassembleDebugInfo(const ir::DebugInfo* ir_debug_info) {
109   if (ir_debug_info == nullptr) {
110     return;
111   }
112 
113   // debug info state machine registers
114   dex::u4 address = 0;
115   int line = ir_debug_info->line_start;
116   ir::String* source_file = ir_method->decl->parent->class_def->source_file;
117 
118   // header
119   if (!ir_debug_info->param_names.empty()) {
120     auto dbg_header = Alloc<DbgInfoHeader>();
121     dbg_header->param_names = ir_debug_info->param_names;
122     dbg_header->offset = 0;
123     dbg_annotations_.push_back(dbg_header);
124   }
125 
126   // initial source file
127   {
128     auto annotation = Alloc<DbgInfoAnnotation>(dex::DBG_SET_FILE);
129     annotation->offset = 0;
130     annotation->operands.push_back(Alloc<String>(
131         source_file, source_file ? source_file->orig_index : dex::kNoIndex));
132     dbg_annotations_.push_back(annotation);
133   }
134 
135   // initial line number - redundant?
136   {
137     auto annotation = Alloc<DbgInfoAnnotation>(dex::DBG_ADVANCE_LINE);
138     annotation->offset = 0;
139     annotation->operands.push_back(Alloc<LineNumber>(line));
140     dbg_annotations_.push_back(annotation);
141   }
142 
143   // debug info annotations
144   const dex::u1* ptr = ir_debug_info->data.ptr<dex::u1>();
145   dex::u1 opcode = 0;
146   while ((opcode = *ptr++) != dex::DBG_END_SEQUENCE) {
147     DbgInfoAnnotation* annotation = nullptr;
148 
149     switch (opcode) {
150       case dex::DBG_ADVANCE_PC:
151         // addr_diff
152         address += dex::ReadULeb128(&ptr);
153         break;
154 
155       case dex::DBG_ADVANCE_LINE:
156         // line_diff
157         line += dex::ReadSLeb128(&ptr);
158         SLICER_WEAK_CHECK(line > 0);
159         break;
160 
161       case dex::DBG_START_LOCAL: {
162         annotation = Alloc<DbgInfoAnnotation>(opcode);
163 
164         // register_num
165         annotation->operands.push_back(Alloc<VReg>(dex::ReadULeb128(&ptr)));
166 
167         // name
168         dex::u4 name_index = dex::ReadULeb128(&ptr) - 1;
169         annotation->operands.push_back(GetString(name_index));
170 
171         // type
172         dex::u4 type_index = dex::ReadULeb128(&ptr) - 1;
173         annotation->operands.push_back(GetType(type_index));
174       } break;
175 
176       case dex::DBG_START_LOCAL_EXTENDED: {
177         annotation = Alloc<DbgInfoAnnotation>(opcode);
178 
179         // register_num
180         annotation->operands.push_back(Alloc<VReg>(dex::ReadULeb128(&ptr)));
181 
182         // name
183         dex::u4 name_index = dex::ReadULeb128(&ptr) - 1;
184         annotation->operands.push_back(GetString(name_index));
185 
186         // type
187         dex::u4 type_index = dex::ReadULeb128(&ptr) - 1;
188         annotation->operands.push_back(GetType(type_index));
189 
190         // signature
191         dex::u4 sig_index = dex::ReadULeb128(&ptr) - 1;
192         annotation->operands.push_back(GetString(sig_index));
193       } break;
194 
195       case dex::DBG_END_LOCAL:
196       case dex::DBG_RESTART_LOCAL:
197         annotation = Alloc<DbgInfoAnnotation>(opcode);
198         // register_num
199         annotation->operands.push_back(Alloc<VReg>(dex::ReadULeb128(&ptr)));
200         break;
201 
202       case dex::DBG_SET_PROLOGUE_END:
203         annotation = Alloc<DbgInfoAnnotation>(opcode);
204         break;
205 
206       case dex::DBG_SET_EPILOGUE_BEGIN:
207         annotation = Alloc<DbgInfoAnnotation>(opcode);
208         break;
209 
210       case dex::DBG_SET_FILE: {
211         annotation = Alloc<DbgInfoAnnotation>(opcode);
212 
213         // source file name
214         dex::u4 name_index = dex::ReadULeb128(&ptr) - 1;
215         source_file = (name_index == dex::kNoIndex)
216                           ? nullptr
217                           : dex_ir->strings_map[name_index];
218         annotation->operands.push_back(Alloc<String>(source_file, name_index));
219       } break;
220 
221       default: {
222         int adjusted_opcode = opcode - dex::DBG_FIRST_SPECIAL;
223         line += dex::DBG_LINE_BASE + (adjusted_opcode % dex::DBG_LINE_RANGE);
224         address += (adjusted_opcode / dex::DBG_LINE_RANGE);
225         SLICER_WEAK_CHECK(line > 0);
226         annotation = Alloc<DbgInfoAnnotation>(dex::DBG_ADVANCE_LINE);
227         annotation->operands.push_back(Alloc<LineNumber>(line));
228       } break;
229     }
230 
231     if (annotation != nullptr) {
232       annotation->offset = address;
233       dbg_annotations_.push_back(annotation);
234     }
235   }
236 }
237 
DisassembleBytecode(const ir::Code * ir_code)238 void CodeIr::DisassembleBytecode(const ir::Code* ir_code) {
239   const dex::u2* begin = ir_code->instructions.begin();
240   const dex::u2* end = ir_code->instructions.end();
241   const dex::u2* ptr = begin;
242 
243   while (ptr < end) {
244     auto isize = dex::GetWidthFromBytecode(ptr);
245     SLICER_CHECK_GT(isize, 0);
246 
247     dex::u4 offset = ptr - begin;
248 
249     Instruction* instr = nullptr;
250     switch (*ptr) {
251       case dex::kPackedSwitchSignature:
252         instr = DecodePackedSwitch(ptr, offset);
253         break;
254 
255       case dex::kSparseSwitchSignature:
256         instr = DecodeSparseSwitch(ptr, offset);
257         break;
258 
259       case dex::kArrayDataSignature:
260         instr = DecodeArrayData(ptr, offset);
261         break;
262 
263       default:
264         instr = DecodeBytecode(ptr, offset);
265         break;
266     }
267 
268     instr->offset = offset;
269     instructions.push_back(instr);
270     ptr += isize;
271   }
272   SLICER_CHECK_EQ(ptr, end);
273 }
274 
FixupSwitches()275 void CodeIr::FixupSwitches() {
276   const dex::u2* begin = ir_method->code->instructions.begin();
277 
278   // packed switches
279   for (auto& fixup : packed_switches_) {
280     FixupPackedSwitch(fixup.second.instr, fixup.second.base_offset,
281                       begin + fixup.first);
282   }
283 
284   // sparse switches
285   for (auto& fixup : sparse_switches_) {
286     FixupSparseSwitch(fixup.second.instr, fixup.second.base_offset,
287                       begin + fixup.first);
288   }
289 }
290 
291 // merge a set of extra instructions into the instruction list
292 template <class I_LIST, class E_LIST>
MergeInstructions(I_LIST & instructions,const E_LIST & extra)293 static void MergeInstructions(I_LIST& instructions, const E_LIST& extra) {
294 
295   // the extra instructins must be sorted by offset
296   SLICER_CHECK(std::is_sorted(extra.begin(), extra.end(),
297                         [](const Instruction* a, const Instruction* b) {
298                           return a->offset < b->offset;
299                         }));
300 
301   auto instrIt = instructions.begin();
302   auto extraIt = extra.begin();
303 
304   while (extraIt != extra.end()) {
305     if (instrIt == instructions.end() ||
306         (*extraIt)->offset == (*instrIt)->offset) {
307       instructions.insert(instrIt, *extraIt);
308       ++extraIt;
309     } else {
310       ++instrIt;
311     }
312   }
313 }
314 
Disassemble()315 void CodeIr::Disassemble() {
316   nodes_.clear();
317   labels_.clear();
318 
319   try_begins_.clear();
320   try_ends_.clear();
321   dbg_annotations_.clear();
322   packed_switches_.clear();
323   sparse_switches_.clear();
324 
325   auto ir_code = ir_method->code;
326   if (ir_code == nullptr) {
327     return;
328   }
329 
330   // decode the .dex bytecodes
331   DisassembleBytecode(ir_code);
332 
333   // try/catch blocks
334   DisassembleTryBlocks(ir_code);
335 
336   // debug information
337   DisassembleDebugInfo(ir_code->debug_info);
338 
339   // fixup switches
340   FixupSwitches();
341 
342   // assign label ids
343   std::vector<Label*> tmp_labels;
344   int nextLabelId = 1;
345   for (auto& label : labels_) {
346     label.second->id = nextLabelId++;
347     tmp_labels.push_back(label.second);
348   }
349 
350   // merge the labels into the instructions stream
351   MergeInstructions(instructions, dbg_annotations_);
352   MergeInstructions(instructions, try_begins_);
353   MergeInstructions(instructions, tmp_labels);
354   MergeInstructions(instructions, try_ends_);
355 }
356 
DecodePackedSwitch(const dex::u2 *,dex::u4 offset)357 PackedSwitchPayload* CodeIr::DecodePackedSwitch(const dex::u2* /*ptr*/,
358                                          dex::u4 offset) {
359   // actual decoding is delayed to FixupPackedSwitch()
360   // (since the label offsets are relative to the referring
361   //  instruction, not the switch data)
362   SLICER_CHECK_EQ(offset % 2, 0);
363   auto& instr = packed_switches_[offset].instr;
364   SLICER_CHECK_EQ(instr, nullptr);
365   instr = Alloc<PackedSwitchPayload>();
366   return instr;
367 }
368 
FixupPackedSwitch(PackedSwitchPayload * instr,dex::u4 base_offset,const dex::u2 * ptr)369 void CodeIr::FixupPackedSwitch(PackedSwitchPayload* instr, dex::u4 base_offset,
370                                const dex::u2* ptr) {
371   SLICER_CHECK(instr->targets.empty());
372 
373   auto dex_packed_switch = reinterpret_cast<const dex::PackedSwitchPayload*>(ptr);
374   SLICER_CHECK_EQ(dex_packed_switch->ident, dex::kPackedSwitchSignature);
375 
376   instr->first_key = dex_packed_switch->first_key;
377   for (dex::u2 i = 0; i < dex_packed_switch->size; ++i) {
378     instr->targets.push_back(
379         GetLabel(base_offset + dex_packed_switch->targets[i]));
380   }
381 }
382 
DecodeSparseSwitch(const dex::u2 *,dex::u4 offset)383 SparseSwitchPayload* CodeIr::DecodeSparseSwitch(const dex::u2* /*ptr*/,
384                                          dex::u4 offset) {
385   // actual decoding is delayed to FixupSparseSwitch()
386   // (since the label offsets are relative to the referring
387   //  instruction, not the switch data)
388   SLICER_CHECK_EQ(offset % 2, 0);
389   auto& instr = sparse_switches_[offset].instr;
390   SLICER_CHECK_EQ(instr, nullptr);
391   instr = Alloc<SparseSwitchPayload>();
392   return instr;
393 }
394 
FixupSparseSwitch(SparseSwitchPayload * instr,dex::u4 base_offset,const dex::u2 * ptr)395 void CodeIr::FixupSparseSwitch(SparseSwitchPayload* instr, dex::u4 base_offset,
396                                const dex::u2* ptr) {
397   SLICER_CHECK(instr->switch_cases.empty());
398 
399   auto dex_sparse_switch = reinterpret_cast<const dex::SparseSwitchPayload*>(ptr);
400   SLICER_CHECK_EQ(dex_sparse_switch->ident, dex::kSparseSwitchSignature);
401 
402   auto& data = dex_sparse_switch->data;
403   auto& size = dex_sparse_switch->size;
404 
405   for (dex::u2 i = 0; i < size; ++i) {
406     SparseSwitchPayload::SwitchCase switch_case = {};
407     switch_case.key = data[i];
408     switch_case.target = GetLabel(base_offset + data[i + size]);
409     instr->switch_cases.push_back(switch_case);
410   }
411 }
412 
DecodeArrayData(const dex::u2 * ptr,dex::u4 offset)413 ArrayData* CodeIr::DecodeArrayData(const dex::u2* ptr, dex::u4 offset) {
414   auto dex_array_data = reinterpret_cast<const dex::ArrayData*>(ptr);
415   SLICER_CHECK_EQ(dex_array_data->ident, dex::kArrayDataSignature);
416   SLICER_CHECK_EQ(offset % 2, 0);
417 
418   auto instr = Alloc<ArrayData>();
419   instr->data = slicer::MemView(ptr, dex::GetWidthFromBytecode(ptr) * 2);
420   return instr;
421 }
422 
GetRegA(const dex::Instruction & dex_instr)423 Operand* CodeIr::GetRegA(const dex::Instruction& dex_instr) {
424   auto verify_flags = dex::GetVerifyFlagsFromOpcode(dex_instr.opcode);
425   if ((verify_flags & dex::kVerifyRegAWide) != 0) {
426     return Alloc<VRegPair>(dex_instr.vA);
427   } else {
428     return Alloc<VReg>(dex_instr.vA);
429   }
430 }
431 
GetRegB(const dex::Instruction & dex_instr)432 Operand* CodeIr::GetRegB(const dex::Instruction& dex_instr) {
433   auto verify_flags = dex::GetVerifyFlagsFromOpcode(dex_instr.opcode);
434   if ((verify_flags & dex::kVerifyRegBWide) != 0) {
435     return Alloc<VRegPair>(dex_instr.vB);
436   } else {
437     return Alloc<VReg>(dex_instr.vB);
438   }
439 }
440 
GetRegC(const dex::Instruction & dex_instr)441 Operand* CodeIr::GetRegC(const dex::Instruction& dex_instr) {
442   auto verify_flags = dex::GetVerifyFlagsFromOpcode(dex_instr.opcode);
443   if ((verify_flags & dex::kVerifyRegCWide) != 0) {
444     return Alloc<VRegPair>(dex_instr.vC);
445   } else {
446     return Alloc<VReg>(dex_instr.vC);
447   }
448 }
449 
DecodeBytecode(const dex::u2 * ptr,dex::u4 offset)450 Bytecode* CodeIr::DecodeBytecode(const dex::u2* ptr, dex::u4 offset) {
451   auto dex_instr = dex::DecodeInstruction(ptr);
452 
453   auto instr = Alloc<Bytecode>();
454   instr->opcode = dex_instr.opcode;
455 
456   auto index_type = dex::GetIndexTypeFromOpcode(dex_instr.opcode);
457   auto format = dex::GetFormatFromOpcode(dex_instr.opcode);
458   switch (format) {
459     case dex::k10x:  // op
460       break;
461 
462     case dex::k12x:  // op vA, vB
463     case dex::k22x:  // op vAA, vBBBB
464     case dex::k32x:  // op vAAAA, vBBBB
465       instr->operands.push_back(GetRegA(dex_instr));
466       instr->operands.push_back(GetRegB(dex_instr));
467       break;
468 
469     case dex::k11n:  // op vA, #+B
470     case dex::k21s:  // op vAA, #+BBBB
471     case dex::k31i:  // op vAA, #+BBBBBBBB
472       instr->operands.push_back(GetRegA(dex_instr));
473       instr->operands.push_back(Alloc<Const32>(dex_instr.vB));
474       break;
475 
476     case dex::k11x:  // op vAA
477       instr->operands.push_back(GetRegA(dex_instr));
478       break;
479 
480     case dex::k10t:  // op +AA
481     case dex::k20t:  // op +AAAA
482     case dex::k30t:  // op +AAAAAAAA
483     {
484       auto label = GetLabel(offset + dex::s4(dex_instr.vA));
485       instr->operands.push_back(Alloc<CodeLocation>(label));
486     } break;
487 
488     case dex::k21t:  // op vAA, +BBBB
489     case dex::k31t:  // op vAA, +BBBBBBBB
490     {
491       dex::u4 targetOffset = offset + dex::s4(dex_instr.vB);
492       instr->operands.push_back(GetRegA(dex_instr));
493       auto label = GetLabel(targetOffset);
494       instr->operands.push_back(Alloc<CodeLocation>(label));
495 
496       if (dex_instr.opcode == dex::OP_PACKED_SWITCH) {
497         label->aligned = true;
498         dex::u4& base_offset = packed_switches_[targetOffset].base_offset;
499         SLICER_CHECK_EQ(base_offset, kInvalidOffset);
500         base_offset = offset;
501       } else if (dex_instr.opcode == dex::OP_SPARSE_SWITCH) {
502         label->aligned = true;
503         dex::u4& base_offset = sparse_switches_[targetOffset].base_offset;
504         SLICER_CHECK_EQ(base_offset, kInvalidOffset);
505         base_offset = offset;
506       } else if (dex_instr.opcode == dex::OP_FILL_ARRAY_DATA) {
507         label->aligned = true;
508       }
509     } break;
510 
511     case dex::k23x:  // op vAA, vBB, vCC
512       instr->operands.push_back(GetRegA(dex_instr));
513       instr->operands.push_back(GetRegB(dex_instr));
514       instr->operands.push_back(GetRegC(dex_instr));
515       break;
516 
517     case dex::k22t:  // op vA, vB, +CCCC
518     {
519       instr->operands.push_back(GetRegA(dex_instr));
520       instr->operands.push_back(GetRegB(dex_instr));
521       auto label = GetLabel(offset + dex::s4(dex_instr.vC));
522       instr->operands.push_back(Alloc<CodeLocation>(label));
523     } break;
524 
525     case dex::k22b:  // op vAA, vBB, #+CC
526     case dex::k22s:  // op vA, vB, #+CCCC
527       instr->operands.push_back(GetRegA(dex_instr));
528       instr->operands.push_back(GetRegB(dex_instr));
529       instr->operands.push_back(Alloc<Const32>(dex_instr.vC));
530       break;
531 
532     case dex::k22c:  // op vA, vB, thing@CCCC
533       instr->operands.push_back(GetRegA(dex_instr));
534       instr->operands.push_back(GetRegB(dex_instr));
535       instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vC));
536       break;
537 
538     case dex::k21c:  // op vAA, thing@BBBB
539     case dex::k31c:  // op vAA, string@BBBBBBBB
540       instr->operands.push_back(GetRegA(dex_instr));
541       instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB));
542       break;
543 
544     case dex::k35c:  // op {vC,vD,vE,vF,vG}, thing@BBBB
545     {
546       SLICER_CHECK_LE(dex_instr.vA, 5);
547       auto vreg_list = Alloc<VRegList>();
548       for (dex::u4 i = 0; i < dex_instr.vA; ++i) {
549         vreg_list->registers.push_back(dex_instr.arg[i]);
550       }
551       instr->operands.push_back(vreg_list);
552       instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB));
553     } break;
554 
555     case dex::k3rc:  // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
556     {
557       auto vreg_range = Alloc<VRegRange>(dex_instr.vC, dex_instr.vA);
558       instr->operands.push_back(vreg_range);
559       instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB));
560     } break;
561 
562     case dex::k45cc: // op {vC, vD, vE, vF, vG}, thing@BBBB, other@HHHH
563     {
564       auto vreg_list = Alloc<VRegList>();
565       SLICER_CHECK_LE(dex_instr.vA, 5);
566       // vC if necessary.
567       if (dex_instr.vA > 1) {
568         vreg_list->registers.push_back(dex_instr.vC);
569       }
570       // Add vD,vE,vF,vG as necessary.
571       for (dex::u4 i = 1; i < dex_instr.vA; ++i) {
572         vreg_list->registers.push_back(dex_instr.arg[i - 1]);
573       }
574       instr->operands.push_back(vreg_list);
575       instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB));
576       dex::u4 vH = dex_instr.arg[4];
577       auto proto_operand = GetSecondIndexedOperand(index_type, vH);
578       instr->operands.push_back(proto_operand);
579     } break;
580 
581     case dex::k4rcc:  // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB, other@HHHH
582     {
583       auto vreg_range = Alloc<VRegRange>(dex_instr.vC, dex_instr.vA);
584       instr->operands.push_back(vreg_range);
585       instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB));
586       dex::u4 vH = dex_instr.arg[4];
587       auto proto_operand = GetSecondIndexedOperand(index_type, vH);
588       instr->operands.push_back(proto_operand);
589     } break;
590 
591     case dex::k21h:  // op vAA, #+BBBB0000[00000000]
592       switch (dex_instr.opcode) {
593         case dex::OP_CONST_HIGH16:
594           instr->operands.push_back(GetRegA(dex_instr));
595           instr->operands.push_back(Alloc<Const32>(dex_instr.vB << 16));
596           break;
597 
598         case dex::OP_CONST_WIDE_HIGH16:
599           instr->operands.push_back(GetRegA(dex_instr));
600           instr->operands.push_back(Alloc<Const64>(dex::u8(dex_instr.vB) << 48));
601           break;
602 
603         default: {
604           std::stringstream ss;
605           ss << "Unexpected opcode: " << dex_instr.opcode;
606           SLICER_FATAL(ss.str());
607         }
608       }
609       break;
610 
611     case dex::k51l:  // op vAA, #+BBBBBBBBBBBBBBBB
612       instr->operands.push_back(GetRegA(dex_instr));
613       instr->operands.push_back(Alloc<Const64>(dex_instr.vB_wide));
614       break;
615 
616     default: {
617       std::stringstream ss;
618       ss << "Unexpected bytecode format " << format << " for opcode " << dex_instr.opcode;
619       SLICER_FATAL(ss.str());
620     }
621   }
622 
623   return instr;
624 }
625 
626 // Get a indexed object (string, field, ...)
627 // (index must be valid != kNoIndex)
GetIndexedOperand(dex::InstructionIndexType index_type,dex::u4 index)628 IndexedOperand* CodeIr::GetIndexedOperand(dex::InstructionIndexType index_type,
629                                           dex::u4 index) {
630   SLICER_CHECK_NE(index, dex::kNoIndex);
631   switch (index_type) {
632     case dex::kIndexStringRef:
633       return Alloc<String>(dex_ir->strings_map[index], index);
634 
635     case dex::kIndexTypeRef:
636       return Alloc<Type>(dex_ir->types_map[index], index);
637 
638     case dex::kIndexFieldRef:
639       return Alloc<Field>(dex_ir->fields_map[index], index);
640 
641     case dex::kIndexMethodRef:
642     case dex::kIndexMethodAndProtoRef:
643       return Alloc<Method>(dex_ir->methods_map[index], index);
644 
645     default:
646       std::stringstream ss;
647       ss << "Unexpected index type 0x";
648       ss << std::hex << std::setfill('0') << std::setw(2) << index_type;
649       SLICER_FATAL(ss.str());
650   }
651 }
652 
653 // Get the second indexed object (if any).
GetSecondIndexedOperand(dex::InstructionIndexType index_type,dex::u4 index)654 IndexedOperand* CodeIr::GetSecondIndexedOperand(dex::InstructionIndexType index_type,
655                                                 dex::u4 index) {
656   SLICER_CHECK_NE(index, dex::kNoIndex);
657   SLICER_CHECK_EQ(index_type, dex::kIndexMethodAndProtoRef);
658   return Alloc<Proto>(dex_ir->protos_map[index], index);
659 }
660 
661 // Get a type based on its index (potentially kNoIndex)
GetType(dex::u4 index)662 Type* CodeIr::GetType(dex::u4 index) {
663   auto ir_type = (index == dex::kNoIndex) ? nullptr : dex_ir->types_map[index];
664   return Alloc<Type>(ir_type, index);
665 }
666 
667 // Get a string based on its index (potentially kNoIndex)
GetString(dex::u4 index)668 String* CodeIr::GetString(dex::u4 index) {
669   auto ir_string = (index == dex::kNoIndex) ? nullptr : dex_ir->strings_map[index];
670   return Alloc<String>(ir_string, index);
671 }
672 
673 // Get en existing, or new label for a particular offset
GetLabel(dex::u4 offset)674 Label* CodeIr::GetLabel(dex::u4 offset) {
675   auto& p = labels_[offset];
676   if (p == nullptr) {
677     p = Alloc<Label>(offset);
678   }
679   ++p->refCount;
680   return p;
681 }
682 
683 }  // namespace lir
684