• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 <inttypes.h>
18 #include <stdio.h>
19 #include <string.h>
20 
21 #include <iostream>
22 #include <vector>
23 
24 #include "android-base/stringprintf.h"
25 
26 #include "base/logging.h"
27 #include "base/macros.h"
28 #include "bytecode_utils.h"
29 #include "dex_file.h"
30 #include "dex_instruction.h"
31 #include "jit/jit.h"
32 #include "jni.h"
33 #include "native_stack_dump.h"
34 #include "jvmti.h"
35 #include "runtime.h"
36 #include "scoped_thread_state_change-inl.h"
37 #include "thread-current-inl.h"
38 #include "thread_list.h"
39 
40 // Test infrastructure
41 #include "jvmti_helper.h"
42 #include "test_env.h"
43 
44 namespace art {
45 namespace Test983SourceTransformVerify {
46 
47 constexpr bool kSkipInitialLoad = true;
48 
49 // The hook we are using.
CheckDexFileHook(jvmtiEnv * jvmti_env ATTRIBUTE_UNUSED,JNIEnv * jni_env ATTRIBUTE_UNUSED,jclass class_being_redefined,jobject loader ATTRIBUTE_UNUSED,const char * name,jobject protection_domain ATTRIBUTE_UNUSED,jint class_data_len,const unsigned char * class_data,jint * new_class_data_len ATTRIBUTE_UNUSED,unsigned char ** new_class_data ATTRIBUTE_UNUSED)50 void JNICALL CheckDexFileHook(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
51                               JNIEnv* jni_env ATTRIBUTE_UNUSED,
52                               jclass class_being_redefined,
53                               jobject loader ATTRIBUTE_UNUSED,
54                               const char* name,
55                               jobject protection_domain ATTRIBUTE_UNUSED,
56                               jint class_data_len,
57                               const unsigned char* class_data,
58                               jint* new_class_data_len ATTRIBUTE_UNUSED,
59                               unsigned char** new_class_data ATTRIBUTE_UNUSED) {
60   if (kSkipInitialLoad && class_being_redefined == nullptr) {
61     // Something got loaded concurrently. Just ignore it for now.
62     return;
63   }
64   std::cout << "Dex file hook for " << name << std::endl;
65   if (IsJVM()) {
66     return;
67   }
68   std::string error;
69   std::unique_ptr<const DexFile> dex(DexFile::Open(class_data,
70                                                    class_data_len,
71                                                    "fake_location.dex",
72                                                    /*location_checksum*/ 0,
73                                                    /*oat_dex_file*/ nullptr,
74                                                    /*verify*/ true,
75                                                    /*verify_checksum*/ true,
76                                                    &error));
77   if (dex.get() == nullptr) {
78     std::cout << "Failed to verify dex file for " << name << " because " << error << std::endl;
79     return;
80   }
81   for (uint32_t i = 0; i < dex->NumClassDefs(); i++) {
82     const DexFile::ClassDef& def = dex->GetClassDef(i);
83     const uint8_t* data_item = dex->GetClassData(def);
84     if (data_item == nullptr) {
85       continue;
86     }
87     for (ClassDataItemIterator it(*dex, data_item); it.HasNext(); it.Next()) {
88       if (!it.IsAtMethod() || it.GetMethodCodeItem() == nullptr) {
89         continue;
90       }
91       for (CodeItemIterator code_it(*it.GetMethodCodeItem()); !code_it.Done(); code_it.Advance()) {
92         const Instruction& inst = code_it.CurrentInstruction();
93         int forbiden_flags = (Instruction::kVerifyError | Instruction::kVerifyRuntimeOnly);
94         if (inst.Opcode() == Instruction::RETURN_VOID_NO_BARRIER ||
95             (inst.GetVerifyExtraFlags() & forbiden_flags) != 0) {
96           std::cout << "Unexpected instruction found in " << dex->PrettyMethod(it.GetMemberIndex())
97                     << " [Dex PC: 0x" << std::hex << code_it.CurrentDexPc() << std::dec << "] : "
98                     << inst.DumpString(dex.get()) << std::endl;
99           continue;
100         }
101       }
102     }
103   }
104 }
105 
106 // Get all capabilities except those related to retransformation.
OnLoad(JavaVM * vm,char * options ATTRIBUTE_UNUSED,void * reserved ATTRIBUTE_UNUSED)107 jint OnLoad(JavaVM* vm,
108             char* options ATTRIBUTE_UNUSED,
109             void* reserved ATTRIBUTE_UNUSED) {
110   if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
111     printf("Unable to get jvmti env!\n");
112     return 1;
113   }
114   SetAllCapabilities(jvmti_env);
115   jvmtiEventCallbacks cb;
116   memset(&cb, 0, sizeof(cb));
117   cb.ClassFileLoadHook = CheckDexFileHook;
118   if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
119     printf("Unable to set class file load hook cb!\n");
120     return 1;
121   }
122   return 0;
123 }
124 
125 }  // namespace Test983SourceTransformVerify
126 }  // namespace art
127