in oatdump/oatdump.cc [1281:1521]
bool Dump() SHARED_REQUIRES(Locks::mutator_lock_) {
std::ostream& os = *os_;
std::ostream& indent_os = vios_.Stream();
os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
os << "IMAGE LOCATION: " << image_space_.GetImageLocation() << "\n\n";
os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
os << "IMAGE SIZE: " << image_header_.GetImageSize() << "\n\n";
for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
auto section = static_cast<ImageHeader::ImageSections>(i);
os << "IMAGE SECTION " << section << ": " << image_header_.GetImageSection(section) << "\n\n";
}
os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum());
os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n\n";
os << "OAT DATA BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatDataBegin()) << "\n\n";
os << "OAT DATA END:" << reinterpret_cast<void*>(image_header_.GetOatDataEnd()) << "\n\n";
os << "OAT FILE END:" << reinterpret_cast<void*>(image_header_.GetOatFileEnd()) << "\n\n";
os << "PATCH DELTA:" << image_header_.GetPatchDelta() << "\n\n";
os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n";
{
os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
static_assert(arraysize(image_roots_descriptions_) ==
static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match");
for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
const char* image_root_description = image_roots_descriptions_[i];
mirror::Object* image_root_object = image_header_.GetImageRoot(image_root);
indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
if (image_root_object->IsObjectArray()) {
mirror::ObjectArray<mirror::Object>* image_root_object_array
= image_root_object->AsObjectArray<mirror::Object>();
ScopedIndentation indent2(&vios_);
for (int j = 0; j < image_root_object_array->GetLength(); j++) {
mirror::Object* value = image_root_object_array->Get(j);
size_t run = 0;
for (int32_t k = j + 1; k < image_root_object_array->GetLength(); k++) {
if (value == image_root_object_array->Get(k)) {
run++;
} else {
break;
}
}
if (run == 0) {
indent_os << StringPrintf("%d: ", j);
} else {
indent_os << StringPrintf("%d to %zd: ", j, j + run);
j = j + run;
}
if (value != nullptr) {
PrettyObjectValue(indent_os, value->GetClass(), value);
} else {
indent_os << j << ": null\n";
}
}
}
}
}
{
os << "METHOD ROOTS\n";
static_assert(arraysize(image_methods_descriptions_) ==
static_cast<size_t>(ImageHeader::kImageMethodsCount), "sizes must match");
for (int i = 0; i < ImageHeader::kImageMethodsCount; i++) {
auto image_root = static_cast<ImageHeader::ImageMethod>(i);
const char* description = image_methods_descriptions_[i];
auto* image_method = image_header_.GetImageMethod(image_root);
indent_os << StringPrintf("%s: %p\n", description, image_method);
}
}
os << "\n";
Runtime* const runtime = Runtime::Current();
ClassLinker* class_linker = runtime->GetClassLinker();
std::string image_filename = image_space_.GetImageFilename();
std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_filename);
os << "OAT LOCATION: " << oat_location;
os << "\n";
std::string error_msg;
const OatFile* oat_file = image_space_.GetOatFile();
if (oat_file == nullptr) {
oat_file = runtime->GetOatFileManager().FindOpenedOatFileFromOatLocation(oat_location);
}
if (oat_file == nullptr) {
oat_file = OatFile::Open(oat_location,
oat_location,
nullptr,
nullptr,
false,
/*low_4gb*/false,
nullptr,
&error_msg);
}
if (oat_file == nullptr) {
os << "OAT FILE NOT FOUND: " << error_msg << "\n";
return EXIT_FAILURE;
}
os << "\n";
stats_.oat_file_bytes = oat_file->Size();
oat_dumper_.reset(new OatDumper(*oat_file, *oat_dumper_options_));
for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
CHECK(oat_dex_file != nullptr);
stats_.oat_dex_file_sizes.push_back(std::make_pair(oat_dex_file->GetDexFileLocation(),
oat_dex_file->FileSize()));
}
os << "OBJECTS:\n" << std::flush;
// Loop through the image space and dump its objects.
gc::Heap* heap = runtime->GetHeap();
Thread* self = Thread::Current();
{
{
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
heap->FlushAllocStack();
}
// Since FlushAllocStack() above resets the (active) allocation
// stack. Need to revoke the thread-local allocation stacks that
// point into it.
ScopedThreadSuspension sts(self, kNative);
ScopedSuspendAll ssa(__FUNCTION__);
heap->RevokeAllThreadLocalAllocationStacks(self);
}
{
// Mark dex caches.
dex_caches_.clear();
{
ReaderMutexLock mu(self, *class_linker->DexLock());
for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) {
mirror::DexCache* dex_cache =
down_cast<mirror::DexCache*>(self->DecodeJObject(data.weak_root));
if (dex_cache != nullptr) {
dex_caches_.insert(dex_cache);
}
}
}
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
// Dump the normal objects before ArtMethods.
image_space_.GetLiveBitmap()->Walk(ImageDumper::Callback, this);
indent_os << "\n";
// TODO: Dump fields.
// Dump methods after.
DumpArtMethodVisitor visitor(this);
image_header_.VisitPackedArtMethods(&visitor,
image_space_.Begin(),
image_header_.GetPointerSize());
// Dump the large objects separately.
heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
indent_os << "\n";
}
os << "STATS:\n" << std::flush;
std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str()));
size_t data_size = image_header_.GetDataSize(); // stored size in file.
if (file == nullptr) {
LOG(WARNING) << "Failed to find image in " << image_filename;
} else {
stats_.file_bytes = file->GetLength();
// If the image is compressed, adjust to decompressed size.
size_t uncompressed_size = image_header_.GetImageSize() - sizeof(ImageHeader);
if (image_header_.GetStorageMode() == ImageHeader::kStorageModeUncompressed) {
DCHECK_EQ(uncompressed_size, data_size) << "Sizes should match for uncompressed image";
}
stats_.file_bytes += uncompressed_size - data_size;
}
size_t header_bytes = sizeof(ImageHeader);
const auto& object_section = image_header_.GetImageSection(ImageHeader::kSectionObjects);
const auto& field_section = image_header_.GetImageSection(ImageHeader::kSectionArtFields);
const auto& method_section = image_header_.GetMethodsSection();
const auto& dex_cache_arrays_section = image_header_.GetImageSection(
ImageHeader::kSectionDexCacheArrays);
const auto& intern_section = image_header_.GetImageSection(
ImageHeader::kSectionInternedStrings);
const auto& class_table_section = image_header_.GetImageSection(
ImageHeader::kSectionClassTable);
const auto& bitmap_section = image_header_.GetImageSection(ImageHeader::kSectionImageBitmap);
stats_.header_bytes = header_bytes;
// Objects are kObjectAlignment-aligned.
// CHECK_EQ(RoundUp(header_bytes, kObjectAlignment), object_section.Offset());
if (object_section.Offset() > header_bytes) {
stats_.alignment_bytes += object_section.Offset() - header_bytes;
}
// Field section is 4-byte aligned.
constexpr size_t kFieldSectionAlignment = 4U;
uint32_t end_objects = object_section.Offset() + object_section.Size();
CHECK_EQ(RoundUp(end_objects, kFieldSectionAlignment), field_section.Offset());
stats_.alignment_bytes += field_section.Offset() - end_objects;
// Method section is 4/8 byte aligned depending on target. Just check for 4-byte alignment.
uint32_t end_fields = field_section.Offset() + field_section.Size();
CHECK_ALIGNED(method_section.Offset(), 4);
stats_.alignment_bytes += method_section.Offset() - end_fields;
// Dex cache arrays section is aligned depending on the target. Just check for 4-byte alignment.
uint32_t end_methods = method_section.Offset() + method_section.Size();
CHECK_ALIGNED(dex_cache_arrays_section.Offset(), 4);
stats_.alignment_bytes += dex_cache_arrays_section.Offset() - end_methods;
// Intern table is 8-byte aligned.
uint32_t end_caches = dex_cache_arrays_section.Offset() + dex_cache_arrays_section.Size();
CHECK_EQ(RoundUp(end_caches, 8U), intern_section.Offset());
stats_.alignment_bytes += intern_section.Offset() - end_caches;
// Add space between intern table and class table.
uint32_t end_intern = intern_section.Offset() + intern_section.Size();
stats_.alignment_bytes += class_table_section.Offset() - end_intern;
// Add space between end of image data and bitmap. Expect the bitmap to be page-aligned.
const size_t bitmap_offset = sizeof(ImageHeader) + data_size;
CHECK_ALIGNED(bitmap_section.Offset(), kPageSize);
stats_.alignment_bytes += RoundUp(bitmap_offset, kPageSize) - bitmap_offset;
stats_.bitmap_bytes += bitmap_section.Size();
stats_.art_field_bytes += field_section.Size();
stats_.art_method_bytes += method_section.Size();
stats_.dex_cache_arrays_bytes += dex_cache_arrays_section.Size();
stats_.interned_strings_bytes += intern_section.Size();
stats_.class_table_bytes += class_table_section.Size();
stats_.Dump(os, indent_os);
os << "\n";
os << std::flush;
return oat_dumper_->Dump(os);
}