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