xref: /aosp_15_r20/art/tools/jvmti-agents/list-extensions/list-extensions.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker // Copyright (C) 2019 The Android Open Source Project
2*795d594fSAndroid Build Coastguard Worker //
3*795d594fSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*795d594fSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*795d594fSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*795d594fSAndroid Build Coastguard Worker //
7*795d594fSAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
8*795d594fSAndroid Build Coastguard Worker //
9*795d594fSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*795d594fSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*795d594fSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*795d594fSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*795d594fSAndroid Build Coastguard Worker // limitations under the License.
14*795d594fSAndroid Build Coastguard Worker //
15*795d594fSAndroid Build Coastguard Worker 
16*795d594fSAndroid Build Coastguard Worker #include <android-base/logging.h>
17*795d594fSAndroid Build Coastguard Worker 
18*795d594fSAndroid Build Coastguard Worker #include <jni.h>
19*795d594fSAndroid Build Coastguard Worker #include <jvmti.h>
20*795d594fSAndroid Build Coastguard Worker #include <string>
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker namespace listextensions {
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker namespace {
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker // Special art ti-version number. We will use this as a fallback if we cannot get a regular JVMTI
27*795d594fSAndroid Build Coastguard Worker // env.
28*795d594fSAndroid Build Coastguard Worker constexpr jint kArtTiVersion = JVMTI_VERSION_1_2 | 0x40000000;
29*795d594fSAndroid Build Coastguard Worker 
Dealloc(jvmtiEnv * env,T * t)30*795d594fSAndroid Build Coastguard Worker template <typename T> void Dealloc(jvmtiEnv* env, T* t) {
31*795d594fSAndroid Build Coastguard Worker   env->Deallocate(reinterpret_cast<unsigned char*>(t));
32*795d594fSAndroid Build Coastguard Worker }
33*795d594fSAndroid Build Coastguard Worker 
Dealloc(jvmtiEnv * env,T * t,Rest...rs)34*795d594fSAndroid Build Coastguard Worker template <typename T, typename... Rest> void Dealloc(jvmtiEnv* env, T* t, Rest... rs) {
35*795d594fSAndroid Build Coastguard Worker   Dealloc(env, t);
36*795d594fSAndroid Build Coastguard Worker   Dealloc(env, rs...);
37*795d594fSAndroid Build Coastguard Worker }
38*795d594fSAndroid Build Coastguard Worker 
DeallocParams(jvmtiEnv * env,jvmtiParamInfo * params,jint n_params)39*795d594fSAndroid Build Coastguard Worker void DeallocParams(jvmtiEnv* env, jvmtiParamInfo* params, jint n_params) {
40*795d594fSAndroid Build Coastguard Worker   for (jint i = 0; i < n_params; i++) {
41*795d594fSAndroid Build Coastguard Worker     Dealloc(env, params[i].name);
42*795d594fSAndroid Build Coastguard Worker   }
43*795d594fSAndroid Build Coastguard Worker }
44*795d594fSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const jvmtiParamInfo & param)45*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const jvmtiParamInfo& param) {
46*795d594fSAndroid Build Coastguard Worker   os << param.name << " (";
47*795d594fSAndroid Build Coastguard Worker #define CASE(type, name)       \
48*795d594fSAndroid Build Coastguard Worker   case JVMTI_##type##_##name:  \
49*795d594fSAndroid Build Coastguard Worker     os << #name;               \
50*795d594fSAndroid Build Coastguard Worker     break
51*795d594fSAndroid Build Coastguard Worker   switch (param.kind) {
52*795d594fSAndroid Build Coastguard Worker     CASE(KIND, IN);
53*795d594fSAndroid Build Coastguard Worker     CASE(KIND, IN_PTR);
54*795d594fSAndroid Build Coastguard Worker     CASE(KIND, IN_BUF);
55*795d594fSAndroid Build Coastguard Worker     CASE(KIND, ALLOC_BUF);
56*795d594fSAndroid Build Coastguard Worker     CASE(KIND, ALLOC_ALLOC_BUF);
57*795d594fSAndroid Build Coastguard Worker     CASE(KIND, OUT);
58*795d594fSAndroid Build Coastguard Worker     CASE(KIND, OUT_BUF);
59*795d594fSAndroid Build Coastguard Worker   }
60*795d594fSAndroid Build Coastguard Worker   os << ", ";
61*795d594fSAndroid Build Coastguard Worker   switch (param.base_type) {
62*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JBYTE);
63*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JCHAR);
64*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JSHORT);
65*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JINT);
66*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JLONG);
67*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JFLOAT);
68*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JDOUBLE);
69*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JBOOLEAN);
70*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JOBJECT);
71*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JTHREAD);
72*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JCLASS);
73*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JVALUE);
74*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JFIELDID);
75*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JMETHODID);
76*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, CCHAR);
77*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, CVOID);
78*795d594fSAndroid Build Coastguard Worker     CASE(TYPE, JNIENV);
79*795d594fSAndroid Build Coastguard Worker   }
80*795d594fSAndroid Build Coastguard Worker #undef CASE
81*795d594fSAndroid Build Coastguard Worker   os << ")";
82*795d594fSAndroid Build Coastguard Worker   return os;
83*795d594fSAndroid Build Coastguard Worker }
84*795d594fSAndroid Build Coastguard Worker 
SetupJvmtiEnv(JavaVM * vm)85*795d594fSAndroid Build Coastguard Worker jint SetupJvmtiEnv(JavaVM* vm) {
86*795d594fSAndroid Build Coastguard Worker   jint res = 0;
87*795d594fSAndroid Build Coastguard Worker   jvmtiEnv* env = nullptr;
88*795d594fSAndroid Build Coastguard Worker   res = vm->GetEnv(reinterpret_cast<void**>(&env), JVMTI_VERSION_1_1);
89*795d594fSAndroid Build Coastguard Worker 
90*795d594fSAndroid Build Coastguard Worker   if (res != JNI_OK || env == nullptr) {
91*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Unable to access JVMTI, error code " << res;
92*795d594fSAndroid Build Coastguard Worker     res = vm->GetEnv(reinterpret_cast<void**>(&env), kArtTiVersion);
93*795d594fSAndroid Build Coastguard Worker     if (res != JNI_OK) {
94*795d594fSAndroid Build Coastguard Worker       return res;
95*795d594fSAndroid Build Coastguard Worker     }
96*795d594fSAndroid Build Coastguard Worker   }
97*795d594fSAndroid Build Coastguard Worker 
98*795d594fSAndroid Build Coastguard Worker   // Get the extensions.
99*795d594fSAndroid Build Coastguard Worker   jint n_ext = 0;
100*795d594fSAndroid Build Coastguard Worker   jvmtiExtensionFunctionInfo* infos = nullptr;
101*795d594fSAndroid Build Coastguard Worker   if (env->GetExtensionFunctions(&n_ext, &infos) != JVMTI_ERROR_NONE) {
102*795d594fSAndroid Build Coastguard Worker     return JNI_ERR;
103*795d594fSAndroid Build Coastguard Worker   }
104*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << "Found " << n_ext << " extension functions";
105*795d594fSAndroid Build Coastguard Worker   for (jint i = 0; i < n_ext; i++) {
106*795d594fSAndroid Build Coastguard Worker     const jvmtiExtensionFunctionInfo& info = infos[i];
107*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << info.id;
108*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "\tdesc: " << info.short_description;
109*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "\targuments: (count: " << info.param_count << ")";
110*795d594fSAndroid Build Coastguard Worker     for (jint j = 0; j < info.param_count; j++) {
111*795d594fSAndroid Build Coastguard Worker       const jvmtiParamInfo& param = info.params[j];
112*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "\t\t" << param;
113*795d594fSAndroid Build Coastguard Worker     }
114*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "\tErrors: (count: " << info.error_count << ")";
115*795d594fSAndroid Build Coastguard Worker     for (jint j = 0; j < info.error_count; j++) {
116*795d594fSAndroid Build Coastguard Worker       char* name;
117*795d594fSAndroid Build Coastguard Worker       CHECK_EQ(JVMTI_ERROR_NONE, env->GetErrorName(info.errors[j], &name));
118*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "\t\t" << name;
119*795d594fSAndroid Build Coastguard Worker       Dealloc(env, name);
120*795d594fSAndroid Build Coastguard Worker     }
121*795d594fSAndroid Build Coastguard Worker     DeallocParams(env, info.params, info.param_count);
122*795d594fSAndroid Build Coastguard Worker     Dealloc(env, info.short_description, info.id, info.errors, info.params);
123*795d594fSAndroid Build Coastguard Worker   }
124*795d594fSAndroid Build Coastguard Worker   // Cleanup the array.
125*795d594fSAndroid Build Coastguard Worker   Dealloc(env, infos);
126*795d594fSAndroid Build Coastguard Worker   jvmtiExtensionEventInfo* events = nullptr;
127*795d594fSAndroid Build Coastguard Worker   if (env->GetExtensionEvents(&n_ext, &events) != JVMTI_ERROR_NONE) {
128*795d594fSAndroid Build Coastguard Worker     return JNI_ERR;
129*795d594fSAndroid Build Coastguard Worker   }
130*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << "Found " << n_ext << " extension events";
131*795d594fSAndroid Build Coastguard Worker   for (jint i = 0; i < n_ext; i++) {
132*795d594fSAndroid Build Coastguard Worker     const jvmtiExtensionEventInfo& info = events[i];
133*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << info.id;
134*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "\tindex: " << info.extension_event_index;
135*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "\tdesc: " << info.short_description;
136*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "\tevent arguments: (count: " << info.param_count << ")";
137*795d594fSAndroid Build Coastguard Worker     for (jint j = 0; j < info.param_count; j++) {
138*795d594fSAndroid Build Coastguard Worker       const jvmtiParamInfo& param = info.params[j];
139*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "\t\t" << param;
140*795d594fSAndroid Build Coastguard Worker     }
141*795d594fSAndroid Build Coastguard Worker     DeallocParams(env, info.params, info.param_count);
142*795d594fSAndroid Build Coastguard Worker     Dealloc(env, info.short_description, info.id, info.params);
143*795d594fSAndroid Build Coastguard Worker   }
144*795d594fSAndroid Build Coastguard Worker   // Cleanup the array.
145*795d594fSAndroid Build Coastguard Worker   Dealloc(env, events);
146*795d594fSAndroid Build Coastguard Worker   env->DisposeEnvironment();
147*795d594fSAndroid Build Coastguard Worker   return JNI_OK;
148*795d594fSAndroid Build Coastguard Worker }
149*795d594fSAndroid Build Coastguard Worker 
AgentStart(JavaVM * vm,char * options,void * reserved)150*795d594fSAndroid Build Coastguard Worker jint AgentStart(JavaVM* vm, [[maybe_unused]] char* options, [[maybe_unused]] void* reserved) {
151*795d594fSAndroid Build Coastguard Worker   if (SetupJvmtiEnv(vm) != JNI_OK) {
152*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Could not get JVMTI env or ArtTiEnv!";
153*795d594fSAndroid Build Coastguard Worker     return JNI_ERR;
154*795d594fSAndroid Build Coastguard Worker   }
155*795d594fSAndroid Build Coastguard Worker   return JNI_OK;
156*795d594fSAndroid Build Coastguard Worker }
157*795d594fSAndroid Build Coastguard Worker 
158*795d594fSAndroid Build Coastguard Worker }  // namespace
159*795d594fSAndroid Build Coastguard Worker 
160*795d594fSAndroid Build Coastguard Worker // Late attachment (e.g. 'am attach-agent').
Agent_OnAttach(JavaVM * vm,char * options,void * reserved)161*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
162*795d594fSAndroid Build Coastguard Worker   return AgentStart(vm, options, reserved);
163*795d594fSAndroid Build Coastguard Worker }
164*795d594fSAndroid Build Coastguard Worker 
165*795d594fSAndroid Build Coastguard Worker // Early attachment
Agent_OnLoad(JavaVM * jvm,char * options,void * reserved)166*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* jvm, char* options, void* reserved) {
167*795d594fSAndroid Build Coastguard Worker   return AgentStart(jvm, options, reserved);
168*795d594fSAndroid Build Coastguard Worker }
169*795d594fSAndroid Build Coastguard Worker 
170*795d594fSAndroid Build Coastguard Worker }  // namespace listextensions
171