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-01-20 Functions: 2 3 66.7 %

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

Generated by: LCOV version 1.10