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