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