189 lines
7.7 KiB
C++
189 lines
7.7 KiB
C++
/*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <sstream>
|
|
|
|
#include "debug_print.h"
|
|
|
|
#include "class_linker.h"
|
|
#include "class_table.h"
|
|
#include "class_loader_utils.h"
|
|
#include "dex/utf.h"
|
|
#include "gc/heap.h"
|
|
#include "gc/space/space-inl.h"
|
|
#include "mirror/class.h"
|
|
#include "mirror/class_loader-inl.h"
|
|
#include "runtime.h"
|
|
#include "scoped_thread_state_change-inl.h"
|
|
#include "thread-current-inl.h"
|
|
#include "well_known_classes.h"
|
|
|
|
namespace art {
|
|
|
|
std::string DescribeSpace(ObjPtr<mirror::Class> klass) {
|
|
std::ostringstream oss;
|
|
gc::Heap* heap = Runtime::Current()->GetHeap();
|
|
gc::space::ContinuousSpace* cs =
|
|
heap->FindContinuousSpaceFromObject(klass, /* fail_ok= */ true);
|
|
if (cs != nullptr) {
|
|
if (cs->IsImageSpace()) {
|
|
gc::space::ImageSpace* ispace = cs->AsImageSpace();
|
|
oss << "image;" << ispace->GetName() << ";"
|
|
// If the file name is the same as the name, output "+" instead to shorten the output.
|
|
<< (ispace->GetImageFilename() == cs->GetName() ? "+" : ispace->GetImageFilename())
|
|
<< ";" << static_cast<const void*>(ispace->Begin());
|
|
} else {
|
|
oss << "continuous;" << cs->GetName();
|
|
}
|
|
} else {
|
|
gc::space::DiscontinuousSpace* ds =
|
|
heap->FindDiscontinuousSpaceFromObject(klass, /* fail_ok= */ true);
|
|
if (ds != nullptr) {
|
|
oss << "discontinuous;" << ds->GetName();
|
|
} else {
|
|
oss << "invalid";
|
|
}
|
|
}
|
|
return oss.str();
|
|
}
|
|
|
|
std::string DescribeLoaders(ObjPtr<mirror::ClassLoader> loader, const char* class_descriptor) {
|
|
std::ostringstream oss;
|
|
uint32_t hash = ComputeModifiedUtf8Hash(class_descriptor);
|
|
ObjPtr<mirror::Class> path_class_loader =
|
|
WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_PathClassLoader);
|
|
ObjPtr<mirror::Class> dex_class_loader =
|
|
WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_DexClassLoader);
|
|
ObjPtr<mirror::Class> delegate_last_class_loader =
|
|
WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_DelegateLastClassLoader);
|
|
|
|
// Print the class loader chain.
|
|
bool found_class = false;
|
|
const char* loader_separator = "";
|
|
if (loader == nullptr) {
|
|
oss << "BootClassLoader"; // This would be unexpected.
|
|
}
|
|
for (; loader != nullptr; loader = loader->GetParent()) {
|
|
ClassTable* table = Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(loader);
|
|
oss << loader_separator << loader->GetClass()->PrettyDescriptor()
|
|
<< "/" << static_cast<const void*>(table);
|
|
loader_separator = ";";
|
|
// If we didn't find the class yet, try to find it in the current class loader.
|
|
if (!found_class) {
|
|
ObjPtr<mirror::Class> klass =
|
|
(table != nullptr) ? table->Lookup(class_descriptor, hash) : nullptr;
|
|
if (klass != nullptr) {
|
|
found_class = true;
|
|
oss << "[hit:" << DescribeSpace(klass) << "]";
|
|
}
|
|
}
|
|
|
|
// For PathClassLoader, DexClassLoader or DelegateLastClassLoader
|
|
// also dump the dex file locations.
|
|
if (loader->GetClass() == path_class_loader ||
|
|
loader->GetClass() == dex_class_loader ||
|
|
loader->GetClass() == delegate_last_class_loader) {
|
|
oss << "(";
|
|
ScopedObjectAccessUnchecked soa(Thread::Current());
|
|
StackHandleScope<1> hs(soa.Self());
|
|
Handle<mirror::ClassLoader> handle(hs.NewHandle(loader));
|
|
const char* path_separator = "";
|
|
const DexFile* base_dex_file = nullptr;
|
|
VisitClassLoaderDexFiles(
|
|
soa,
|
|
handle,
|
|
[&](const DexFile* dex_file) {
|
|
oss << path_separator;
|
|
path_separator = ":";
|
|
if (base_dex_file != nullptr &&
|
|
dex_file->GetLocation().length() > base_dex_file->GetLocation().length() &&
|
|
dex_file->GetLocation().compare(0u,
|
|
base_dex_file->GetLocation().length(),
|
|
base_dex_file->GetLocation()) == 0) {
|
|
// Replace the base location with "+" to shorten the output.
|
|
oss << "+" << dex_file->GetLocation().substr(base_dex_file->GetLocation().length());
|
|
} else {
|
|
oss << dex_file->GetLocation();
|
|
base_dex_file = dex_file;
|
|
}
|
|
oss << "/" << static_cast<const void*>(dex_file);
|
|
return true; // Continue with the next DexFile.
|
|
});
|
|
oss << ")";
|
|
}
|
|
}
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
void DumpB77342775DebugData(ObjPtr<mirror::Class> target_class, ObjPtr<mirror::Class> src_class) {
|
|
std::string target_descriptor_storage;
|
|
const char* target_descriptor = target_class->GetDescriptor(&target_descriptor_storage);
|
|
const char kCheckedPrefix[] = "Lorg/apache/http/";
|
|
// Avoid spam for other packages. (That spam would break some ART run-tests for example.)
|
|
if (strncmp(target_descriptor, kCheckedPrefix, sizeof(kCheckedPrefix) - 1) != 0) {
|
|
return;
|
|
}
|
|
auto matcher = [target_descriptor, target_class](ObjPtr<mirror::Class> klass)
|
|
REQUIRES_SHARED(Locks::mutator_lock_) {
|
|
if (klass->DescriptorEquals(target_descriptor)) {
|
|
LOG(ERROR) << " descriptor match in "
|
|
<< DescribeLoaders(klass->GetClassLoader(), target_descriptor)
|
|
<< " match? " << std::boolalpha << (klass == target_class);
|
|
}
|
|
};
|
|
|
|
std::string source_descriptor_storage;
|
|
const char* source_descriptor = src_class->GetDescriptor(&source_descriptor_storage);
|
|
|
|
LOG(ERROR) << "Maybe bug 77342775, looking for " << target_descriptor
|
|
<< " " << target_class.Ptr() << "[" << DescribeSpace(target_class) << "]"
|
|
<< " defined in " << target_class->GetDexFile().GetLocation()
|
|
<< "/" << static_cast<const void*>(&target_class->GetDexFile())
|
|
<< "\n with loader: " << DescribeLoaders(target_class->GetClassLoader(), target_descriptor);
|
|
if (target_class->IsInterface()) {
|
|
ObjPtr<mirror::IfTable> iftable = src_class->GetIfTable();
|
|
CHECK(iftable != nullptr);
|
|
size_t ifcount = iftable->Count();
|
|
LOG(ERROR) << " in interface table for " << source_descriptor
|
|
<< " " << src_class.Ptr() << "[" << DescribeSpace(src_class) << "]"
|
|
<< " defined in " << src_class->GetDexFile().GetLocation()
|
|
<< "/" << static_cast<const void*>(&src_class->GetDexFile())
|
|
<< " ifcount=" << ifcount
|
|
<< "\n with loader " << DescribeLoaders(src_class->GetClassLoader(), source_descriptor);
|
|
for (size_t i = 0; i != ifcount; ++i) {
|
|
ObjPtr<mirror::Class> iface = iftable->GetInterface(i);
|
|
CHECK(iface != nullptr);
|
|
LOG(ERROR) << " iface #" << i << ": " << iface->PrettyDescriptor();
|
|
matcher(iface);
|
|
}
|
|
} else {
|
|
LOG(ERROR) << " in superclass chain for " << source_descriptor
|
|
<< " " << src_class.Ptr() << "[" << DescribeSpace(src_class) << "]"
|
|
<< " defined in " << src_class->GetDexFile().GetLocation()
|
|
<< "/" << static_cast<const void*>(&src_class->GetDexFile())
|
|
<< "\n with loader " << DescribeLoaders(src_class->GetClassLoader(), source_descriptor);
|
|
for (ObjPtr<mirror::Class> klass = src_class;
|
|
klass != nullptr;
|
|
klass = klass->GetSuperClass()) {
|
|
LOG(ERROR) << " - " << klass->PrettyDescriptor();
|
|
matcher(klass);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace art
|