in oatdump/oatdump.cc [775:973]
bool DumpOatMethod(VariableIndentationOutputStream* vios,
const DexFile::ClassDef& class_def,
uint32_t class_method_index,
const OatFile::OatClass& oat_class, const DexFile& dex_file,
uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
uint32_t method_access_flags, bool* addr_found) {
bool success = true;
// TODO: Support regex
std::string method_name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
if (method_name.find(options_.method_filter_) == std::string::npos) {
return success;
}
std::string pretty_method = PrettyMethod(dex_method_idx, dex_file, true);
vios->Stream() << StringPrintf("%d: %s (dex_method_idx=%d)\n",
class_method_index, pretty_method.c_str(),
dex_method_idx);
if (options_.list_methods_) return success;
uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
uint32_t code_offset = oat_method.GetCodeOffset();
uint32_t code_size = oat_method.GetQuickCodeSize();
if (resolved_addr2instr_ != 0) {
if (resolved_addr2instr_ > code_offset + code_size) {
return success;
} else {
*addr_found = true; // stop analyzing file at next iteration
}
}
// Everything below is indented at least once.
ScopedIndentation indent1(vios);
{
vios->Stream() << "DEX CODE:\n";
ScopedIndentation indent2(vios);
DumpDexCode(vios->Stream(), dex_file, code_item);
}
std::unique_ptr<StackHandleScope<1>> hs;
std::unique_ptr<verifier::MethodVerifier> verifier;
if (Runtime::Current() != nullptr) {
// We need to have the handle scope stay live until after the verifier since the verifier has
// a handle to the dex cache from hs.
hs.reset(new StackHandleScope<1>(Thread::Current()));
vios->Stream() << "VERIFIER TYPE ANALYSIS:\n";
ScopedIndentation indent2(vios);
verifier.reset(DumpVerifier(vios, hs.get(),
dex_method_idx, &dex_file, class_def, code_item,
method_access_flags));
}
{
vios->Stream() << "OatMethodOffsets ";
if (options_.absolute_addresses_) {
vios->Stream() << StringPrintf("%p ", oat_method_offsets);
}
vios->Stream() << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset);
if (oat_method_offsets_offset > oat_file_.Size()) {
vios->Stream() << StringPrintf(
"WARNING: oat method offsets offset 0x%08x is past end of file 0x%08zx.\n",
oat_method_offsets_offset, oat_file_.Size());
// If we can't read OatMethodOffsets, the rest of the data is dangerous to read.
vios->Stream() << std::flush;
return false;
}
ScopedIndentation indent2(vios);
vios->Stream() << StringPrintf("code_offset: 0x%08x ", code_offset);
uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset());
if (aligned_code_begin > oat_file_.Size()) {
vios->Stream() << StringPrintf("WARNING: "
"code offset 0x%08x is past end of file 0x%08zx.\n",
aligned_code_begin, oat_file_.Size());
success = false;
}
vios->Stream() << "\n";
}
{
vios->Stream() << "OatQuickMethodHeader ";
uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset();
const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
if (options_.absolute_addresses_) {
vios->Stream() << StringPrintf("%p ", method_header);
}
vios->Stream() << StringPrintf("(offset=0x%08x)\n", method_header_offset);
if (method_header_offset > oat_file_.Size()) {
vios->Stream() << StringPrintf(
"WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n",
method_header_offset, oat_file_.Size());
// If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read.
vios->Stream() << std::flush;
return false;
}
ScopedIndentation indent2(vios);
vios->Stream() << "vmap_table: ";
if (options_.absolute_addresses_) {
vios->Stream() << StringPrintf("%p ", oat_method.GetVmapTable());
}
uint32_t vmap_table_offset = oat_method.GetVmapTableOffset();
vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
if (vmap_table_offset > oat_file_.Size()) {
vios->Stream() << StringPrintf("WARNING: "
"vmap table offset 0x%08x is past end of file 0x%08zx. "
"vmap table offset was loaded from offset 0x%08x.\n",
vmap_table_offset, oat_file_.Size(),
oat_method.GetVmapTableOffsetOffset());
success = false;
} else if (options_.dump_vmap_) {
DumpVmapData(vios, oat_method, code_item);
}
}
{
vios->Stream() << "QuickMethodFrameInfo\n";
ScopedIndentation indent2(vios);
vios->Stream()
<< StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
vios->Stream() << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
DumpSpillMask(vios->Stream(), oat_method.GetCoreSpillMask(), false);
vios->Stream() << "\n";
vios->Stream() << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
DumpSpillMask(vios->Stream(), oat_method.GetFpSpillMask(), true);
vios->Stream() << "\n";
}
{
// Based on spill masks from QuickMethodFrameInfo so placed
// after it is dumped, but useful for understanding quick
// code, so dumped here.
ScopedIndentation indent2(vios);
DumpVregLocations(vios->Stream(), oat_method, code_item);
}
{
vios->Stream() << "CODE: ";
uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset();
if (code_size_offset > oat_file_.Size()) {
ScopedIndentation indent2(vios);
vios->Stream() << StringPrintf("WARNING: "
"code size offset 0x%08x is past end of file 0x%08zx.",
code_size_offset, oat_file_.Size());
success = false;
} else {
const void* code = oat_method.GetQuickCode();
uint32_t aligned_code_begin = AlignCodeOffset(code_offset);
uint64_t aligned_code_end = aligned_code_begin + code_size;
if (options_.absolute_addresses_) {
vios->Stream() << StringPrintf("%p ", code);
}
vios->Stream() << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
code_offset,
code_size_offset,
code_size,
code != nullptr ? "..." : "");
ScopedIndentation indent2(vios);
if (aligned_code_begin > oat_file_.Size()) {
vios->Stream() << StringPrintf("WARNING: "
"start of code at 0x%08x is past end of file 0x%08zx.",
aligned_code_begin, oat_file_.Size());
success = false;
} else if (aligned_code_end > oat_file_.Size()) {
vios->Stream() << StringPrintf(
"WARNING: "
"end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
"code size is 0x%08x loaded from offset 0x%08x.\n",
aligned_code_end, oat_file_.Size(),
code_size, code_size_offset);
success = false;
if (options_.disassemble_code_) {
if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
DumpCode(vios, oat_method, code_item, true, kPrologueBytes);
}
}
} else if (code_size > kMaxCodeSize) {
vios->Stream() << StringPrintf(
"WARNING: "
"code size %d is bigger than max expected threshold of %d. "
"code size is 0x%08x loaded from offset 0x%08x.\n",
code_size, kMaxCodeSize,
code_size, code_size_offset);
success = false;
if (options_.disassemble_code_) {
if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
DumpCode(vios, oat_method, code_item, true, kPrologueBytes);
}
}
} else if (options_.disassemble_code_) {
DumpCode(vios, oat_method, code_item, !success, 0);
}
}
}
vios->Stream() << std::flush;
return success;
}