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 "disassembler.h"
18
19 #include <stdio.h>
20 #include <cinttypes>
21 #include <cmath>
22 #include <sstream>
23
24 // Builds a human readable method declaration, not including the name, ex:
25 // "(android.content.Context, android.content.pm.ActivityInfo) : java.lang.String"
MethodDeclaration(const ir::Proto * proto)26 static std::string MethodDeclaration(const ir::Proto* proto) {
27 std::stringstream ss;
28 ss << "(";
29 if (proto->param_types != nullptr) {
30 bool first = true;
31 for (auto type : proto->param_types->types) {
32 ss << (first ? "" : ", ") << type->Decl();
33 first = false;
34 }
35 }
36 ss << "):";
37 ss << proto->return_type->Decl();
38 return ss.str();
39 }
40
StartInstruction(const lir::Instruction * instr)41 void PrintCodeIrVisitor::StartInstruction(const lir::Instruction* instr) {
42 if (cfg_ == nullptr || current_block_index_ >= cfg_->basic_blocks.size()) {
43 return;
44 }
45 const lir::BasicBlock& current_block = cfg_->basic_blocks[current_block_index_];
46 if (instr == current_block.region.first) {
47 printf("............................. begin block %d .............................\n", current_block.id);
48 }
49 }
50
EndInstruction(const lir::Instruction * instr)51 void PrintCodeIrVisitor::EndInstruction(const lir::Instruction* instr) {
52 if (cfg_ == nullptr || current_block_index_ >= cfg_->basic_blocks.size()) {
53 return;
54 }
55 const lir::BasicBlock& current_block = cfg_->basic_blocks[current_block_index_];
56 if (instr == current_block.region.last) {
57 printf(".............................. end block %d ..............................\n", current_block.id);
58 ++current_block_index_;
59 }
60 }
61
Visit(lir::Bytecode * bytecode)62 bool PrintCodeIrVisitor::Visit(lir::Bytecode* bytecode) {
63 StartInstruction(bytecode);
64 printf("\t%5u| %s", bytecode->offset, dex::GetOpcodeName(bytecode->opcode));
65 bool first = true;
66 for (auto op : bytecode->operands) {
67 printf(first ? " " : ", ");
68 op->Accept(this);
69 first = false;
70 }
71 printf("\n");
72 EndInstruction(bytecode);
73 return true;
74 }
75
Visit(lir::PackedSwitchPayload * packed_switch)76 bool PrintCodeIrVisitor::Visit(lir::PackedSwitchPayload* packed_switch) {
77 StartInstruction(packed_switch);
78 printf("\t%5u| packed-switch-payload\n", packed_switch->offset);
79 int key = packed_switch->first_key;
80 for (auto target : packed_switch->targets) {
81 printf("\t\t%5d: ", key++);
82 printf("Label_%d", target->id);
83 printf("\n");
84 }
85 EndInstruction(packed_switch);
86 return true;
87 }
88
Visit(lir::SparseSwitchPayload * sparse_switch)89 bool PrintCodeIrVisitor::Visit(lir::SparseSwitchPayload* sparse_switch) {
90 StartInstruction(sparse_switch);
91 printf("\t%5u| sparse-switch-payload\n", sparse_switch->offset);
92 for (auto& switchCase : sparse_switch->switch_cases) {
93 printf("\t\t%5d: ", switchCase.key);
94 printf("Label_%d", switchCase.target->id);
95 printf("\n");
96 }
97 EndInstruction(sparse_switch);
98 return true;
99 }
100
Visit(lir::ArrayData * array_data)101 bool PrintCodeIrVisitor::Visit(lir::ArrayData* array_data) {
102 StartInstruction(array_data);
103 printf("\t%5u| fill-array-data-payload\n", array_data->offset);
104 EndInstruction(array_data);
105 return true;
106 }
107
Visit(lir::CodeLocation * target)108 bool PrintCodeIrVisitor::Visit(lir::CodeLocation* target) {
109 printf("Label_%d", target->label->id);
110 return true;
111 }
112
Visit(lir::Const32 * const32)113 bool PrintCodeIrVisitor::Visit(lir::Const32* const32) {
114 printf("#%+d (0x%08x | ", const32->u.s4_value, const32->u.u4_value);
115 if (std::isnan(const32->u.float_value)) {
116 printf("NaN)");
117 } else {
118 printf("%#.6g)", const32->u.float_value);
119 }
120 return true;
121 }
122
Visit(lir::Const64 * const64)123 bool PrintCodeIrVisitor::Visit(lir::Const64* const64) {
124 printf("#%+" PRId64 " (0x%016" PRIx64 " | ", const64->u.s8_value, const64->u.u8_value);
125 if (std::isnan(const64->u.double_value)) {
126 printf("NaN)");
127 } else {
128 printf("%#.6g)", const64->u.double_value);
129 }
130 return true;
131 }
132
Visit(lir::VReg * vreg)133 bool PrintCodeIrVisitor::Visit(lir::VReg* vreg) {
134 printf("v%d", vreg->reg);
135 return true;
136 }
137
Visit(lir::VRegPair * vreg_pair)138 bool PrintCodeIrVisitor::Visit(lir::VRegPair* vreg_pair) {
139 printf("v%d:v%d", vreg_pair->base_reg, vreg_pair->base_reg + 1);
140 return true;
141 }
142
Visit(lir::VRegList * vreg_list)143 bool PrintCodeIrVisitor::Visit(lir::VRegList* vreg_list) {
144 bool first = true;
145 printf("{");
146 for (auto reg : vreg_list->registers) {
147 printf("%sv%d", (first ? "" : ","), reg);
148 first = false;
149 }
150 printf("}");
151 return true;
152 }
153
Visit(lir::VRegRange * vreg_range)154 bool PrintCodeIrVisitor::Visit(lir::VRegRange* vreg_range) {
155 if (vreg_range->count == 0) {
156 printf("{}");
157 } else {
158 printf("{v%d..v%d}", vreg_range->base_reg,
159 vreg_range->base_reg + vreg_range->count - 1);
160 }
161 return true;
162 }
163
Visit(lir::String * string)164 bool PrintCodeIrVisitor::Visit(lir::String* string) {
165 if (string->ir_string == nullptr) {
166 printf("<null>");
167 return true;
168 }
169 auto ir_string = string->ir_string;
170 printf("\"");
171 for (const char* p = ir_string->c_str(); *p != '\0'; ++p) {
172 if (::isprint(*p)) {
173 printf("%c", *p);
174 } else {
175 switch (*p) {
176 case '\'': printf("\\'"); break;
177 case '\"': printf("\\\""); break;
178 case '\?': printf("\\?"); break;
179 case '\\': printf("\\\\"); break;
180 case '\a': printf("\\a"); break;
181 case '\b': printf("\\b"); break;
182 case '\f': printf("\\f"); break;
183 case '\n': printf("\\n"); break;
184 case '\r': printf("\\r"); break;
185 case '\t': printf("\\t"); break;
186 case '\v': printf("\\v"); break;
187 default:
188 printf("\\x%02x", *p);
189 break;
190 }
191 }
192 }
193 printf("\"");
194 return true;
195 }
196
Visit(lir::Type * type)197 bool PrintCodeIrVisitor::Visit(lir::Type* type) {
198 SLICER_CHECK_NE(type->index, dex::kNoIndex);
199 auto ir_type = type->ir_type;
200 printf("%s", ir_type->Decl().c_str());
201 return true;
202 }
203
Visit(lir::Field * field)204 bool PrintCodeIrVisitor::Visit(lir::Field* field) {
205 SLICER_CHECK_NE(field->index, dex::kNoIndex);
206 auto ir_field = field->ir_field;
207 printf("%s.%s", ir_field->parent->Decl().c_str(), ir_field->name->c_str());
208 return true;
209 }
210
Visit(lir::Method * method)211 bool PrintCodeIrVisitor::Visit(lir::Method* method) {
212 SLICER_CHECK_NE(method->index, dex::kNoIndex);
213 auto ir_method = method->ir_method;
214 printf("%s.%s%s",
215 ir_method->parent->Decl().c_str(),
216 ir_method->name->c_str(),
217 MethodDeclaration(ir_method->prototype).c_str());
218 return true;
219 }
220
Visit(lir::MethodHandle * method_handle)221 bool PrintCodeIrVisitor::Visit(lir::MethodHandle* method_handle){
222 SLICER_CHECK_NE(method_handle->index, dex::kNoIndex);
223 auto ir_method_handle = method_handle->ir_method_handle;
224 if(ir_method_handle->IsField()){
225 printf("%s", ir_method_handle->field->name->c_str());
226 }
227 else {
228 printf("%s", ir_method_handle->method->name->c_str());
229 }
230 return true;
231 }
232
Visit(lir::Proto * proto)233 bool PrintCodeIrVisitor::Visit(lir::Proto* proto) {
234 SLICER_CHECK_NE(proto->index, dex::kNoIndex);
235 auto ir_proto = proto->ir_proto;
236 printf("%s", MethodDeclaration(ir_proto).c_str());
237 return true;
238 }
239
Visit(lir::LineNumber * line_number)240 bool PrintCodeIrVisitor::Visit(lir::LineNumber* line_number) {
241 printf("%d", line_number->line);
242 return true;
243 }
244
Visit(lir::Label * label)245 bool PrintCodeIrVisitor::Visit(lir::Label* label) {
246 StartInstruction(label);
247 printf("Label_%d:%s\n", label->id, (label->aligned ? " <aligned>" : ""));
248 EndInstruction(label);
249 return true;
250 }
251
Visit(lir::TryBlockBegin * try_begin)252 bool PrintCodeIrVisitor::Visit(lir::TryBlockBegin* try_begin) {
253 StartInstruction(try_begin);
254 printf("\t.try_begin_%d\n", try_begin->id);
255 EndInstruction(try_begin);
256 return true;
257 }
258
Visit(lir::TryBlockEnd * try_end)259 bool PrintCodeIrVisitor::Visit(lir::TryBlockEnd* try_end) {
260 StartInstruction(try_end);
261 printf("\t.try_end_%d\n", try_end->try_begin->id);
262 for (const auto& handler : try_end->handlers) {
263 printf("\t catch(%s) : Label_%d\n", handler.ir_type->Decl().c_str(),
264 handler.label->id);
265 }
266 if (try_end->catch_all != nullptr) {
267 printf("\t catch(...) : Label_%d\n", try_end->catch_all->id);
268 }
269 EndInstruction(try_end);
270 return true;
271 }
272
Visit(lir::DbgInfoHeader * dbg_header)273 bool PrintCodeIrVisitor::Visit(lir::DbgInfoHeader* dbg_header) {
274 StartInstruction(dbg_header);
275 printf("\t.params");
276 bool first = true;
277 for (auto paramName : dbg_header->param_names) {
278 printf(first ? " " : ", ");
279 printf("\"%s\"", paramName ? paramName->c_str() : "?");
280 first = false;
281 }
282 printf("\n");
283 EndInstruction(dbg_header);
284 return true;
285 }
286
Visit(lir::DbgInfoAnnotation * annotation)287 bool PrintCodeIrVisitor::Visit(lir::DbgInfoAnnotation* annotation) {
288 StartInstruction(annotation);
289 const char* name = ".dbg_???";
290 switch (annotation->dbg_opcode) {
291 case dex::DBG_START_LOCAL:
292 name = ".local";
293 break;
294 case dex::DBG_START_LOCAL_EXTENDED:
295 name = ".local_ex";
296 break;
297 case dex::DBG_END_LOCAL:
298 name = ".end_local";
299 break;
300 case dex::DBG_RESTART_LOCAL:
301 name = ".restart_local";
302 break;
303 case dex::DBG_SET_PROLOGUE_END:
304 name = ".prologue_end";
305 break;
306 case dex::DBG_SET_EPILOGUE_BEGIN:
307 name = ".epilogue_begin";
308 break;
309 case dex::DBG_ADVANCE_LINE:
310 name = ".line";
311 break;
312 case dex::DBG_SET_FILE:
313 name = ".src";
314 break;
315 }
316 printf("\t%s", name);
317
318 bool first = true;
319 for (auto op : annotation->operands) {
320 printf(first ? " " : ", ");
321 op->Accept(this);
322 first = false;
323 }
324
325 printf("\n");
326 EndInstruction(annotation);
327 return true;
328 }
329
DumpAllMethods() const330 void DexDisassembler::DumpAllMethods() const {
331 for (auto& ir_method : dex_ir_->encoded_methods) {
332 DumpMethod(ir_method.get());
333 }
334 }
335
DumpMethod(ir::EncodedMethod * ir_method) const336 void DexDisassembler::DumpMethod(ir::EncodedMethod* ir_method) const {
337 printf("\nmethod %s.%s%s\n{\n",
338 ir_method->decl->parent->Decl().c_str(),
339 ir_method->decl->name->c_str(),
340 MethodDeclaration(ir_method->decl->prototype).c_str());
341 Disassemble(ir_method);
342 printf("}\n");
343 }
344
Disassemble(ir::EncodedMethod * ir_method) const345 void DexDisassembler::Disassemble(ir::EncodedMethod* ir_method) const {
346 lir::CodeIr code_ir(ir_method, dex_ir_);
347 std::unique_ptr<lir::ControlFlowGraph> cfg;
348 switch (cfg_type_) {
349 case CfgType::Compact:
350 cfg.reset(new lir::ControlFlowGraph(&code_ir, false));
351 break;
352 case CfgType::Verbose:
353 cfg.reset(new lir::ControlFlowGraph(&code_ir, true));
354 break;
355 default:
356 break;
357 }
358 PrintCodeIrVisitor visitor(dex_ir_, cfg.get());
359 code_ir.Accept(&visitor);
360 }
361