1 /* Copyright (C) 2016 The Android Open Source Project
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This file implements interfaces from the file jvmti.h. This implementation
5  * is licensed under the same terms as the file jvmti.h.  The
6  * copyright and license information for the file jvmti.h follows.
7  *
8  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10  *
11  * This code is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU General Public License version 2 only, as
13  * published by the Free Software Foundation.  Oracle designates this
14  * particular file as subject to the "Classpath" exception as provided
15  * by Oracle in the LICENSE file that accompanied this code.
16  *
17  * This code is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20  * version 2 for more details (a copy is included in the LICENSE file that
21  * accompanied this code).
22  *
23  * You should have received a copy of the GNU General Public License version
24  * 2 along with this work; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26  *
27  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28  * or visit www.oracle.com if you need additional information or have any
29  * questions.
30  */
31 
32 #include "ti_field.h"
33 
34 #include "art_field-inl.h"
35 #include "art_jvmti.h"
36 #include "base/enums.h"
37 #include "dex/dex_file_annotations.h"
38 #include "dex/modifiers.h"
39 #include "jni/jni_internal.h"
40 #include "mirror/object_array-inl.h"
41 #include "scoped_thread_state_change-inl.h"
42 #include "thread-current-inl.h"
43 
44 namespace openjdkjvmti {
45 
46 // Note: For all these functions, we could do a check that the field actually belongs to the given
47 //       class. But the spec seems to assume a certain encoding of the field ID, and so doesn't
48 //       specify any errors.
49 
GetFieldName(jvmtiEnv * env,jclass klass,jfieldID field,char ** name_ptr,char ** signature_ptr,char ** generic_ptr)50 jvmtiError FieldUtil::GetFieldName(jvmtiEnv* env,
51                                    jclass klass,
52                                    jfieldID field,
53                                    char** name_ptr,
54                                    char** signature_ptr,
55                                    char** generic_ptr) {
56   if (klass == nullptr) {
57     return ERR(INVALID_CLASS);
58   }
59   if (field == nullptr) {
60     return ERR(INVALID_FIELDID);
61   }
62 
63   art::ScopedObjectAccess soa(art::Thread::Current());
64   art::ArtField* art_field = art::jni::DecodeArtField(field);
65 
66   JvmtiUniquePtr<char[]> name_copy;
67   if (name_ptr != nullptr) {
68     const char* field_name = art_field->GetName();
69     if (field_name == nullptr) {
70       field_name = "<error>";
71     }
72     jvmtiError ret;
73     name_copy = CopyString(env, field_name, &ret);
74     if (name_copy == nullptr) {
75       return ret;
76     }
77     *name_ptr = name_copy.get();
78   }
79 
80   JvmtiUniquePtr<char[]> signature_copy;
81   if (signature_ptr != nullptr) {
82     const char* sig = art_field->GetTypeDescriptor();
83     jvmtiError ret;
84     signature_copy = CopyString(env, sig, &ret);
85     if (signature_copy == nullptr) {
86       return ret;
87     }
88     *signature_ptr = signature_copy.get();
89   }
90 
91   if (generic_ptr != nullptr) {
92     *generic_ptr = nullptr;
93     if (!art_field->GetDeclaringClass()->IsProxyClass()) {
94       art::ObjPtr<art::mirror::ObjectArray<art::mirror::String>> str_array =
95           art::annotations::GetSignatureAnnotationForField(art_field);
96       if (str_array != nullptr) {
97         std::ostringstream oss;
98         for (int32_t i = 0; i != str_array->GetLength(); ++i) {
99           oss << str_array->Get(i)->ToModifiedUtf8();
100         }
101         std::string output_string = oss.str();
102         jvmtiError ret;
103         JvmtiUniquePtr<char[]> copy = CopyString(env, output_string.c_str(), &ret);
104         if (copy == nullptr) {
105           return ret;
106         }
107         *generic_ptr = copy.release();
108       } else if (soa.Self()->IsExceptionPending()) {
109         // TODO: Should we report an error here?
110         soa.Self()->ClearException();
111       }
112     }
113   }
114 
115   // Everything is fine, release the buffers.
116   name_copy.release();
117   signature_copy.release();
118 
119   return ERR(NONE);
120 }
121 
GetFieldDeclaringClass(jvmtiEnv * env ATTRIBUTE_UNUSED,jclass klass,jfieldID field,jclass * declaring_class_ptr)122 jvmtiError FieldUtil::GetFieldDeclaringClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
123                                              jclass klass,
124                                              jfieldID field,
125                                              jclass* declaring_class_ptr) {
126   if (klass == nullptr) {
127     return ERR(INVALID_CLASS);
128   }
129   if (field == nullptr) {
130     return ERR(INVALID_FIELDID);
131   }
132   if (declaring_class_ptr == nullptr) {
133     return ERR(NULL_POINTER);
134   }
135 
136   art::ScopedObjectAccess soa(art::Thread::Current());
137   art::ArtField* art_field = art::jni::DecodeArtField(field);
138   art::ObjPtr<art::mirror::Class> field_klass = art_field->GetDeclaringClass();
139 
140   *declaring_class_ptr = soa.AddLocalReference<jclass>(field_klass);
141 
142   return ERR(NONE);
143 }
144 
GetFieldModifiers(jvmtiEnv * env ATTRIBUTE_UNUSED,jclass klass,jfieldID field,jint * modifiers_ptr)145 jvmtiError FieldUtil::GetFieldModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
146                                         jclass klass,
147                                         jfieldID field,
148                                         jint* modifiers_ptr) {
149   if (klass == nullptr) {
150     return ERR(INVALID_CLASS);
151   }
152   if (field == nullptr) {
153     return ERR(INVALID_FIELDID);
154   }
155   if (modifiers_ptr == nullptr) {
156     return ERR(NULL_POINTER);
157   }
158 
159   art::ScopedObjectAccess soa(art::Thread::Current());
160   art::ArtField* art_field = art::jni::DecodeArtField(field);
161   // Note: Keep this code in sync with Field.getModifiers.
162   uint32_t modifiers = art_field->GetAccessFlags() & 0xFFFF;
163 
164   *modifiers_ptr = modifiers;
165   return ERR(NONE);
166 }
167 
IsFieldSynthetic(jvmtiEnv * env ATTRIBUTE_UNUSED,jclass klass,jfieldID field,jboolean * is_synthetic_ptr)168 jvmtiError FieldUtil::IsFieldSynthetic(jvmtiEnv* env ATTRIBUTE_UNUSED,
169                                        jclass klass,
170                                        jfieldID field,
171                                        jboolean* is_synthetic_ptr) {
172   if (klass == nullptr) {
173     return ERR(INVALID_CLASS);
174   }
175   if (field == nullptr) {
176     return ERR(INVALID_FIELDID);
177   }
178   if (is_synthetic_ptr == nullptr) {
179     return ERR(NULL_POINTER);
180   }
181 
182   art::ScopedObjectAccess soa(art::Thread::Current());
183   art::ArtField* art_field = art::jni::DecodeArtField(field);
184   uint32_t modifiers = art_field->GetAccessFlags();
185 
186   *is_synthetic_ptr = ((modifiers & art::kAccSynthetic) != 0) ? JNI_TRUE : JNI_FALSE;
187   return ERR(NONE);
188 }
189 
SetFieldModificationWatch(jvmtiEnv * jenv,jclass klass,jfieldID field)190 jvmtiError FieldUtil::SetFieldModificationWatch(jvmtiEnv* jenv, jclass klass, jfieldID field) {
191   ArtJvmTiEnv* env = ArtJvmTiEnv::AsArtJvmTiEnv(jenv);
192   art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
193   if (klass == nullptr) {
194     return ERR(INVALID_CLASS);
195   }
196   if (field == nullptr) {
197     return ERR(INVALID_FIELDID);
198   }
199   auto res_pair = env->modify_watched_fields.insert(art::jni::DecodeArtField(field));
200   if (!res_pair.second) {
201     // Didn't get inserted because it's already present!
202     return ERR(DUPLICATE);
203   }
204   return OK;
205 }
206 
ClearFieldModificationWatch(jvmtiEnv * jenv,jclass klass,jfieldID field)207 jvmtiError FieldUtil::ClearFieldModificationWatch(jvmtiEnv* jenv, jclass klass, jfieldID field) {
208   ArtJvmTiEnv* env = ArtJvmTiEnv::AsArtJvmTiEnv(jenv);
209   art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
210   if (klass == nullptr) {
211     return ERR(INVALID_CLASS);
212   }
213   if (field == nullptr) {
214     return ERR(INVALID_FIELDID);
215   }
216   auto pos = env->modify_watched_fields.find(art::jni::DecodeArtField(field));
217   if (pos == env->modify_watched_fields.end()) {
218     return ERR(NOT_FOUND);
219   }
220   env->modify_watched_fields.erase(pos);
221   return OK;
222 }
223 
SetFieldAccessWatch(jvmtiEnv * jenv,jclass klass,jfieldID field)224 jvmtiError FieldUtil::SetFieldAccessWatch(jvmtiEnv* jenv, jclass klass, jfieldID field) {
225   ArtJvmTiEnv* env = ArtJvmTiEnv::AsArtJvmTiEnv(jenv);
226   art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
227   if (klass == nullptr) {
228     return ERR(INVALID_CLASS);
229   }
230   if (field == nullptr) {
231     return ERR(INVALID_FIELDID);
232   }
233   auto res_pair = env->access_watched_fields.insert(art::jni::DecodeArtField(field));
234   if (!res_pair.second) {
235     // Didn't get inserted because it's already present!
236     return ERR(DUPLICATE);
237   }
238   return OK;
239 }
240 
ClearFieldAccessWatch(jvmtiEnv * jenv,jclass klass,jfieldID field)241 jvmtiError FieldUtil::ClearFieldAccessWatch(jvmtiEnv* jenv, jclass klass, jfieldID field) {
242   ArtJvmTiEnv* env = ArtJvmTiEnv::AsArtJvmTiEnv(jenv);
243   art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
244   if (klass == nullptr) {
245     return ERR(INVALID_CLASS);
246   }
247   if (field == nullptr) {
248     return ERR(INVALID_FIELDID);
249   }
250   auto pos = env->access_watched_fields.find(art::jni::DecodeArtField(field));
251   if (pos == env->access_watched_fields.end()) {
252     return ERR(NOT_FOUND);
253   }
254   env->access_watched_fields.erase(pos);
255   return OK;
256 }
257 
258 }  // namespace openjdkjvmti
259