blob: d21ff77849fda684a7e4e975cdbbcec5e17e48b7 [file] [log] [blame]
Alex Light7233c7e2016-07-28 10:07:45 -07001/*
2 * Copyright (C) 2016 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#include "agent.h"
18#include "java_vm_ext.h"
19#include "runtime.h"
20
21namespace art {
22namespace ti {
23
24const char* AGENT_ON_LOAD_FUNCTION_NAME = "Agent_OnLoad";
25const char* AGENT_ON_ATTACH_FUNCTION_NAME = "Agent_OnAttach";
26const char* AGENT_ON_UNLOAD_FUNCTION_NAME = "Agent_OnUnload";
27
Alex Light7233c7e2016-07-28 10:07:45 -070028// TODO We need to acquire some locks probably.
Leonard Mosescueb842212016-10-06 17:26:36 -070029Agent::LoadError Agent::DoLoadHelper(bool attaching,
30 /*out*/jint* call_res,
31 /*out*/std::string* error_msg) {
Alex Light7233c7e2016-07-28 10:07:45 -070032 DCHECK(call_res != nullptr);
33 DCHECK(error_msg != nullptr);
Alex Light49948e92016-08-11 15:35:28 -070034
Alex Light7233c7e2016-07-28 10:07:45 -070035 if (IsStarted()) {
36 *error_msg = StringPrintf("the agent at %s has already been started!", name_.c_str());
37 VLOG(agents) << "err: " << *error_msg;
38 return kAlreadyStarted;
39 }
40 LoadError err = DoDlOpen(error_msg);
41 if (err != kNoError) {
42 VLOG(agents) << "err: " << *error_msg;
43 return err;
44 }
Leonard Mosescueb842212016-10-06 17:26:36 -070045 AgentOnLoadFunction callback = attaching ? onattach_ : onload_;
46 if (callback == nullptr) {
47 *error_msg = StringPrintf("Unable to start agent %s: No %s callback found",
48 (attaching ? "attach" : "load"),
Alex Light7233c7e2016-07-28 10:07:45 -070049 name_.c_str());
50 VLOG(agents) << "err: " << *error_msg;
51 return kLoadingError;
52 }
Alex Light49948e92016-08-11 15:35:28 -070053 // Need to let the function fiddle with the array.
54 std::unique_ptr<char[]> copied_args(new char[args_.size() + 1]);
55 strcpy(copied_args.get(), args_.c_str());
Alex Light7233c7e2016-07-28 10:07:45 -070056 // TODO Need to do some checks that we are at a good spot etc.
Leonard Mosescueb842212016-10-06 17:26:36 -070057 *call_res = callback(Runtime::Current()->GetJavaVM(),
58 copied_args.get(),
59 nullptr);
Alex Light7233c7e2016-07-28 10:07:45 -070060 if (*call_res != 0) {
61 *error_msg = StringPrintf("Initialization of %s returned non-zero value of %d",
62 name_.c_str(), *call_res);
63 VLOG(agents) << "err: " << *error_msg;
64 return kInitializationError;
65 } else {
66 return kNoError;
67 }
68}
69
70Agent::LoadError Agent::DoDlOpen(/*out*/std::string* error_msg) {
71 DCHECK(error_msg != nullptr);
Leonard Mosescueb842212016-10-06 17:26:36 -070072
73 DCHECK(dlopen_handle_ == nullptr);
74 DCHECK(onload_ == nullptr);
75 DCHECK(onattach_ == nullptr);
76 DCHECK(onunload_ == nullptr);
77
Alex Light7233c7e2016-07-28 10:07:45 -070078 dlopen_handle_ = dlopen(name_.c_str(), RTLD_LAZY);
79 if (dlopen_handle_ == nullptr) {
80 *error_msg = StringPrintf("Unable to dlopen %s: %s", name_.c_str(), dlerror());
81 return kLoadingError;
82 }
83
84 onload_ = reinterpret_cast<AgentOnLoadFunction>(dlsym(dlopen_handle_,
85 AGENT_ON_LOAD_FUNCTION_NAME));
86 if (onload_ == nullptr) {
87 VLOG(agents) << "Unable to find 'Agent_OnLoad' symbol in " << this;
88 }
Leonard Mosescueb842212016-10-06 17:26:36 -070089 onattach_ = reinterpret_cast<AgentOnLoadFunction>(dlsym(dlopen_handle_,
Alex Light7233c7e2016-07-28 10:07:45 -070090 AGENT_ON_ATTACH_FUNCTION_NAME));
91 if (onattach_ == nullptr) {
92 VLOG(agents) << "Unable to find 'Agent_OnAttach' symbol in " << this;
93 }
94 onunload_= reinterpret_cast<AgentOnUnloadFunction>(dlsym(dlopen_handle_,
95 AGENT_ON_UNLOAD_FUNCTION_NAME));
96 if (onunload_ == nullptr) {
97 VLOG(agents) << "Unable to find 'Agent_OnUnload' symbol in " << this;
98 }
99 return kNoError;
100}
101
102// TODO Lock some stuff probably.
103void Agent::Unload() {
104 if (dlopen_handle_ != nullptr) {
105 if (onunload_ != nullptr) {
106 onunload_(Runtime::Current()->GetJavaVM());
107 }
108 dlclose(dlopen_handle_);
109 dlopen_handle_ = nullptr;
Leonard Mosescueb842212016-10-06 17:26:36 -0700110 onload_ = nullptr;
111 onattach_ = nullptr;
112 onunload_ = nullptr;
Alex Light7233c7e2016-07-28 10:07:45 -0700113 } else {
114 VLOG(agents) << this << " is not currently loaded!";
115 }
116}
117
Leonard Mosescueb842212016-10-06 17:26:36 -0700118Agent::Agent(std::string arg)
119 : dlopen_handle_(nullptr),
120 onload_(nullptr),
121 onattach_(nullptr),
122 onunload_(nullptr) {
123 size_t eq = arg.find_first_of('=');
124 if (eq == std::string::npos) {
125 name_ = arg;
126 } else {
127 name_ = arg.substr(0, eq);
128 args_ = arg.substr(eq + 1, arg.length());
Alex Light7233c7e2016-07-28 10:07:45 -0700129 }
130}
131
Leonard Mosescueb842212016-10-06 17:26:36 -0700132Agent::Agent(const Agent& other)
133 : dlopen_handle_(nullptr),
134 onload_(nullptr),
135 onattach_(nullptr),
136 onunload_(nullptr) {
137 *this = other;
138}
139
140// Attempting to copy to/from loaded/started agents is a fatal error
141Agent& Agent::operator=(const Agent& other) {
142 if (this != &other) {
143 if (other.dlopen_handle_ != nullptr) {
144 LOG(FATAL) << "Attempting to copy a loaded agent!";
145 }
146
147 if (dlopen_handle_ != nullptr) {
148 LOG(FATAL) << "Attempting to assign into a loaded agent!";
149 }
150
151 DCHECK(other.onload_ == nullptr);
152 DCHECK(other.onattach_ == nullptr);
153 DCHECK(other.onunload_ == nullptr);
154
155 DCHECK(onload_ == nullptr);
156 DCHECK(onattach_ == nullptr);
157 DCHECK(onunload_ == nullptr);
158
159 name_ = other.name_;
160 args_ = other.args_;
161
162 dlopen_handle_ = nullptr;
163 onload_ = nullptr;
164 onattach_ = nullptr;
165 onunload_ = nullptr;
166 }
167 return *this;
168}
169
170Agent::Agent(Agent&& other)
171 : dlopen_handle_(nullptr),
172 onload_(nullptr),
173 onattach_(nullptr),
174 onunload_(nullptr) {
175 *this = std::move(other);
176}
177
178Agent& Agent::operator=(Agent&& other) {
179 if (this != &other) {
180 if (dlopen_handle_ != nullptr) {
181 dlclose(dlopen_handle_);
182 }
183 name_ = std::move(other.name_);
184 args_ = std::move(other.args_);
185 dlopen_handle_ = other.dlopen_handle_;
186 onload_ = other.onload_;
187 onattach_ = other.onattach_;
188 onunload_ = other.onunload_;
189 other.dlopen_handle_ = nullptr;
190 other.onload_ = nullptr;
191 other.onattach_ = nullptr;
192 other.onunload_ = nullptr;
193 }
194 return *this;
195}
196
Alex Light7233c7e2016-07-28 10:07:45 -0700197Agent::~Agent() {
198 if (dlopen_handle_ != nullptr) {
199 dlclose(dlopen_handle_);
200 }
201}
202
203std::ostream& operator<<(std::ostream &os, const Agent* m) {
204 return os << *m;
205}
206
207std::ostream& operator<<(std::ostream &os, Agent const& m) {
208 return os << "Agent { name=\"" << m.name_ << "\", args=\"" << m.args_ << "\", handle="
209 << m.dlopen_handle_ << " }";
210}
211
212} // namespace ti
213} // namespace art