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