blob: 2151a41725b1b45d82d3e74bddf56182768ec837 [file] [log] [blame]
Nicolas Geoffray2ebff052018-04-04 22:32:03 +01001/*
2 * Copyright (C) 2018 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#ifndef ART_TOOLS_VERIDEX_FLOW_ANALYSIS_H_
18#define ART_TOOLS_VERIDEX_FLOW_ANALYSIS_H_
19
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -070020#include "dex/class_accessor.h"
Nicolas Geoffray2ebff052018-04-04 22:32:03 +010021#include "dex/code_item_accessors.h"
22#include "dex/dex_file_reference.h"
23#include "dex/method_reference.h"
Nicolas Geoffray4f6e5232018-04-18 12:54:04 +010024#include "hidden_api.h"
Nicolas Geoffraye2b41952018-04-25 09:09:28 +010025#include "resolver.h"
Nicolas Geoffray2ebff052018-04-04 22:32:03 +010026#include "veridex.h"
27
28namespace art {
29
Nicolas Geoffray2ebff052018-04-04 22:32:03 +010030/**
31 * The source where a dex register comes from.
32 */
33enum class RegisterSource {
34 kParameter,
35 kField,
36 kMethod,
37 kClass,
38 kString,
Nicolas Geoffray66166d52018-05-09 18:19:29 +010039 kConstant,
Nicolas Geoffray2ebff052018-04-04 22:32:03 +010040 kNone
41};
42
43/**
44 * Abstract representation of a dex register value.
45 */
46class RegisterValue {
47 public:
Nicolas Geoffraye2b41952018-04-25 09:09:28 +010048 RegisterValue() : source_(RegisterSource::kNone),
Nicolas Geoffray66166d52018-05-09 18:19:29 +010049 value_(0),
Nicolas Geoffraye2b41952018-04-25 09:09:28 +010050 reference_(nullptr, 0),
51 type_(nullptr) {}
Nicolas Geoffray2ebff052018-04-04 22:32:03 +010052 RegisterValue(RegisterSource source, DexFileReference reference, const VeriClass* type)
Nicolas Geoffray66166d52018-05-09 18:19:29 +010053 : source_(source), value_(0), reference_(reference), type_(type) {}
Nicolas Geoffraye2b41952018-04-25 09:09:28 +010054
55 RegisterValue(RegisterSource source,
Nicolas Geoffray66166d52018-05-09 18:19:29 +010056 uint32_t value,
Nicolas Geoffraye2b41952018-04-25 09:09:28 +010057 DexFileReference reference,
58 const VeriClass* type)
Nicolas Geoffray66166d52018-05-09 18:19:29 +010059 : source_(source), value_(value), reference_(reference), type_(type) {}
Nicolas Geoffray2ebff052018-04-04 22:32:03 +010060
61 RegisterSource GetSource() const { return source_; }
62 DexFileReference GetDexFileReference() const { return reference_; }
63 const VeriClass* GetType() const { return type_; }
Nicolas Geoffraye2b41952018-04-25 09:09:28 +010064 uint32_t GetParameterIndex() const {
65 CHECK(IsParameter());
Nicolas Geoffray66166d52018-05-09 18:19:29 +010066 return value_;
67 }
68 uint32_t GetConstant() const {
69 CHECK(IsConstant());
70 return value_;
Nicolas Geoffraye2b41952018-04-25 09:09:28 +010071 }
72 bool IsParameter() const { return source_ == RegisterSource::kParameter; }
73 bool IsClass() const { return source_ == RegisterSource::kClass; }
74 bool IsString() const { return source_ == RegisterSource::kString; }
Nicolas Geoffray66166d52018-05-09 18:19:29 +010075 bool IsConstant() const { return source_ == RegisterSource::kConstant; }
Nicolas Geoffray2ebff052018-04-04 22:32:03 +010076
Nicolas Geoffray4f6e5232018-04-18 12:54:04 +010077 std::string ToString() const {
Nicolas Geoffray2ebff052018-04-04 22:32:03 +010078 switch (source_) {
Nicolas Geoffray4f6e5232018-04-18 12:54:04 +010079 case RegisterSource::kString: {
80 const char* str = reference_.dex_file->StringDataByIdx(dex::StringIndex(reference_.index));
81 if (type_ == VeriClass::class_) {
82 // Class names at the Java level are of the form x.y.z, but the list encodes
83 // them of the form Lx/y/z;. Inner classes have '$' for both Java level class
84 // names in strings, and hidden API lists.
85 return HiddenApi::ToInternalName(str);
86 } else {
87 return str;
88 }
89 }
Nicolas Geoffray2ebff052018-04-04 22:32:03 +010090 case RegisterSource::kClass:
91 return reference_.dex_file->StringByTypeIdx(dex::TypeIndex(reference_.index));
Nicolas Geoffraye2b41952018-04-25 09:09:28 +010092 case RegisterSource::kParameter:
93 return std::string("Parameter of ") + reference_.dex_file->PrettyMethod(reference_.index);
Nicolas Geoffray2ebff052018-04-04 22:32:03 +010094 default:
95 return "<unknown>";
96 }
97 }
98
99 private:
100 RegisterSource source_;
Nicolas Geoffray66166d52018-05-09 18:19:29 +0100101 uint32_t value_;
Nicolas Geoffray2ebff052018-04-04 22:32:03 +0100102 DexFileReference reference_;
103 const VeriClass* type_;
104};
105
106struct InstructionInfo {
107 bool has_been_visited;
108};
109
110class VeriFlowAnalysis {
111 public:
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -0700112 VeriFlowAnalysis(VeridexResolver* resolver, const ClassAccessor::Method& method);
Nicolas Geoffray2ebff052018-04-04 22:32:03 +0100113
114 void Run();
115
Nicolas Geoffraye2b41952018-04-25 09:09:28 +0100116 virtual RegisterValue AnalyzeInvoke(const Instruction& instruction, bool is_range) = 0;
117 virtual void AnalyzeFieldSet(const Instruction& instruction) = 0;
118 virtual ~VeriFlowAnalysis() {}
Nicolas Geoffray2ebff052018-04-04 22:32:03 +0100119
120 private:
121 // Find all branches in the code.
122 void FindBranches();
123
124 // Analyze all non-deead instructions in the code.
125 void AnalyzeCode();
126
127 // Set the instruction at the given pc as a branch target.
128 void SetAsBranchTarget(uint32_t dex_pc);
129
130 // Whether the instruction at the given pc is a branch target.
131 bool IsBranchTarget(uint32_t dex_pc);
132
133 // Merge the register values at the given pc with `current_registers`.
134 // Return whether the register values have changed, and the instruction needs
135 // to be visited again.
136 bool MergeRegisterValues(uint32_t dex_pc);
137
138 void UpdateRegister(
139 uint32_t dex_register, RegisterSource kind, VeriClass* cls, uint32_t source_id);
140 void UpdateRegister(uint32_t dex_register, const RegisterValue& value);
141 void UpdateRegister(uint32_t dex_register, const VeriClass* cls);
Nicolas Geoffray66166d52018-05-09 18:19:29 +0100142 void UpdateRegister(uint32_t dex_register, int32_t value, const VeriClass* cls);
Nicolas Geoffray2ebff052018-04-04 22:32:03 +0100143 void ProcessDexInstruction(const Instruction& inst);
144 void SetVisited(uint32_t dex_pc);
Nicolas Geoffray2ebff052018-04-04 22:32:03 +0100145 RegisterValue GetFieldType(uint32_t field_index);
146
Nicolas Geoffray66166d52018-05-09 18:19:29 +0100147 int GetBranchFlags(const Instruction& instruction) const;
148
Nicolas Geoffraye2b41952018-04-25 09:09:28 +0100149 protected:
Nicolas Geoffray66166d52018-05-09 18:19:29 +0100150 const RegisterValue& GetRegister(uint32_t dex_register) const;
Nicolas Geoffraye2b41952018-04-25 09:09:28 +0100151 RegisterValue GetReturnType(uint32_t method_index);
152
Nicolas Geoffray2ebff052018-04-04 22:32:03 +0100153 VeridexResolver* resolver_;
Nicolas Geoffraye2b41952018-04-25 09:09:28 +0100154
155 private:
156 const uint32_t method_id_;
157 CodeItemDataAccessor code_item_accessor_;
Nicolas Geoffray2ebff052018-04-04 22:32:03 +0100158
159 // Vector of register values for all branch targets.
160 std::vector<std::unique_ptr<std::vector<RegisterValue>>> dex_registers_;
161
162 // The current values of dex registers.
163 std::vector<RegisterValue> current_registers_;
164
165 // Information on each instruction useful for the analysis.
166 std::vector<InstructionInfo> instruction_infos_;
167
168 // The value of invoke instructions, to be fetched when visiting move-result.
169 RegisterValue last_result_;
Nicolas Geoffraye2b41952018-04-25 09:09:28 +0100170};
Nicolas Geoffray2ebff052018-04-04 22:32:03 +0100171
Nicolas Geoffraye2b41952018-04-25 09:09:28 +0100172struct ReflectAccessInfo {
173 RegisterValue cls;
174 RegisterValue name;
175 bool is_method;
Nicolas Geoffray2ebff052018-04-04 22:32:03 +0100176
Andreas Gampe9b031f72018-10-04 11:03:34 -0700177 ReflectAccessInfo(RegisterValue c, RegisterValue n, bool is_method)
178 : cls(c), name(n), is_method(is_method) {}
Nicolas Geoffraye2b41952018-04-25 09:09:28 +0100179
180 bool IsConcrete() const {
181 // We capture RegisterSource::kString for the class, for example in Class.forName.
182 return (cls.IsClass() || cls.IsString()) && name.IsString();
183 }
184};
185
186// Collects all reflection uses.
187class FlowAnalysisCollector : public VeriFlowAnalysis {
188 public:
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -0700189 FlowAnalysisCollector(VeridexResolver* resolver, const ClassAccessor::Method& method)
190 : VeriFlowAnalysis(resolver, method) {}
Nicolas Geoffraye2b41952018-04-25 09:09:28 +0100191
192 const std::vector<ReflectAccessInfo>& GetUses() const {
193 return uses_;
194 }
195
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100196 RegisterValue AnalyzeInvoke(const Instruction& instruction, bool is_range) override;
197 void AnalyzeFieldSet(const Instruction& instruction) override;
Nicolas Geoffraye2b41952018-04-25 09:09:28 +0100198
199 private:
200 // List of reflection uses found, concrete and abstract.
201 std::vector<ReflectAccessInfo> uses_;
202};
203
204// Substitutes reflection uses by new ones.
205class FlowAnalysisSubstitutor : public VeriFlowAnalysis {
206 public:
207 FlowAnalysisSubstitutor(VeridexResolver* resolver,
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -0700208 const ClassAccessor::Method& method,
Nicolas Geoffraye2b41952018-04-25 09:09:28 +0100209 const std::map<MethodReference, std::vector<ReflectAccessInfo>>& accesses)
Mathieu Chartier8f75f7b2018-08-06 23:38:48 -0700210 : VeriFlowAnalysis(resolver, method), accesses_(accesses) {}
Nicolas Geoffraye2b41952018-04-25 09:09:28 +0100211
212 const std::vector<ReflectAccessInfo>& GetUses() const {
213 return uses_;
214 }
215
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100216 RegisterValue AnalyzeInvoke(const Instruction& instruction, bool is_range) override;
217 void AnalyzeFieldSet(const Instruction& instruction) override;
Nicolas Geoffraye2b41952018-04-25 09:09:28 +0100218
219 private:
220 // List of reflection uses found, concrete and abstract.
221 std::vector<ReflectAccessInfo> uses_;
222 // The abstract uses we are trying to subsititute.
223 const std::map<MethodReference, std::vector<ReflectAccessInfo>>& accesses_;
Nicolas Geoffray2ebff052018-04-04 22:32:03 +0100224};
225
226} // namespace art
227
228#endif // ART_TOOLS_VERIDEX_FLOW_ANALYSIS_H_