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::Proto * proto)221 bool PrintCodeIrVisitor::Visit(lir::Proto* proto) {
222 SLICER_CHECK_NE(proto->index, dex::kNoIndex);
223 auto ir_proto = proto->ir_proto;
224 printf("%s", MethodDeclaration(ir_proto).c_str());
225 return true;
226 }
227
Visit(lir::LineNumber * line_number)228 bool PrintCodeIrVisitor::Visit(lir::LineNumber* line_number) {
229 printf("%d", line_number->line);
230 return true;
231 }
232
Visit(lir::Label * label)233 bool PrintCodeIrVisitor::Visit(lir::Label* label) {
234 StartInstruction(label);
235 printf("Label_%d:%s\n", label->id, (label->aligned ? " <aligned>" : ""));
236 EndInstruction(label);
237 return true;
238 }
239
Visit(lir::TryBlockBegin * try_begin)240 bool PrintCodeIrVisitor::Visit(lir::TryBlockBegin* try_begin) {
241 StartInstruction(try_begin);
242 printf("\t.try_begin_%d\n", try_begin->id);
243 EndInstruction(try_begin);
244 return true;
245 }
246
Visit(lir::TryBlockEnd * try_end)247 bool PrintCodeIrVisitor::Visit(lir::TryBlockEnd* try_end) {
248 StartInstruction(try_end);
249 printf("\t.try_end_%d\n", try_end->try_begin->id);
250 for (const auto& handler : try_end->handlers) {
251 printf("\t catch(%s) : Label_%d\n", handler.ir_type->Decl().c_str(),
252 handler.label->id);
253 }
254 if (try_end->catch_all != nullptr) {
255 printf("\t catch(...) : Label_%d\n", try_end->catch_all->id);
256 }
257 EndInstruction(try_end);
258 return true;
259 }
260
Visit(lir::DbgInfoHeader * dbg_header)261 bool PrintCodeIrVisitor::Visit(lir::DbgInfoHeader* dbg_header) {
262 StartInstruction(dbg_header);
263 printf("\t.params");
264 bool first = true;
265 for (auto paramName : dbg_header->param_names) {
266 printf(first ? " " : ", ");
267 printf("\"%s\"", paramName ? paramName->c_str() : "?");
268 first = false;
269 }
270 printf("\n");
271 EndInstruction(dbg_header);
272 return true;
273 }
274
Visit(lir::DbgInfoAnnotation * annotation)275 bool PrintCodeIrVisitor::Visit(lir::DbgInfoAnnotation* annotation) {
276 StartInstruction(annotation);
277 const char* name = ".dbg_???";
278 switch (annotation->dbg_opcode) {
279 case dex::DBG_START_LOCAL:
280 name = ".local";
281 break;
282 case dex::DBG_START_LOCAL_EXTENDED:
283 name = ".local_ex";
284 break;
285 case dex::DBG_END_LOCAL:
286 name = ".end_local";
287 break;
288 case dex::DBG_RESTART_LOCAL:
289 name = ".restart_local";
290 break;
291 case dex::DBG_SET_PROLOGUE_END:
292 name = ".prologue_end";
293 break;
294 case dex::DBG_SET_EPILOGUE_BEGIN:
295 name = ".epilogue_begin";
296 break;
297 case dex::DBG_ADVANCE_LINE:
298 name = ".line";
299 break;
300 case dex::DBG_SET_FILE:
301 name = ".src";
302 break;
303 }
304 printf("\t%s", name);
305
306 bool first = true;
307 for (auto op : annotation->operands) {
308 printf(first ? " " : ", ");
309 op->Accept(this);
310 first = false;
311 }
312
313 printf("\n");
314 EndInstruction(annotation);
315 return true;
316 }
317
DumpAllMethods() const318 void DexDisassembler::DumpAllMethods() const {
319 for (auto& ir_method : dex_ir_->encoded_methods) {
320 DumpMethod(ir_method.get());
321 }
322 }
323
DumpMethod(ir::EncodedMethod * ir_method) const324 void DexDisassembler::DumpMethod(ir::EncodedMethod* ir_method) const {
325 printf("\nmethod %s.%s%s\n{\n",
326 ir_method->decl->parent->Decl().c_str(),
327 ir_method->decl->name->c_str(),
328 MethodDeclaration(ir_method->decl->prototype).c_str());
329 Disassemble(ir_method);
330 printf("}\n");
331 }
332
Disassemble(ir::EncodedMethod * ir_method) const333 void DexDisassembler::Disassemble(ir::EncodedMethod* ir_method) const {
334 lir::CodeIr code_ir(ir_method, dex_ir_);
335 std::unique_ptr<lir::ControlFlowGraph> cfg;
336 switch (cfg_type_) {
337 case CfgType::Compact:
338 cfg.reset(new lir::ControlFlowGraph(&code_ir, false));
339 break;
340 case CfgType::Verbose:
341 cfg.reset(new lir::ControlFlowGraph(&code_ir, true));
342 break;
343 default:
344 break;
345 }
346 PrintCodeIrVisitor visitor(dex_ir_, cfg.get());
347 code_ir.Accept(&visitor);
348 }
349