1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
|
/*
* Copyright (C) 2018 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.
*/
#ifndef ART_TOOLS_VERIDEX_FLOW_ANALYSIS_H_
#define ART_TOOLS_VERIDEX_FLOW_ANALYSIS_H_
#include "dex/class_accessor.h"
#include "dex/code_item_accessors.h"
#include "dex/dex_file_reference.h"
#include "dex/method_reference.h"
#include "hidden_api.h"
#include "resolver.h"
#include "veridex.h"
namespace art {
/**
* The source where a dex register comes from.
*/
enum class RegisterSource {
kParameter,
kField,
kMethod,
kClass,
kString,
kConstant,
kNone
};
/**
* Abstract representation of a dex register value.
*/
class RegisterValue {
public:
RegisterValue() : source_(RegisterSource::kNone),
value_(0),
reference_(nullptr, 0),
type_(nullptr) {}
RegisterValue(RegisterSource source, DexFileReference reference, const VeriClass* type)
: source_(source), value_(0), reference_(reference), type_(type) {}
RegisterValue(RegisterSource source,
uint32_t value,
DexFileReference reference,
const VeriClass* type)
: source_(source), value_(value), reference_(reference), type_(type) {}
RegisterSource GetSource() const { return source_; }
DexFileReference GetDexFileReference() const { return reference_; }
const VeriClass* GetType() const { return type_; }
uint32_t GetParameterIndex() const {
CHECK(IsParameter());
return value_;
}
uint32_t GetConstant() const {
CHECK(IsConstant());
return value_;
}
bool IsParameter() const { return source_ == RegisterSource::kParameter; }
bool IsClass() const { return source_ == RegisterSource::kClass; }
bool IsString() const { return source_ == RegisterSource::kString; }
bool IsConstant() const { return source_ == RegisterSource::kConstant; }
std::string ToString() const {
switch (source_) {
case RegisterSource::kString: {
const char* str = reference_.dex_file->StringDataByIdx(dex::StringIndex(reference_.index));
if (type_ == VeriClass::class_) {
// Class names at the Java level are of the form x.y.z, but the list encodes
// them of the form Lx/y/z;. Inner classes have '$' for both Java level class
// names in strings, and hidden API lists.
return HiddenApi::ToInternalName(str);
} else {
return str;
}
}
case RegisterSource::kClass:
return reference_.dex_file->StringByTypeIdx(dex::TypeIndex(reference_.index));
case RegisterSource::kParameter:
return std::string("Parameter of ") + reference_.dex_file->PrettyMethod(reference_.index);
default:
return "<unknown>";
}
}
private:
RegisterSource source_;
uint32_t value_;
DexFileReference reference_;
const VeriClass* type_;
};
struct InstructionInfo {
bool has_been_visited;
};
class VeriFlowAnalysis {
public:
VeriFlowAnalysis(VeridexResolver* resolver, const ClassAccessor::Method& method);
void Run();
virtual RegisterValue AnalyzeInvoke(const Instruction& instruction, bool is_range) = 0;
virtual void AnalyzeFieldSet(const Instruction& instruction) = 0;
virtual ~VeriFlowAnalysis() {}
private:
// Find all branches in the code.
void FindBranches();
// Analyze all non-deead instructions in the code.
void AnalyzeCode();
// Set the instruction at the given pc as a branch target.
void SetAsBranchTarget(uint32_t dex_pc);
// Whether the instruction at the given pc is a branch target.
bool IsBranchTarget(uint32_t dex_pc);
// Merge the register values at the given pc with `current_registers`.
// Return whether the register values have changed, and the instruction needs
// to be visited again.
bool MergeRegisterValues(uint32_t dex_pc);
void UpdateRegister(
uint32_t dex_register, RegisterSource kind, VeriClass* cls, uint32_t source_id);
void UpdateRegister(uint32_t dex_register, const RegisterValue& value);
void UpdateRegister(uint32_t dex_register, const VeriClass* cls);
void UpdateRegister(uint32_t dex_register, int32_t value, const VeriClass* cls);
void ProcessDexInstruction(const Instruction& inst);
void SetVisited(uint32_t dex_pc);
RegisterValue GetFieldType(uint32_t field_index);
int GetBranchFlags(const Instruction& instruction) const;
protected:
const RegisterValue& GetRegister(uint32_t dex_register) const;
RegisterValue GetReturnType(uint32_t method_index);
VeridexResolver* resolver_;
private:
const uint32_t method_id_;
CodeItemDataAccessor code_item_accessor_;
// Vector of register values for all branch targets.
std::vector<std::unique_ptr<std::vector<RegisterValue>>> dex_registers_;
// The current values of dex registers.
std::vector<RegisterValue> current_registers_;
// Information on each instruction useful for the analysis.
std::vector<InstructionInfo> instruction_infos_;
// The value of invoke instructions, to be fetched when visiting move-result.
RegisterValue last_result_;
};
struct ReflectAccessInfo {
RegisterValue cls;
RegisterValue name;
bool is_method;
ReflectAccessInfo(RegisterValue c, RegisterValue n, bool is_method)
: cls(c), name(n), is_method(is_method) {}
bool IsConcrete() const {
// We capture RegisterSource::kString for the class, for example in Class.forName.
return (cls.IsClass() || cls.IsString()) && name.IsString();
}
};
// Collects all reflection uses.
class FlowAnalysisCollector : public VeriFlowAnalysis {
public:
FlowAnalysisCollector(VeridexResolver* resolver, const ClassAccessor::Method& method)
: VeriFlowAnalysis(resolver, method) {}
const std::vector<ReflectAccessInfo>& GetUses() const {
return uses_;
}
RegisterValue AnalyzeInvoke(const Instruction& instruction, bool is_range) override;
void AnalyzeFieldSet(const Instruction& instruction) override;
private:
// List of reflection uses found, concrete and abstract.
std::vector<ReflectAccessInfo> uses_;
};
// Substitutes reflection uses by new ones.
class FlowAnalysisSubstitutor : public VeriFlowAnalysis {
public:
FlowAnalysisSubstitutor(VeridexResolver* resolver,
const ClassAccessor::Method& method,
const std::map<MethodReference, std::vector<ReflectAccessInfo>>& accesses)
: VeriFlowAnalysis(resolver, method), accesses_(accesses) {}
const std::vector<ReflectAccessInfo>& GetUses() const {
return uses_;
}
RegisterValue AnalyzeInvoke(const Instruction& instruction, bool is_range) override;
void AnalyzeFieldSet(const Instruction& instruction) override;
private:
// List of reflection uses found, concrete and abstract.
std::vector<ReflectAccessInfo> uses_;
// The abstract uses we are trying to subsititute.
const std::map<MethodReference, std::vector<ReflectAccessInfo>>& accesses_;
};
} // namespace art
#endif // ART_TOOLS_VERIDEX_FLOW_ANALYSIS_H_
|