bool DumpOatMethod()

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;
  }