1 /* 2 * Copyright (C) 2018 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 <sstream> 18 19 #include "debug_print.h" 20 21 #include "class_linker.h" 22 #include "class_table.h" 23 #include "class_loader_utils.h" 24 #include "dex/utf.h" 25 #include "gc/heap.h" 26 #include "gc/space/space-inl.h" 27 #include "mirror/class.h" 28 #include "mirror/class_loader-inl.h" 29 #include "runtime.h" 30 #include "scoped_thread_state_change-inl.h" 31 #include "thread-current-inl.h" 32 #include "well_known_classes.h" 33 34 namespace art { 35 36 std::string DescribeSpace(ObjPtr<mirror::Class> klass) { 37 std::ostringstream oss; 38 gc::Heap* heap = Runtime::Current()->GetHeap(); 39 gc::space::ContinuousSpace* cs = 40 heap->FindContinuousSpaceFromObject(klass, /* fail_ok= */ true); 41 if (cs != nullptr) { 42 if (cs->IsImageSpace()) { 43 gc::space::ImageSpace* ispace = cs->AsImageSpace(); 44 oss << "image;" << ispace->GetName() << ";" 45 // If the file name is the same as the name, output "+" instead to shorten the output. 46 << (ispace->GetImageFilename() == cs->GetName() ? "+" : ispace->GetImageFilename()) 47 << ";" << static_cast<const void*>(ispace->Begin()); 48 } else { 49 oss << "continuous;" << cs->GetName(); 50 } 51 } else { 52 gc::space::DiscontinuousSpace* ds = 53 heap->FindDiscontinuousSpaceFromObject(klass, /* fail_ok= */ true); 54 if (ds != nullptr) { 55 oss << "discontinuous;" << ds->GetName(); 56 } else { 57 oss << "invalid"; 58 } 59 } 60 return oss.str(); 61 } 62 63 std::string DescribeLoaders(ObjPtr<mirror::ClassLoader> loader, const char* class_descriptor) { 64 std::ostringstream oss; 65 uint32_t hash = ComputeModifiedUtf8Hash(class_descriptor); 66 ObjPtr<mirror::Class> path_class_loader = 67 WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_PathClassLoader); 68 ObjPtr<mirror::Class> dex_class_loader = 69 WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_DexClassLoader); 70 ObjPtr<mirror::Class> delegate_last_class_loader = 71 WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_DelegateLastClassLoader); 72 73 // Print the class loader chain. 74 bool found_class = false; 75 const char* loader_separator = ""; 76 if (loader == nullptr) { 77 oss << "BootClassLoader"; // This would be unexpected. 78 } 79 for (; loader != nullptr; loader = loader->GetParent()) { 80 ClassTable* table = Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(loader); 81 oss << loader_separator << loader->GetClass()->PrettyDescriptor() 82 << "/" << static_cast<const void*>(table); 83 loader_separator = ";"; 84 // If we didn't find the class yet, try to find it in the current class loader. 85 if (!found_class) { 86 ObjPtr<mirror::Class> klass = 87 (table != nullptr) ? table->Lookup(class_descriptor, hash) : nullptr; 88 if (klass != nullptr) { 89 found_class = true; 90 oss << "[hit:" << DescribeSpace(klass) << "]"; 91 } 92 } 93 94 // For PathClassLoader, DexClassLoader or DelegateLastClassLoader 95 // also dump the dex file locations. 96 if (loader->GetClass() == path_class_loader || 97 loader->GetClass() == dex_class_loader || 98 loader->GetClass() == delegate_last_class_loader) { 99 oss << "("; 100 ScopedObjectAccessUnchecked soa(Thread::Current()); 101 StackHandleScope<1> hs(soa.Self()); 102 Handle<mirror::ClassLoader> handle(hs.NewHandle(loader)); 103 const char* path_separator = ""; 104 const DexFile* base_dex_file = nullptr; 105 VisitClassLoaderDexFiles( 106 soa, 107 handle, 108 [&](const DexFile* dex_file) { 109 oss << path_separator; 110 path_separator = ":"; 111 if (base_dex_file != nullptr && 112 dex_file->GetLocation().length() > base_dex_file->GetLocation().length() && 113 dex_file->GetLocation().compare(0u, 114 base_dex_file->GetLocation().length(), 115 base_dex_file->GetLocation()) == 0) { 116 // Replace the base location with "+" to shorten the output. 117 oss << "+" << dex_file->GetLocation().substr(base_dex_file->GetLocation().length()); 118 } else { 119 oss << dex_file->GetLocation(); 120 base_dex_file = dex_file; 121 } 122 oss << "/" << static_cast<const void*>(dex_file); 123 return true; // Continue with the next DexFile. 124 }); 125 oss << ")"; 126 } 127 } 128 129 return oss.str(); 130 } 131 132 void DumpB77342775DebugData(ObjPtr<mirror::Class> target_class, ObjPtr<mirror::Class> src_class) { 133 std::string target_descriptor_storage; 134 const char* target_descriptor = target_class->GetDescriptor(&target_descriptor_storage); 135 const char kCheckedPrefix[] = "Lorg/apache/http/"; 136 // Avoid spam for other packages. (That spam would break some ART run-tests for example.) 137 if (strncmp(target_descriptor, kCheckedPrefix, sizeof(kCheckedPrefix) - 1) != 0) { 138 return; 139 } 140 auto matcher = [target_descriptor, target_class](ObjPtr<mirror::Class> klass) 141 REQUIRES_SHARED(Locks::mutator_lock_) { 142 if (klass->DescriptorEquals(target_descriptor)) { 143 LOG(ERROR) << " descriptor match in " 144 << DescribeLoaders(klass->GetClassLoader(), target_descriptor) 145 << " match? " << std::boolalpha << (klass == target_class); 146 } 147 }; 148 149 std::string source_descriptor_storage; 150 const char* source_descriptor = src_class->GetDescriptor(&source_descriptor_storage); 151 152 LOG(ERROR) << "Maybe bug 77342775, looking for " << target_descriptor 153 << " " << target_class.Ptr() << "[" << DescribeSpace(target_class) << "]" 154 << " defined in " << target_class->GetDexFile().GetLocation() 155 << "/" << static_cast<const void*>(&target_class->GetDexFile()) 156 << "\n with loader: " << DescribeLoaders(target_class->GetClassLoader(), target_descriptor); 157 if (target_class->IsInterface()) { 158 ObjPtr<mirror::IfTable> iftable = src_class->GetIfTable(); 159 CHECK(iftable != nullptr); 160 size_t ifcount = iftable->Count(); 161 LOG(ERROR) << " in interface table for " << source_descriptor 162 << " " << src_class.Ptr() << "[" << DescribeSpace(src_class) << "]" 163 << " defined in " << src_class->GetDexFile().GetLocation() 164 << "/" << static_cast<const void*>(&src_class->GetDexFile()) 165 << " ifcount=" << ifcount 166 << "\n with loader " << DescribeLoaders(src_class->GetClassLoader(), source_descriptor); 167 for (size_t i = 0; i != ifcount; ++i) { 168 ObjPtr<mirror::Class> iface = iftable->GetInterface(i); 169 CHECK(iface != nullptr); 170 LOG(ERROR) << " iface #" << i << ": " << iface->PrettyDescriptor(); 171 matcher(iface); 172 } 173 } else { 174 LOG(ERROR) << " in superclass chain for " << source_descriptor 175 << " " << src_class.Ptr() << "[" << DescribeSpace(src_class) << "]" 176 << " defined in " << src_class->GetDexFile().GetLocation() 177 << "/" << static_cast<const void*>(&src_class->GetDexFile()) 178 << "\n with loader " << DescribeLoaders(src_class->GetClassLoader(), source_descriptor); 179 for (ObjPtr<mirror::Class> klass = src_class; 180 klass != nullptr; 181 klass = klass->GetSuperClass()) { 182 LOG(ERROR) << " - " << klass->PrettyDescriptor(); 183 matcher(klass); 184 } 185 } 186 } 187 188 } // namespace art 189