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 
Match(MethodDecl * method_decl) const24 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 
FindMethod(const MethodId & method_id) const30 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 
FindPrototype(const char * signature) const52 Proto* Builder::FindPrototype(const char* signature) const {
53   return dex_ir_->prototypes_lookup.Lookup(signature);
54 }
55 
FindAsciiString(const char * cstr) const56 String* Builder::FindAsciiString(const char* cstr) const {
57     return dex_ir_->strings_lookup.Lookup(cstr);
58 }
59 
GetAsciiString(const char * cstr)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 
GetType(String * descriptor)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 
GetTypeList(const std::vector<Type * > & types)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()
CreateShorty(Type * return_type,TypeList * param_types)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 
GetProto(Type * return_type,TypeList * param_types)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 
GetFieldDecl(String * name,Type * type,Type * parent)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 
GetMethodDecl(String * name,Proto * proto,Type * parent)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