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 "slicer/dex_ir_builder.h" 18 19 #include <sstream> 20 #include <string.h> 21 22 namespace ir { 23 24 bool MethodId::Match(MethodDecl* method_decl) const { 25 return ::strcmp(class_descriptor, method_decl->parent->descriptor->c_str()) == 0 26 && ::strcmp(method_name, method_decl->name->c_str()) == 0 27 && method_decl->prototype->Signature() == signature; 28 } 29 30 EncodedMethod* Builder::FindMethod(const MethodId& method_id) const { 31 // first, lookup the strings 32 auto ir_descriptor = FindAsciiString(method_id.class_descriptor); 33 auto ir_method_name = FindAsciiString(method_id.method_name); 34 if (ir_descriptor == nullptr || ir_method_name == nullptr) { 35 return nullptr; 36 } 37 38 // look up the prototype 39 auto ir_prototype = FindPrototype(method_id.signature); 40 if (ir_prototype == nullptr) { 41 return nullptr; 42 } 43 44 // look up the method itself 45 ir::MethodKey method_key; 46 method_key.class_descriptor = ir_descriptor; 47 method_key.method_name = ir_method_name; 48 method_key.prototype = ir_prototype; 49 return dex_ir_->methods_lookup.Lookup(method_key); 50 } 51 52 Proto* Builder::FindPrototype(const char* signature) const { 53 return dex_ir_->prototypes_lookup.Lookup(signature); 54 } 55 56 String* Builder::FindAsciiString(const char* cstr) const { 57 return dex_ir_->strings_lookup.Lookup(cstr); 58 } 59 60 String* Builder::GetAsciiString(const char* cstr) { 61 // look for the string first... 62 auto ir_string = FindAsciiString(cstr); 63 if(ir_string != nullptr) { 64 return ir_string; 65 } 66 67 // create a new string data 68 dex::u4 len = strlen(cstr); 69 slicer::Buffer buff; 70 buff.PushULeb128(len); 71 buff.Push(cstr, len + 1); 72 buff.Seal(1); 73 74 // create the new .dex IR string node 75 ir_string = dex_ir_->Alloc<String>(); 76 ir_string->data = slicer::MemView(buff.data(), buff.size()); 77 78 // update the index -> ir node map 79 auto new_index = dex_ir_->strings_indexes.AllocateIndex(); 80 auto& ir_node = dex_ir_->strings_map[new_index]; 81 SLICER_CHECK(ir_node == nullptr); 82 ir_node = ir_string; 83 ir_string->orig_index = new_index; 84 85 // attach the new string data to the .dex IR 86 dex_ir_->AttachBuffer(std::move(buff)); 87 88 // update the strings lookup table 89 dex_ir_->strings_lookup.Insert(ir_string); 90 91 return ir_string; 92 } 93 94 Type* Builder::GetType(String* descriptor) { 95 // look for an existing type 96 for (const auto& ir_type : dex_ir_->types) { 97 if (ir_type->descriptor == descriptor) { 98 return ir_type.get(); 99 } 100 } 101 102 // create a new type 103 auto ir_type = dex_ir_->Alloc<Type>(); 104 ir_type->descriptor = descriptor; 105 106 // update the index -> ir node map 107 auto new_index = dex_ir_->types_indexes.AllocateIndex(); 108 auto& ir_node = dex_ir_->types_map[new_index]; 109 SLICER_CHECK(ir_node == nullptr); 110 ir_node = ir_type; 111 ir_type->orig_index = new_index; 112 113 return ir_type; 114 } 115 116 TypeList* Builder::GetTypeList(const std::vector<Type*>& types) { 117 if (types.empty()) { 118 return nullptr; 119 } 120 121 // look for an existing TypeList 122 for (const auto& ir_type_list : dex_ir_->type_lists) { 123 if (ir_type_list->types == types) { 124 return ir_type_list.get(); 125 } 126 } 127 128 // create a new TypeList 129 auto ir_type_list = dex_ir_->Alloc<TypeList>(); 130 ir_type_list->types = types; 131 return ir_type_list; 132 } 133 134 // Helper for GetProto() 135 static std::string CreateShorty(Type* return_type, TypeList* param_types) { 136 std::stringstream ss; 137 ss << dex::DescriptorToShorty(return_type->descriptor->c_str()); 138 if (param_types != nullptr) { 139 for (auto param_type : param_types->types) { 140 ss << dex::DescriptorToShorty(param_type->descriptor->c_str()); 141 } 142 } 143 return ss.str(); 144 } 145 146 Proto* Builder::GetProto(Type* return_type, TypeList* param_types) { 147 // create "shorty" descriptor automatically 148 auto shorty = GetAsciiString(CreateShorty(return_type, param_types).c_str()); 149 150 // look for an existing proto 151 for (const auto& ir_proto : dex_ir_->protos) { 152 if (ir_proto->shorty == shorty && 153 ir_proto->return_type == return_type && 154 ir_proto->param_types == param_types) { 155 return ir_proto.get(); 156 } 157 } 158 159 // create a new proto 160 auto ir_proto = dex_ir_->Alloc<Proto>(); 161 ir_proto->shorty = shorty; 162 ir_proto->return_type = return_type; 163 ir_proto->param_types = param_types; 164 165 // update the index -> ir node map 166 auto new_index = dex_ir_->protos_indexes.AllocateIndex(); 167 auto& ir_node = dex_ir_->protos_map[new_index]; 168 SLICER_CHECK(ir_node == nullptr); 169 ir_node = ir_proto; 170 ir_proto->orig_index = new_index; 171 172 // update the prototypes lookup table 173 dex_ir_->prototypes_lookup.Insert(ir_proto); 174 175 return ir_proto; 176 } 177 178 FieldDecl* Builder::GetFieldDecl(String* name, Type* type, Type* parent) { 179 // look for an existing field 180 for (const auto& ir_field : dex_ir_->fields) { 181 if (ir_field->name == name && 182 ir_field->type == type && 183 ir_field->parent == parent) { 184 return ir_field.get(); 185 } 186 } 187 188 // create a new field declaration 189 auto ir_field = dex_ir_->Alloc<FieldDecl>(); 190 ir_field->name = name; 191 ir_field->type = type; 192 ir_field->parent = parent; 193 194 // update the index -> ir node map 195 auto new_index = dex_ir_->fields_indexes.AllocateIndex(); 196 auto& ir_node = dex_ir_->fields_map[new_index]; 197 SLICER_CHECK(ir_node == nullptr); 198 ir_node = ir_field; 199 ir_field->orig_index = new_index; 200 201 return ir_field; 202 } 203 204 MethodDecl* Builder::GetMethodDecl(String* name, Proto* proto, Type* parent) { 205 // look for an existing method 206 for (const auto& ir_method : dex_ir_->methods) { 207 if (ir_method->name == name && 208 ir_method->prototype == proto && 209 ir_method->parent == parent) { 210 return ir_method.get(); 211 } 212 } 213 214 // create a new method declaration 215 auto ir_method = dex_ir_->Alloc<MethodDecl>(); 216 ir_method->name = name; 217 ir_method->prototype = proto; 218 ir_method->parent = parent; 219 220 // update the index -> ir node map 221 auto new_index = dex_ir_->methods_indexes.AllocateIndex(); 222 auto& ir_node = dex_ir_->methods_map[new_index]; 223 SLICER_CHECK(ir_node == nullptr); 224 ir_node = ir_method; 225 ir_method->orig_index = new_index; 226 227 return ir_method; 228 } 229 230 } // namespace ir 231 232