ronnie
2022-10-14 1504bb53e29d3d46222c0b3ea994fc494b48e153
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
/*
 * Copyright (C) 2016 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_RUNTIME_TI_AGENT_H_
#define ART_RUNTIME_TI_AGENT_H_
 
#include <dlfcn.h>
#include <jni.h>  // for jint, JavaVM* etc declarations
 
#include <memory>
 
#include <android-base/logging.h>
#include <android-base/macros.h>
 
namespace art {
namespace ti {
 
class Agent;
 
enum LoadError {
  kNoError,              // No error occurred..
  kLoadingError,         // dlopen or dlsym returned an error.
  kInitializationError,  // The entrypoint did not return 0. This might require an abort.
};
 
class AgentSpec {
 public:
  explicit AgentSpec(const std::string& arg);
 
  const std::string& GetName() const {
    return name_;
  }
 
  const std::string& GetArgs() const {
    return args_;
  }
 
  bool HasArgs() const {
    return !GetArgs().empty();
  }
 
  std::unique_ptr<Agent> Load(/*out*/jint* call_res,
                              /*out*/LoadError* error,
                              /*out*/std::string* error_msg);
 
  // Tries to attach the agent using its OnAttach method. Returns true on success.
  std::unique_ptr<Agent> Attach(JNIEnv* env,
                                jobject class_loader,
                                /*out*/jint* call_res,
                                /*out*/LoadError* error,
                                /*out*/std::string* error_msg);
 
 private:
  std::unique_ptr<Agent> DoDlOpen(JNIEnv* env,
                                  jobject class_loader,
                                  /*out*/LoadError* error,
                                  /*out*/std::string* error_msg);
 
  std::unique_ptr<Agent> DoLoadHelper(JNIEnv* env,
                                      bool attaching,
                                      jobject class_loader,
                                      /*out*/jint* call_res,
                                      /*out*/LoadError* error,
                                      /*out*/std::string* error_msg);
 
  std::string name_;
  std::string args_;
 
  friend std::ostream& operator<<(std::ostream &os, AgentSpec const& m);
};
 
std::ostream& operator<<(std::ostream &os, AgentSpec const& m);
 
using AgentOnLoadFunction = jint (*)(JavaVM*, const char*, void*);
using AgentOnUnloadFunction = void (*)(JavaVM*);
 
// Agents are native libraries that will be loaded by the runtime for the purpose of
// instrumentation. They will be entered by Agent_OnLoad or Agent_OnAttach depending on whether the
// agent is being attached during runtime startup or later.
//
// The agent's Agent_OnUnload function will be called during runtime shutdown.
//
// TODO: consider splitting ti::Agent into command line, agent and shared library handler classes
// TODO Support native-bridge. Currently agents can only be the actual runtime ISA of the device.
class Agent {
 public:
  const std::string& GetName() const {
    return name_;
  }
 
  void* FindSymbol(const std::string& name) const;
 
  // TODO We need to acquire some locks probably.
  void Unload();
 
  Agent(Agent&& other) noexcept;
  Agent& operator=(Agent&& other) noexcept;
 
  ~Agent();
 
 private:
  Agent(const std::string& name, void* dlopen_handle) : name_(name),
                                                        dlopen_handle_(dlopen_handle),
                                                        onload_(nullptr),
                                                        onattach_(nullptr),
                                                        onunload_(nullptr) {
    DCHECK(dlopen_handle != nullptr);
  }
 
  void PopulateFunctions();
 
  std::string name_;
  void* dlopen_handle_;
 
  // The entrypoints.
  AgentOnLoadFunction onload_;
  AgentOnLoadFunction onattach_;
  AgentOnUnloadFunction onunload_;
 
  friend class AgentSpec;
  friend std::ostream& operator<<(std::ostream &os, Agent const& m);
 
  DISALLOW_COPY_AND_ASSIGN(Agent);
};
 
std::ostream& operator<<(std::ostream &os, Agent const& m);
std::ostream& operator<<(std::ostream &os, const Agent* m);
 
}  // namespace ti
}  // namespace art
 
#endif  // ART_RUNTIME_TI_AGENT_H_