LCOV - code coverage report
Current view: top level - src - disassembler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1 3 33.3 %
Date: 2019-03-21 Functions: 1 2 50.0 %

          Line data    Source code
       1             : // Copyright 2011 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/disassembler.h"
       6             : 
       7             : #include <memory>
       8             : #include <unordered_map>
       9             : #include <vector>
      10             : 
      11             : #include "src/assembler-inl.h"
      12             : #include "src/code-comments.h"
      13             : #include "src/code-reference.h"
      14             : #include "src/debug/debug.h"
      15             : #include "src/deoptimizer.h"
      16             : #include "src/disasm.h"
      17             : #include "src/ic/ic.h"
      18             : #include "src/isolate-data.h"
      19             : #include "src/macro-assembler.h"
      20             : #include "src/objects-inl.h"
      21             : #include "src/snapshot/embedded-data.h"
      22             : #include "src/snapshot/serializer-common.h"
      23             : #include "src/string-stream.h"
      24             : #include "src/vector.h"
      25             : #include "src/wasm/wasm-code-manager.h"
      26             : #include "src/wasm/wasm-engine.h"
      27             : 
      28             : namespace v8 {
      29             : namespace internal {
      30             : 
      31             : #ifdef ENABLE_DISASSEMBLER
      32             : 
      33             : class V8NameConverter: public disasm::NameConverter {
      34             :  public:
      35             :   explicit V8NameConverter(Isolate* isolate, CodeReference code = {})
      36             :       : isolate_(isolate), code_(code) {}
      37             :   const char* NameOfAddress(byte* pc) const override;
      38             :   const char* NameInCode(byte* addr) const override;
      39             :   const char* RootRelativeName(int offset) const override;
      40             : 
      41             :   const CodeReference& code() const { return code_; }
      42             : 
      43             :  private:
      44             :   void InitExternalRefsCache() const;
      45             : 
      46             :   Isolate* isolate_;
      47             :   CodeReference code_;
      48             : 
      49             :   EmbeddedVector<char, 128> v8_buffer_;
      50             : 
      51             :   // Map from root-register relative offset of the external reference value to
      52             :   // the external reference name (stored in the external reference table).
      53             :   // This cache is used to recognize [root_reg + offs] patterns as direct
      54             :   // access to certain external reference's value.
      55             :   mutable std::unordered_map<int, const char*> directly_accessed_external_refs_;
      56             : };
      57             : 
      58             : void V8NameConverter::InitExternalRefsCache() const {
      59             :   ExternalReferenceTable* external_reference_table =
      60             :       isolate_->external_reference_table();
      61             :   if (!external_reference_table->is_initialized()) return;
      62             : 
      63             :   base::AddressRegion addressable_region =
      64             :       isolate_->root_register_addressable_region();
      65             :   Address isolate_root = isolate_->isolate_root();
      66             : 
      67             :   for (uint32_t i = 0; i < ExternalReferenceTable::kSize; i++) {
      68             :     Address address = external_reference_table->address(i);
      69             :     if (addressable_region.contains(address)) {
      70             :       int offset = static_cast<int>(address - isolate_root);
      71             :       const char* name = external_reference_table->name(i);
      72             :       directly_accessed_external_refs_.insert({offset, name});
      73             :     }
      74             :   }
      75             : }
      76             : 
      77             : const char* V8NameConverter::NameOfAddress(byte* pc) const {
      78             :   if (!code_.is_null()) {
      79             :     const char* name =
      80             :         isolate_ ? isolate_->builtins()->Lookup(reinterpret_cast<Address>(pc))
      81             :                  : nullptr;
      82             : 
      83             :     if (name != nullptr) {
      84             :       SNPrintF(v8_buffer_, "%p  (%s)", static_cast<void*>(pc), name);
      85             :       return v8_buffer_.start();
      86             :     }
      87             : 
      88             :     int offs = static_cast<int>(reinterpret_cast<Address>(pc) -
      89             :                                 code_.instruction_start());
      90             :     // print as code offset, if it seems reasonable
      91             :     if (0 <= offs && offs < code_.instruction_size()) {
      92             :       SNPrintF(v8_buffer_, "%p  <+0x%x>", static_cast<void*>(pc), offs);
      93             :       return v8_buffer_.start();
      94             :     }
      95             : 
      96             :     wasm::WasmCode* wasm_code =
      97             :         isolate_ ? isolate_->wasm_engine()->code_manager()->LookupCode(
      98             :                        reinterpret_cast<Address>(pc))
      99             :                  : nullptr;
     100             :     if (wasm_code != nullptr) {
     101             :       SNPrintF(v8_buffer_, "%p  (%s)", static_cast<void*>(pc),
     102             :                wasm::GetWasmCodeKindAsString(wasm_code->kind()));
     103             :       return v8_buffer_.start();
     104             :     }
     105             :   }
     106             : 
     107             :   return disasm::NameConverter::NameOfAddress(pc);
     108             : }
     109             : 
     110             : 
     111             : const char* V8NameConverter::NameInCode(byte* addr) const {
     112             :   // The V8NameConverter is used for well known code, so we can "safely"
     113             :   // dereference pointers in generated code.
     114             :   return code_.is_null() ? "" : reinterpret_cast<const char*>(addr);
     115             : }
     116             : 
     117             : const char* V8NameConverter::RootRelativeName(int offset) const {
     118             :   if (isolate_ == nullptr) return nullptr;
     119             : 
     120             :   const int kRootsTableStart = IsolateData::roots_table_offset();
     121             :   const unsigned kRootsTableSize = sizeof(RootsTable);
     122             :   const int kExtRefsTableStart = IsolateData::external_reference_table_offset();
     123             :   const unsigned kExtRefsTableSize = ExternalReferenceTable::kSizeInBytes;
     124             :   const int kBuiltinsTableStart = IsolateData::builtins_table_offset();
     125             :   const unsigned kBuiltinsTableSize =
     126             :       Builtins::builtin_count * kSystemPointerSize;
     127             : 
     128             :   if (static_cast<unsigned>(offset - kRootsTableStart) < kRootsTableSize) {
     129             :     uint32_t offset_in_roots_table = offset - kRootsTableStart;
     130             : 
     131             :     // Fail safe in the unlikely case of an arbitrary root-relative offset.
     132             :     if (offset_in_roots_table % kSystemPointerSize != 0) return nullptr;
     133             : 
     134             :     RootIndex root_index =
     135             :         static_cast<RootIndex>(offset_in_roots_table / kSystemPointerSize);
     136             : 
     137             :     SNPrintF(v8_buffer_, "root (%s)", RootsTable::name(root_index));
     138             :     return v8_buffer_.start();
     139             : 
     140             :   } else if (static_cast<unsigned>(offset - kExtRefsTableStart) <
     141             :              kExtRefsTableSize) {
     142             :     uint32_t offset_in_extref_table = offset - kExtRefsTableStart;
     143             : 
     144             :     // Fail safe in the unlikely case of an arbitrary root-relative offset.
     145             :     if (offset_in_extref_table % ExternalReferenceTable::kEntrySize != 0) {
     146             :       return nullptr;
     147             :     }
     148             : 
     149             :     // Likewise if the external reference table is uninitialized.
     150             :     if (!isolate_->external_reference_table()->is_initialized()) {
     151             :       return nullptr;
     152             :     }
     153             : 
     154             :     SNPrintF(v8_buffer_, "external reference (%s)",
     155             :              isolate_->external_reference_table()->NameFromOffset(
     156             :                  offset_in_extref_table));
     157             :     return v8_buffer_.start();
     158             : 
     159             :   } else if (static_cast<unsigned>(offset - kBuiltinsTableStart) <
     160             :              kBuiltinsTableSize) {
     161             :     uint32_t offset_in_builtins_table = (offset - kBuiltinsTableStart);
     162             : 
     163             :     Builtins::Name builtin_id = static_cast<Builtins::Name>(
     164             :         offset_in_builtins_table / kSystemPointerSize);
     165             : 
     166             :     const char* name = Builtins::name(builtin_id);
     167             :     SNPrintF(v8_buffer_, "builtin (%s)", name);
     168             :     return v8_buffer_.start();
     169             : 
     170             :   } else {
     171             :     // It must be a direct access to one of the external values.
     172             :     if (directly_accessed_external_refs_.empty()) {
     173             :       InitExternalRefsCache();
     174             :     }
     175             : 
     176             :     auto iter = directly_accessed_external_refs_.find(offset);
     177             :     if (iter != directly_accessed_external_refs_.end()) {
     178             :       SNPrintF(v8_buffer_, "external value (%s)", iter->second);
     179             :       return v8_buffer_.start();
     180             :     }
     181             :     return "WAAT??? What are we accessing here???";
     182             :   }
     183             : }
     184             : 
     185             : static void DumpBuffer(std::ostream* os, StringBuilder* out) {
     186             :   (*os) << out->Finalize() << std::endl;
     187             :   out->Reset();
     188             : }
     189             : 
     190             : 
     191             : static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength;
     192             : static const int kRelocInfoPosition = 57;
     193             : 
     194             : static void PrintRelocInfo(StringBuilder* out, Isolate* isolate,
     195             :                            const ExternalReferenceEncoder* ref_encoder,
     196             :                            std::ostream* os, CodeReference host,
     197             :                            RelocInfo* relocinfo, bool first_reloc_info = true) {
     198             :   // Indent the printing of the reloc info.
     199             :   if (first_reloc_info) {
     200             :     // The first reloc info is printed after the disassembled instruction.
     201             :     out->AddPadding(' ', kRelocInfoPosition - out->position());
     202             :   } else {
     203             :     // Additional reloc infos are printed on separate lines.
     204             :     DumpBuffer(os, out);
     205             :     out->AddPadding(' ', kRelocInfoPosition);
     206             :   }
     207             : 
     208             :   RelocInfo::Mode rmode = relocinfo->rmode();
     209             :   if (rmode == RelocInfo::DEOPT_SCRIPT_OFFSET) {
     210             :     out->AddFormatted("    ;; debug: deopt position, script offset '%d'",
     211             :                       static_cast<int>(relocinfo->data()));
     212             :   } else if (rmode == RelocInfo::DEOPT_INLINING_ID) {
     213             :     out->AddFormatted("    ;; debug: deopt position, inlining id '%d'",
     214             :                       static_cast<int>(relocinfo->data()));
     215             :   } else if (rmode == RelocInfo::DEOPT_REASON) {
     216             :     DeoptimizeReason reason = static_cast<DeoptimizeReason>(relocinfo->data());
     217             :     out->AddFormatted("    ;; debug: deopt reason '%s'",
     218             :                       DeoptimizeReasonToString(reason));
     219             :   } else if (rmode == RelocInfo::DEOPT_ID) {
     220             :     out->AddFormatted("    ;; debug: deopt index %d",
     221             :                       static_cast<int>(relocinfo->data()));
     222             :   } else if (rmode == RelocInfo::EMBEDDED_OBJECT) {
     223             :     HeapStringAllocator allocator;
     224             :     StringStream accumulator(&allocator);
     225             :     relocinfo->target_object()->ShortPrint(&accumulator);
     226             :     std::unique_ptr<char[]> obj_name = accumulator.ToCString();
     227             :     out->AddFormatted("    ;; object: %s", obj_name.get());
     228             :   } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
     229             :     const char* reference_name =
     230             :         ref_encoder ? ref_encoder->NameOfAddress(
     231             :                           isolate, relocinfo->target_external_reference())
     232             :                     : "unknown";
     233             :     out->AddFormatted("    ;; external reference (%s)", reference_name);
     234             :   } else if (RelocInfo::IsCodeTargetMode(rmode)) {
     235             :     out->AddFormatted("    ;; code:");
     236             :     Code code = isolate->heap()->GcSafeFindCodeForInnerPointer(
     237             :         relocinfo->target_address());
     238             :     Code::Kind kind = code->kind();
     239             :     if (code->is_builtin()) {
     240             :       out->AddFormatted(" Builtin::%s", Builtins::name(code->builtin_index()));
     241             :     } else {
     242             :       out->AddFormatted(" %s", Code::Kind2String(kind));
     243             :     }
     244             :   } else if (RelocInfo::IsWasmStubCall(rmode) && host.is_wasm_code()) {
     245             :     // Host is isolate-independent, try wasm native module instead.
     246             :     const char* runtime_stub_name =
     247             :         host.as_wasm_code()->native_module()->GetRuntimeStubName(
     248             :             relocinfo->wasm_stub_call_address());
     249             :     out->AddFormatted("    ;; wasm stub: %s", runtime_stub_name);
     250             :   } else if (RelocInfo::IsRuntimeEntry(rmode) && isolate &&
     251             :              isolate->deoptimizer_data() != nullptr) {
     252             :     // A runtime entry relocinfo might be a deoptimization bailout.
     253             :     Address addr = relocinfo->target_address();
     254             :     DeoptimizeKind type;
     255             :     if (Deoptimizer::IsDeoptimizationEntry(isolate, addr, &type)) {
     256             :       out->AddFormatted("    ;; %s deoptimization bailout",
     257             :                         Deoptimizer::MessageFor(type));
     258             :     } else {
     259             :       out->AddFormatted("    ;; %s", RelocInfo::RelocModeName(rmode));
     260             :     }
     261             :   } else {
     262             :     out->AddFormatted("    ;; %s", RelocInfo::RelocModeName(rmode));
     263             :   }
     264             : }
     265             : 
     266             : static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder,
     267             :                     std::ostream* os, CodeReference code,
     268             :                     const V8NameConverter& converter, byte* begin, byte* end,
     269             :                     Address current_pc) {
     270             :   CHECK(!code.is_null());
     271             :   v8::internal::EmbeddedVector<char, 128> decode_buffer;
     272             :   v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer;
     273             :   StringBuilder out(out_buffer.start(), out_buffer.length());
     274             :   byte* pc = begin;
     275             :   disasm::Disassembler d(converter,
     276             :                          disasm::Disassembler::kContinueOnUnimplementedOpcode);
     277             :   RelocIterator* it = nullptr;
     278             :   CodeCommentsIterator cit(code.code_comments());
     279             :   // Relocation exists if we either have no isolate (wasm code),
     280             :   // or we have an isolate and it is not an off-heap instruction stream.
     281             :   if (!isolate ||
     282             :       !InstructionStream::PcIsOffHeap(isolate, bit_cast<Address>(begin))) {
     283             :     it = new RelocIterator(code);
     284             :   } else {
     285             :     // No relocation information when printing code stubs.
     286             :   }
     287             :   int constants = -1;  // no constants being decoded at the start
     288             : 
     289             :   while (pc < end) {
     290             :     // First decode instruction so that we know its length.
     291             :     byte* prev_pc = pc;
     292             :     if (constants > 0) {
     293             :       SNPrintF(decode_buffer,
     294             :                "%08x       constant",
     295             :                *reinterpret_cast<int32_t*>(pc));
     296             :       constants--;
     297             :       pc += 4;
     298             :     } else {
     299             :       int num_const = d.ConstantPoolSizeAt(pc);
     300             :       if (num_const >= 0) {
     301             :         SNPrintF(decode_buffer,
     302             :                  "%08x       constant pool begin (num_const = %d)",
     303             :                  *reinterpret_cast<int32_t*>(pc), num_const);
     304             :         constants = num_const;
     305             :         pc += 4;
     306             :       } else if (it != nullptr && !it->done() &&
     307             :                  it->rinfo()->pc() == reinterpret_cast<Address>(pc) &&
     308             :                  it->rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE) {
     309             :         // raw pointer embedded in code stream, e.g., jump table
     310             :         byte* ptr = *reinterpret_cast<byte**>(pc);
     311             :         SNPrintF(
     312             :             decode_buffer, "%08" V8PRIxPTR "      jump table entry %4" PRIuS,
     313             :             reinterpret_cast<intptr_t>(ptr), static_cast<size_t>(ptr - begin));
     314             :         pc += sizeof(ptr);
     315             :       } else {
     316             :         decode_buffer[0] = '\0';
     317             :         pc += d.InstructionDecode(decode_buffer, pc);
     318             :       }
     319             :     }
     320             : 
     321             :     // Collect RelocInfo for this instruction (prev_pc .. pc-1)
     322             :     std::vector<const char*> comments;
     323             :     std::vector<Address> pcs;
     324             :     std::vector<RelocInfo::Mode> rmodes;
     325             :     std::vector<intptr_t> datas;
     326             :     if (it != nullptr) {
     327             :       while (!it->done() && it->rinfo()->pc() < reinterpret_cast<Address>(pc)) {
     328             :         // Collect all data.
     329             :         pcs.push_back(it->rinfo()->pc());
     330             :         rmodes.push_back(it->rinfo()->rmode());
     331             :         datas.push_back(it->rinfo()->data());
     332             :         it->next();
     333             :       }
     334             :     }
     335             :     while (cit.HasCurrent() &&
     336             :            cit.GetPCOffset() < static_cast<Address>(pc - begin)) {
     337             :       comments.push_back(cit.GetComment());
     338             :       cit.Next();
     339             :     }
     340             : 
     341             :     // Comments.
     342             :     for (size_t i = 0; i < comments.size(); i++) {
     343             :       out.AddFormatted("                  %s", comments[i]);
     344             :       DumpBuffer(os, &out);
     345             :     }
     346             : 
     347             :     // Instruction address and instruction offset.
     348             :     if (FLAG_log_colour && reinterpret_cast<Address>(prev_pc) == current_pc) {
     349             :       // If this is the given "current" pc, make it yellow and bold.
     350             :       out.AddFormatted("\033[33;1m");
     351             :     }
     352             :     out.AddFormatted("%p  %4" V8PRIxPTRDIFF "  ", static_cast<void*>(prev_pc),
     353             :                      prev_pc - begin);
     354             : 
     355             :     // Instruction.
     356             :     out.AddFormatted("%s", decode_buffer.start());
     357             : 
     358             :     // Print all the reloc info for this instruction which are not comments.
     359             :     for (size_t i = 0; i < pcs.size(); i++) {
     360             :       // Put together the reloc info
     361             :       const CodeReference& host = code;
     362             :       Address constant_pool =
     363             :           host.is_null() ? kNullAddress : host.constant_pool();
     364             :       RelocInfo relocinfo(pcs[i], rmodes[i], datas[i], Code(), constant_pool);
     365             : 
     366             :       bool first_reloc_info = (i == 0);
     367             :       PrintRelocInfo(&out, isolate, ref_encoder, os, code, &relocinfo,
     368             :                      first_reloc_info);
     369             :     }
     370             : 
     371             :     // If this is a constant pool load and we haven't found any RelocInfo
     372             :     // already, check if we can find some RelocInfo for the target address in
     373             :     // the constant pool.
     374             :     if (pcs.empty() && !code.is_null()) {
     375             :       RelocInfo dummy_rinfo(reinterpret_cast<Address>(prev_pc),
     376             :       RelocInfo::NONE,
     377             :                             0, Code());
     378             :       if (dummy_rinfo.IsInConstantPool()) {
     379             :         Address constant_pool_entry_address =
     380             :             dummy_rinfo.constant_pool_entry_address();
     381             :         RelocIterator reloc_it(code);
     382             :         while (!reloc_it.done()) {
     383             :           if (reloc_it.rinfo()->IsInConstantPool() &&
     384             :               (reloc_it.rinfo()->constant_pool_entry_address() ==
     385             :                constant_pool_entry_address)) {
     386             :             PrintRelocInfo(&out, isolate, ref_encoder, os, code,
     387             :                            reloc_it.rinfo());
     388             :             break;
     389             :           }
     390             :           reloc_it.next();
     391             :         }
     392             :       }
     393             :     }
     394             : 
     395             :     if (FLAG_log_colour && reinterpret_cast<Address>(prev_pc) == current_pc) {
     396             :       out.AddFormatted("\033[m");
     397             :     }
     398             : 
     399             :     DumpBuffer(os, &out);
     400             :   }
     401             : 
     402             :   // Emit comments following the last instruction (if any).
     403             :   while (cit.HasCurrent() &&
     404             :          cit.GetPCOffset() < static_cast<Address>(pc - begin)) {
     405             :     out.AddFormatted("                  %s", cit.GetComment());
     406             :     DumpBuffer(os, &out);
     407             :     cit.Next();
     408             :   }
     409             : 
     410             :   delete it;
     411             :   return static_cast<int>(pc - begin);
     412             : }
     413             : 
     414             : int Disassembler::Decode(Isolate* isolate, std::ostream* os, byte* begin,
     415             :                          byte* end, CodeReference code, Address current_pc) {
     416             :   V8NameConverter v8NameConverter(isolate, code);
     417             :   if (isolate) {
     418             :     // We have an isolate, so support external reference names.
     419             :     SealHandleScope shs(isolate);
     420             :     DisallowHeapAllocation no_alloc;
     421             :     ExternalReferenceEncoder ref_encoder(isolate);
     422             :     return DecodeIt(isolate, &ref_encoder, os, code, v8NameConverter, begin,
     423             :                     end, current_pc);
     424             :   } else {
     425             :     // No isolate => isolate-independent code. No external reference names.
     426             :     return DecodeIt(nullptr, nullptr, os, code, v8NameConverter, begin, end,
     427             :                     current_pc);
     428             :   }
     429             : }
     430             : 
     431             : #else  // ENABLE_DISASSEMBLER
     432             : 
     433           0 : int Disassembler::Decode(Isolate* isolate, std::ostream* os, byte* begin,
     434             :                          byte* end, CodeReference code, Address current_pc) {
     435           0 :   return 0;
     436             : }
     437             : 
     438             : #endif  // ENABLE_DISASSEMBLER
     439             : 
     440             : }  // namespace internal
     441      120216 : }  // namespace v8

Generated by: LCOV version 1.10