• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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