You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
6.5 KiB
232 lines
6.5 KiB
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "slicer/dex_ir_builder.h"
|
|
|
|
#include <sstream>
|
|
#include <string.h>
|
|
|
|
namespace ir {
|
|
|
|
bool MethodId::Match(MethodDecl* method_decl) const {
|
|
return ::strcmp(class_descriptor, method_decl->parent->descriptor->c_str()) == 0
|
|
&& ::strcmp(method_name, method_decl->name->c_str()) == 0
|
|
&& method_decl->prototype->Signature() == signature;
|
|
}
|
|
|
|
EncodedMethod* Builder::FindMethod(const MethodId& method_id) const {
|
|
// first, lookup the strings
|
|
auto ir_descriptor = FindAsciiString(method_id.class_descriptor);
|
|
auto ir_method_name = FindAsciiString(method_id.method_name);
|
|
if (ir_descriptor == nullptr || ir_method_name == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
// look up the prototype
|
|
auto ir_prototype = FindPrototype(method_id.signature);
|
|
if (ir_prototype == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
// look up the method itself
|
|
ir::MethodKey method_key;
|
|
method_key.class_descriptor = ir_descriptor;
|
|
method_key.method_name = ir_method_name;
|
|
method_key.prototype = ir_prototype;
|
|
return dex_ir_->methods_lookup.Lookup(method_key);
|
|
}
|
|
|
|
Proto* Builder::FindPrototype(const char* signature) const {
|
|
return dex_ir_->prototypes_lookup.Lookup(signature);
|
|
}
|
|
|
|
String* Builder::FindAsciiString(const char* cstr) const {
|
|
return dex_ir_->strings_lookup.Lookup(cstr);
|
|
}
|
|
|
|
String* Builder::GetAsciiString(const char* cstr) {
|
|
// look for the string first...
|
|
auto ir_string = FindAsciiString(cstr);
|
|
if(ir_string != nullptr) {
|
|
return ir_string;
|
|
}
|
|
|
|
// create a new string data
|
|
dex::u4 len = strlen(cstr);
|
|
slicer::Buffer buff;
|
|
buff.PushULeb128(len);
|
|
buff.Push(cstr, len + 1);
|
|
buff.Seal(1);
|
|
|
|
// create the new .dex IR string node
|
|
ir_string = dex_ir_->Alloc<String>();
|
|
ir_string->data = slicer::MemView(buff.data(), buff.size());
|
|
|
|
// update the index -> ir node map
|
|
auto new_index = dex_ir_->strings_indexes.AllocateIndex();
|
|
auto& ir_node = dex_ir_->strings_map[new_index];
|
|
SLICER_CHECK(ir_node == nullptr);
|
|
ir_node = ir_string;
|
|
ir_string->orig_index = new_index;
|
|
|
|
// attach the new string data to the .dex IR
|
|
dex_ir_->AttachBuffer(std::move(buff));
|
|
|
|
// update the strings lookup table
|
|
dex_ir_->strings_lookup.Insert(ir_string);
|
|
|
|
return ir_string;
|
|
}
|
|
|
|
Type* Builder::GetType(String* descriptor) {
|
|
// look for an existing type
|
|
for (const auto& ir_type : dex_ir_->types) {
|
|
if (ir_type->descriptor == descriptor) {
|
|
return ir_type.get();
|
|
}
|
|
}
|
|
|
|
// create a new type
|
|
auto ir_type = dex_ir_->Alloc<Type>();
|
|
ir_type->descriptor = descriptor;
|
|
|
|
// update the index -> ir node map
|
|
auto new_index = dex_ir_->types_indexes.AllocateIndex();
|
|
auto& ir_node = dex_ir_->types_map[new_index];
|
|
SLICER_CHECK(ir_node == nullptr);
|
|
ir_node = ir_type;
|
|
ir_type->orig_index = new_index;
|
|
|
|
return ir_type;
|
|
}
|
|
|
|
TypeList* Builder::GetTypeList(const std::vector<Type*>& types) {
|
|
if (types.empty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
// look for an existing TypeList
|
|
for (const auto& ir_type_list : dex_ir_->type_lists) {
|
|
if (ir_type_list->types == types) {
|
|
return ir_type_list.get();
|
|
}
|
|
}
|
|
|
|
// create a new TypeList
|
|
auto ir_type_list = dex_ir_->Alloc<TypeList>();
|
|
ir_type_list->types = types;
|
|
return ir_type_list;
|
|
}
|
|
|
|
// Helper for GetProto()
|
|
static std::string CreateShorty(Type* return_type, TypeList* param_types) {
|
|
std::stringstream ss;
|
|
ss << dex::DescriptorToShorty(return_type->descriptor->c_str());
|
|
if (param_types != nullptr) {
|
|
for (auto param_type : param_types->types) {
|
|
ss << dex::DescriptorToShorty(param_type->descriptor->c_str());
|
|
}
|
|
}
|
|
return ss.str();
|
|
}
|
|
|
|
Proto* Builder::GetProto(Type* return_type, TypeList* param_types) {
|
|
// create "shorty" descriptor automatically
|
|
auto shorty = GetAsciiString(CreateShorty(return_type, param_types).c_str());
|
|
|
|
// look for an existing proto
|
|
for (const auto& ir_proto : dex_ir_->protos) {
|
|
if (ir_proto->shorty == shorty &&
|
|
ir_proto->return_type == return_type &&
|
|
ir_proto->param_types == param_types) {
|
|
return ir_proto.get();
|
|
}
|
|
}
|
|
|
|
// create a new proto
|
|
auto ir_proto = dex_ir_->Alloc<Proto>();
|
|
ir_proto->shorty = shorty;
|
|
ir_proto->return_type = return_type;
|
|
ir_proto->param_types = param_types;
|
|
|
|
// update the index -> ir node map
|
|
auto new_index = dex_ir_->protos_indexes.AllocateIndex();
|
|
auto& ir_node = dex_ir_->protos_map[new_index];
|
|
SLICER_CHECK(ir_node == nullptr);
|
|
ir_node = ir_proto;
|
|
ir_proto->orig_index = new_index;
|
|
|
|
// update the prototypes lookup table
|
|
dex_ir_->prototypes_lookup.Insert(ir_proto);
|
|
|
|
return ir_proto;
|
|
}
|
|
|
|
FieldDecl* Builder::GetFieldDecl(String* name, Type* type, Type* parent) {
|
|
// look for an existing field
|
|
for (const auto& ir_field : dex_ir_->fields) {
|
|
if (ir_field->name == name &&
|
|
ir_field->type == type &&
|
|
ir_field->parent == parent) {
|
|
return ir_field.get();
|
|
}
|
|
}
|
|
|
|
// create a new field declaration
|
|
auto ir_field = dex_ir_->Alloc<FieldDecl>();
|
|
ir_field->name = name;
|
|
ir_field->type = type;
|
|
ir_field->parent = parent;
|
|
|
|
// update the index -> ir node map
|
|
auto new_index = dex_ir_->fields_indexes.AllocateIndex();
|
|
auto& ir_node = dex_ir_->fields_map[new_index];
|
|
SLICER_CHECK(ir_node == nullptr);
|
|
ir_node = ir_field;
|
|
ir_field->orig_index = new_index;
|
|
|
|
return ir_field;
|
|
}
|
|
|
|
MethodDecl* Builder::GetMethodDecl(String* name, Proto* proto, Type* parent) {
|
|
// look for an existing method
|
|
for (const auto& ir_method : dex_ir_->methods) {
|
|
if (ir_method->name == name &&
|
|
ir_method->prototype == proto &&
|
|
ir_method->parent == parent) {
|
|
return ir_method.get();
|
|
}
|
|
}
|
|
|
|
// create a new method declaration
|
|
auto ir_method = dex_ir_->Alloc<MethodDecl>();
|
|
ir_method->name = name;
|
|
ir_method->prototype = proto;
|
|
ir_method->parent = parent;
|
|
|
|
// update the index -> ir node map
|
|
auto new_index = dex_ir_->methods_indexes.AllocateIndex();
|
|
auto& ir_node = dex_ir_->methods_map[new_index];
|
|
SLICER_CHECK(ir_node == nullptr);
|
|
ir_node = ir_method;
|
|
ir_method->orig_index = new_index;
|
|
|
|
return ir_method;
|
|
}
|
|
|
|
} // namespace ir
|
|
|