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
DescribeSpace(ObjPtr<mirror::Class> klass)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
DescribeLoaders(ObjPtr<mirror::ClassLoader> loader,const char * class_descriptor)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
DumpB77342775DebugData(ObjPtr<mirror::Class> target_class,ObjPtr<mirror::Class> src_class)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