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-inl.h"
33
34 namespace art HIDDEN {
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 = WellKnownClasses::dalvik_system_PathClassLoader.Get();
67 ObjPtr<mirror::Class> dex_class_loader = WellKnownClasses::dalvik_system_DexClassLoader.Get();
68 ObjPtr<mirror::Class> delegate_last_class_loader =
69 WellKnownClasses::dalvik_system_DelegateLastClassLoader.Get();
70
71 // Print the class loader chain.
72 bool found_class = false;
73 const char* loader_separator = "";
74 if (loader == nullptr) {
75 oss << "BootClassLoader"; // This would be unexpected.
76 }
77 for (; loader != nullptr; loader = loader->GetParent()) {
78 ClassTable* table = Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(loader);
79 oss << loader_separator << loader->GetClass()->PrettyDescriptor()
80 << "/" << static_cast<const void*>(table);
81 loader_separator = ";";
82 // If we didn't find the class yet, try to find it in the current class loader.
83 if (!found_class) {
84 ObjPtr<mirror::Class> klass =
85 (table != nullptr) ? table->Lookup(class_descriptor, hash) : nullptr;
86 if (klass != nullptr) {
87 found_class = true;
88 oss << "[hit:" << DescribeSpace(klass) << "]";
89 }
90 }
91
92 // For PathClassLoader, DexClassLoader or DelegateLastClassLoader
93 // also dump the dex file locations.
94 if (loader->GetClass() == path_class_loader ||
95 loader->GetClass() == dex_class_loader ||
96 loader->GetClass() == delegate_last_class_loader) {
97 oss << "(";
98 Thread* self = Thread::Current();
99 StackHandleScope<1> hs(self);
100 Handle<mirror::ClassLoader> handle(hs.NewHandle(loader));
101 const char* path_separator = "";
102 const DexFile* base_dex_file = nullptr;
103 VisitClassLoaderDexFiles(
104 self,
105 handle,
106 [&](const DexFile* dex_file) {
107 oss << path_separator;
108 path_separator = ":";
109 if (base_dex_file != nullptr &&
110 dex_file->GetLocation().length() > base_dex_file->GetLocation().length() &&
111 dex_file->GetLocation().compare(0u,
112 base_dex_file->GetLocation().length(),
113 base_dex_file->GetLocation()) == 0) {
114 // Replace the base location with "+" to shorten the output.
115 oss << "+" << dex_file->GetLocation().substr(base_dex_file->GetLocation().length());
116 } else {
117 oss << dex_file->GetLocation();
118 base_dex_file = dex_file;
119 }
120 oss << "/" << static_cast<const void*>(dex_file);
121 return true; // Continue with the next DexFile.
122 });
123 oss << ")";
124 }
125 }
126
127 return oss.str();
128 }
129
130 } // namespace art
131