summaryrefslogtreecommitdiffstats
path: root/tools/veridex/flow_analysis.h
blob: 2151a41725b1b45d82d3e74bddf56182768ec837 (plain)
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_