LCOV - code coverage report
Current view: top level - js/src/wasm - WasmDebug.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 356 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 30 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  *
       4             :  * Copyright 2016 Mozilla Foundation
       5             :  *
       6             :  * Licensed under the Apache License, Version 2.0 (the "License");
       7             :  * you may not use this file except in compliance with the License.
       8             :  * You may obtain a copy of the License at
       9             :  *
      10             :  *     http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  * Unless required by applicable law or agreed to in writing, software
      13             :  * distributed under the License is distributed on an "AS IS" BASIS,
      14             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  * See the License for the specific language governing permissions and
      16             :  * limitations under the License.
      17             :  */
      18             : 
      19             : #include "wasm/WasmDebug.h"
      20             : 
      21             : #include "mozilla/BinarySearch.h"
      22             : 
      23             : #include "ds/Sort.h"
      24             : #include "jit/ExecutableAllocator.h"
      25             : #include "jit/MacroAssembler.h"
      26             : #include "vm/Debugger.h"
      27             : #include "vm/StringBuffer.h"
      28             : #include "wasm/WasmBinaryToText.h"
      29             : #include "wasm/WasmValidate.h"
      30             : 
      31             : using namespace js;
      32             : using namespace js::jit;
      33             : using namespace js::wasm;
      34             : 
      35             : using mozilla::BinarySearchIf;
      36             : 
      37             : bool
      38           0 : GeneratedSourceMap::searchLineByOffset(JSContext* cx, uint32_t offset, size_t* exprlocIndex)
      39             : {
      40           0 :     MOZ_ASSERT(!exprlocs_.empty());
      41           0 :     size_t exprlocsLength = exprlocs_.length();
      42             : 
      43             :     // Lazily build sorted array for fast log(n) lookup.
      44           0 :     if (!sortedByOffsetExprLocIndices_) {
      45           0 :         ExprLocIndexVector scratch;
      46           0 :         auto indices = MakeUnique<ExprLocIndexVector>();
      47           0 :         if (!indices || !indices->resize(exprlocsLength) || !scratch.resize(exprlocsLength)) {
      48           0 :             ReportOutOfMemory(cx);
      49           0 :             return false;
      50             :         }
      51           0 :         sortedByOffsetExprLocIndices_ = Move(indices);
      52             : 
      53           0 :         for (size_t i = 0; i < exprlocsLength; i++)
      54           0 :             (*sortedByOffsetExprLocIndices_)[i] = i;
      55             : 
      56           0 :         auto compareExprLocViaIndex = [&](uint32_t i, uint32_t j, bool* lessOrEqualp) -> bool {
      57           0 :             *lessOrEqualp = exprlocs_[i].offset <= exprlocs_[j].offset;
      58           0 :             return true;
      59           0 :         };
      60           0 :         MOZ_ALWAYS_TRUE(MergeSort(sortedByOffsetExprLocIndices_->begin(), exprlocsLength,
      61             :                                   scratch.begin(), compareExprLocViaIndex));
      62             :     }
      63             : 
      64             :     // Allowing non-exact search and if BinarySearchIf returns out-of-bound
      65             :     // index, moving the index to the last index.
      66           0 :     auto lookupFn = [&](uint32_t i) -> int {
      67           0 :         const ExprLoc& loc = exprlocs_[i];
      68           0 :         return offset == loc.offset ? 0 : offset < loc.offset ? -1 : 1;
      69           0 :     };
      70             :     size_t match;
      71           0 :     Unused << BinarySearchIf(sortedByOffsetExprLocIndices_->begin(), 0, exprlocsLength, lookupFn, &match);
      72           0 :     if (match >= exprlocsLength)
      73           0 :         match = exprlocsLength - 1;
      74           0 :     *exprlocIndex = (*sortedByOffsetExprLocIndices_)[match];
      75           0 :     return true;
      76             : }
      77             : 
      78             : size_t
      79           0 : GeneratedSourceMap::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
      80             : {
      81           0 :     size_t size = exprlocs_.sizeOfExcludingThis(mallocSizeOf);
      82           0 :     if (sortedByOffsetExprLocIndices_)
      83           0 :         size += sortedByOffsetExprLocIndices_->sizeOfIncludingThis(mallocSizeOf);
      84           0 :     return size;
      85             : }
      86             : 
      87           0 : DebugState::DebugState(SharedCode code,
      88             :                        const ShareableBytes* maybeBytecode,
      89           0 :                        bool binarySource)
      90           0 :   : code_(Move(code)),
      91             :     maybeBytecode_(maybeBytecode),
      92             :     binarySource_(binarySource),
      93           0 :     enterAndLeaveFrameTrapsCounter_(0)
      94             : {
      95           0 :     MOZ_ASSERT_IF(debugEnabled(), maybeBytecode);
      96           0 : }
      97             : 
      98             : const char enabledMessage[] =
      99             :     "Restart with developer tools open to view WebAssembly source";
     100             : 
     101             : const char tooBigMessage[] =
     102             :     "Unfortunately, this WebAssembly module is too big to view as text.\n"
     103             :     "We are working hard to remove this limitation.";
     104             : 
     105             : const char notGeneratedMessage[] =
     106             :     "WebAssembly text generation was disabled.";
     107             : 
     108             : static const unsigned TooBig = 1000000;
     109             : 
     110             : static const uint32_t DefaultBinarySourceColumnNumber = 1;
     111             : 
     112             : static const CallSite*
     113           0 : SlowCallSiteSearchByOffset(const MetadataTier& metadata, uint32_t offset)
     114             : {
     115           0 :     for (const CallSite& callSite : metadata.callSites) {
     116           0 :         if (callSite.lineOrBytecode() == offset && callSite.kind() == CallSiteDesc::Breakpoint)
     117           0 :             return &callSite;
     118             :     }
     119           0 :     return nullptr;
     120             : }
     121             : 
     122             : JSString*
     123           0 : DebugState::createText(JSContext* cx)
     124             : {
     125           0 :     StringBuffer buffer(cx);
     126           0 :     if (!maybeBytecode_) {
     127           0 :         if (!buffer.append(enabledMessage))
     128           0 :             return nullptr;
     129             : 
     130           0 :         MOZ_ASSERT(!maybeSourceMap_);
     131           0 :     } else if (binarySource_) {
     132           0 :         if (!buffer.append(notGeneratedMessage))
     133           0 :             return nullptr;
     134           0 :         return buffer.finishString();
     135           0 :     } else if (maybeBytecode_->bytes.length() > TooBig) {
     136           0 :         if (!buffer.append(tooBigMessage))
     137           0 :             return nullptr;
     138             : 
     139           0 :         MOZ_ASSERT(!maybeSourceMap_);
     140             :     } else {
     141           0 :         const Bytes& bytes = maybeBytecode_->bytes;
     142           0 :         auto sourceMap = MakeUnique<GeneratedSourceMap>();
     143           0 :         if (!sourceMap) {
     144           0 :             ReportOutOfMemory(cx);
     145           0 :             return nullptr;
     146             :         }
     147           0 :         maybeSourceMap_ = Move(sourceMap);
     148             : 
     149           0 :         if (!BinaryToText(cx, bytes.begin(), bytes.length(), buffer, maybeSourceMap_.get()))
     150           0 :             return nullptr;
     151             : 
     152             : #if DEBUG
     153             :         // Check that expression locations are sorted by line number.
     154           0 :         uint32_t lastLineno = 0;
     155           0 :         for (const ExprLoc& loc : maybeSourceMap_->exprlocs()) {
     156           0 :             MOZ_ASSERT(lastLineno <= loc.lineno);
     157           0 :             lastLineno = loc.lineno;
     158             :         }
     159             : #endif
     160             :     }
     161             : 
     162           0 :     return buffer.finishString();
     163             : }
     164             : 
     165             : bool
     166           0 : DebugState::ensureSourceMap(JSContext* cx)
     167             : {
     168           0 :     if (maybeSourceMap_ || !maybeBytecode_)
     169           0 :         return true;
     170             : 
     171             :     // We just need to cache maybeSourceMap_, ignoring the text result.
     172           0 :     return createText(cx);
     173             : }
     174             : 
     175             : struct LineComparator
     176             : {
     177             :     const uint32_t lineno;
     178           0 :     explicit LineComparator(uint32_t lineno) : lineno(lineno) {}
     179             : 
     180           0 :     int operator()(const ExprLoc& loc) const {
     181           0 :         return lineno == loc.lineno ? 0 : lineno < loc.lineno ? -1 : 1;
     182             :     }
     183             : };
     184             : 
     185             : bool
     186           0 : DebugState::getLineOffsets(JSContext* cx, size_t lineno, Vector<uint32_t>* offsets)
     187             : {
     188           0 :     if (!debugEnabled())
     189           0 :         return true;
     190             : 
     191           0 :     if (binarySource_) {
     192           0 :         const CallSite* callsite = SlowCallSiteSearchByOffset(metadata(Tier::Debug), lineno);
     193           0 :         if (callsite && !offsets->append(lineno))
     194           0 :             return false;
     195           0 :         return true;
     196             :     }
     197             : 
     198           0 :     if (!ensureSourceMap(cx))
     199           0 :         return false;
     200             : 
     201           0 :     if (!maybeSourceMap_)
     202           0 :         return true; // no source text available, keep offsets empty.
     203             : 
     204           0 :     ExprLocVector& exprlocs = maybeSourceMap_->exprlocs();
     205             : 
     206             :     // Binary search for the expression with the specified line number and
     207             :     // rewind to the first expression, if more than one expression on the same line.
     208             :     size_t match;
     209           0 :     if (!BinarySearchIf(exprlocs, 0, exprlocs.length(), LineComparator(lineno), &match))
     210           0 :         return true;
     211             : 
     212           0 :     while (match > 0 && exprlocs[match - 1].lineno == lineno)
     213           0 :         match--;
     214             : 
     215             :     // Return all expression offsets that were printed on the specified line.
     216           0 :     for (size_t i = match; i < exprlocs.length() && exprlocs[i].lineno == lineno; i++) {
     217           0 :         if (!offsets->append(exprlocs[i].offset))
     218           0 :             return false;
     219             :     }
     220             : 
     221           0 :     return true;
     222             : }
     223             : 
     224             : bool
     225           0 : DebugState::getAllColumnOffsets(JSContext* cx, Vector<ExprLoc>* offsets)
     226             : {
     227           0 :     if (!metadata().debugEnabled)
     228           0 :         return true;
     229             : 
     230           0 :     if (binarySource_) {
     231           0 :         for (const CallSite& callSite : metadata(Tier::Debug).callSites) {
     232           0 :             if (callSite.kind() != CallSite::Breakpoint)
     233           0 :                 continue;
     234           0 :             uint32_t offset = callSite.lineOrBytecode();
     235           0 :             if (!offsets->emplaceBack(offset, DefaultBinarySourceColumnNumber, offset))
     236           0 :                 return false;
     237             :         }
     238           0 :         return true;
     239             :     }
     240             : 
     241           0 :     if (!ensureSourceMap(cx))
     242           0 :         return false;
     243             : 
     244           0 :     if (!maybeSourceMap_)
     245           0 :         return true; // no source text available, keep offsets empty.
     246             : 
     247           0 :     return offsets->appendAll(maybeSourceMap_->exprlocs());
     248             : }
     249             : 
     250             : bool
     251           0 : DebugState::getOffsetLocation(JSContext* cx, uint32_t offset, bool* found, size_t* lineno, size_t* column)
     252             : {
     253           0 :     *found = false;
     254           0 :     if (!debugEnabled())
     255           0 :         return true;
     256             : 
     257           0 :     if (binarySource_) {
     258           0 :         if (!SlowCallSiteSearchByOffset(metadata(Tier::Debug), offset))
     259           0 :             return true; // offset was not found
     260           0 :         *found = true;
     261           0 :         *lineno = offset;
     262           0 :         *column = DefaultBinarySourceColumnNumber;
     263           0 :         return true;
     264             :     }
     265             : 
     266           0 :     if (!ensureSourceMap(cx))
     267           0 :         return false;
     268             : 
     269           0 :     if (!maybeSourceMap_ || maybeSourceMap_->exprlocs().empty())
     270           0 :         return true; // no source text available
     271             : 
     272             :     size_t foundAt;
     273           0 :     if (!maybeSourceMap_->searchLineByOffset(cx, offset, &foundAt))
     274           0 :         return false;
     275             : 
     276           0 :     const ExprLoc& loc = maybeSourceMap_->exprlocs()[foundAt];
     277           0 :     *found = true;
     278           0 :     *lineno = loc.lineno;
     279           0 :     *column = loc.column;
     280           0 :     return true;
     281             : }
     282             : 
     283             : bool
     284           0 : DebugState::totalSourceLines(JSContext* cx, uint32_t* count)
     285             : {
     286           0 :     *count = 0;
     287           0 :     if (!debugEnabled())
     288           0 :         return true;
     289             : 
     290           0 :     if (binarySource_) {
     291           0 :         if (maybeBytecode_)
     292           0 :             *count = maybeBytecode_->length();
     293           0 :         return true;
     294             :     }
     295             : 
     296           0 :     if (!ensureSourceMap(cx))
     297           0 :         return false;
     298             : 
     299           0 :     if (maybeSourceMap_)
     300           0 :         *count = maybeSourceMap_->totalLines();
     301           0 :     return true;
     302             : }
     303             : 
     304             : bool
     305           0 : DebugState::stepModeEnabled(uint32_t funcIndex) const
     306             : {
     307           0 :     return stepModeCounters_.initialized() && stepModeCounters_.lookup(funcIndex);
     308             : }
     309             : 
     310             : bool
     311           0 : DebugState::incrementStepModeCount(JSContext* cx, uint32_t funcIndex)
     312             : {
     313           0 :     MOZ_ASSERT(debugEnabled());
     314           0 :     const CodeRange& codeRange = codeRanges(Tier::Debug)[debugFuncToCodeRangeIndex(funcIndex)];
     315           0 :     MOZ_ASSERT(codeRange.isFunction());
     316             : 
     317           0 :     if (!stepModeCounters_.initialized() && !stepModeCounters_.init()) {
     318           0 :         ReportOutOfMemory(cx);
     319           0 :         return false;
     320             :     }
     321             : 
     322           0 :     StepModeCounters::AddPtr p = stepModeCounters_.lookupForAdd(funcIndex);
     323           0 :     if (p) {
     324           0 :         MOZ_ASSERT(p->value() > 0);
     325           0 :         p->value()++;
     326           0 :         return true;
     327             :     }
     328           0 :     if (!stepModeCounters_.add(p, funcIndex, 1)) {
     329           0 :         ReportOutOfMemory(cx);
     330           0 :         return false;
     331             :     }
     332             : 
     333           0 :     AutoWritableJitCode awjc(cx->runtime(), code_->segment(Tier::Debug).base() + codeRange.begin(),
     334           0 :                              codeRange.end() - codeRange.begin());
     335           0 :     AutoFlushICache afc("Code::incrementStepModeCount");
     336             : 
     337           0 :     for (const CallSite& callSite : callSites(Tier::Debug)) {
     338           0 :         if (callSite.kind() != CallSite::Breakpoint)
     339           0 :             continue;
     340           0 :         uint32_t offset = callSite.returnAddressOffset();
     341           0 :         if (codeRange.begin() <= offset && offset <= codeRange.end())
     342           0 :             toggleDebugTrap(offset, true);
     343             :     }
     344           0 :     return true;
     345             : }
     346             : 
     347             : bool
     348           0 : DebugState::decrementStepModeCount(FreeOp* fop, uint32_t funcIndex)
     349             : {
     350           0 :     MOZ_ASSERT(debugEnabled());
     351           0 :     const CodeRange& codeRange = codeRanges(Tier::Debug)[debugFuncToCodeRangeIndex(funcIndex)];
     352           0 :     MOZ_ASSERT(codeRange.isFunction());
     353             : 
     354           0 :     MOZ_ASSERT(stepModeCounters_.initialized() && !stepModeCounters_.empty());
     355           0 :     StepModeCounters::Ptr p = stepModeCounters_.lookup(funcIndex);
     356           0 :     MOZ_ASSERT(p);
     357           0 :     if (--p->value())
     358           0 :         return true;
     359             : 
     360           0 :     stepModeCounters_.remove(p);
     361             : 
     362           0 :     AutoWritableJitCode awjc(fop->runtime(), code_->segment(Tier::Debug).base() + codeRange.begin(),
     363           0 :                              codeRange.end() - codeRange.begin());
     364           0 :     AutoFlushICache afc("Code::decrementStepModeCount");
     365             : 
     366           0 :     for (const CallSite& callSite : callSites(Tier::Debug)) {
     367           0 :         if (callSite.kind() != CallSite::Breakpoint)
     368           0 :             continue;
     369           0 :         uint32_t offset = callSite.returnAddressOffset();
     370           0 :         if (codeRange.begin() <= offset && offset <= codeRange.end()) {
     371           0 :             bool enabled = breakpointSites_.initialized() && breakpointSites_.has(offset);
     372           0 :             toggleDebugTrap(offset, enabled);
     373             :         }
     374             :     }
     375           0 :     return true;
     376             : }
     377             : 
     378             : bool
     379           0 : DebugState::hasBreakpointTrapAtOffset(uint32_t offset)
     380             : {
     381           0 :     if (!debugEnabled())
     382           0 :         return false;
     383           0 :     return SlowCallSiteSearchByOffset(metadata(Tier::Debug), offset);
     384             : }
     385             : 
     386             : void
     387           0 : DebugState::toggleBreakpointTrap(JSRuntime* rt, uint32_t offset, bool enabled)
     388             : {
     389           0 :     MOZ_ASSERT(debugEnabled());
     390           0 :     const CallSite* callSite = SlowCallSiteSearchByOffset(metadata(Tier::Debug), offset);
     391           0 :     if (!callSite)
     392           0 :         return;
     393           0 :     size_t debugTrapOffset = callSite->returnAddressOffset();
     394             : 
     395           0 :     const CodeSegment& codeSegment = code_->segment(Tier::Debug);
     396           0 :     const CodeRange* codeRange = code_->lookupRange(codeSegment.base() + debugTrapOffset);
     397           0 :     MOZ_ASSERT(codeRange && codeRange->isFunction());
     398             : 
     399           0 :     if (stepModeCounters_.initialized() && stepModeCounters_.lookup(codeRange->funcIndex()))
     400           0 :         return; // no need to toggle when step mode is enabled
     401             : 
     402           0 :     AutoWritableJitCode awjc(rt, codeSegment.base(), codeSegment.length());
     403           0 :     AutoFlushICache afc("Code::toggleBreakpointTrap");
     404           0 :     AutoFlushICache::setRange(uintptr_t(codeSegment.base()), codeSegment.length());
     405           0 :     toggleDebugTrap(debugTrapOffset, enabled);
     406             : }
     407             : 
     408             : WasmBreakpointSite*
     409           0 : DebugState::getOrCreateBreakpointSite(JSContext* cx, uint32_t offset)
     410             : {
     411             :     WasmBreakpointSite* site;
     412           0 :     if (!breakpointSites_.initialized() && !breakpointSites_.init()) {
     413           0 :         ReportOutOfMemory(cx);
     414           0 :         return nullptr;
     415             :     }
     416             : 
     417           0 :     WasmBreakpointSiteMap::AddPtr p = breakpointSites_.lookupForAdd(offset);
     418           0 :     if (!p) {
     419           0 :         site = cx->runtime()->new_<WasmBreakpointSite>(this, offset);
     420           0 :         if (!site || !breakpointSites_.add(p, offset, site)) {
     421           0 :             js_delete(site);
     422           0 :             ReportOutOfMemory(cx);
     423           0 :             return nullptr;
     424             :         }
     425             :     } else {
     426           0 :         site = p->value();
     427             :     }
     428           0 :     return site;
     429             : }
     430             : 
     431             : bool
     432           0 : DebugState::hasBreakpointSite(uint32_t offset)
     433             : {
     434           0 :     return breakpointSites_.initialized() && breakpointSites_.has(offset);
     435             : }
     436             : 
     437             : void
     438           0 : DebugState::destroyBreakpointSite(FreeOp* fop, uint32_t offset)
     439             : {
     440           0 :     MOZ_ASSERT(breakpointSites_.initialized());
     441           0 :     WasmBreakpointSiteMap::Ptr p = breakpointSites_.lookup(offset);
     442           0 :     MOZ_ASSERT(p);
     443           0 :     fop->delete_(p->value());
     444           0 :     breakpointSites_.remove(p);
     445           0 : }
     446             : 
     447             : bool
     448           0 : DebugState::clearBreakpointsIn(JSContext* cx, WasmInstanceObject* instance, js::Debugger* dbg, JSObject* handler)
     449             : {
     450           0 :     MOZ_ASSERT(instance);
     451           0 :     if (!breakpointSites_.initialized())
     452           0 :         return true;
     453             : 
     454             :     // Make copy of all sites list, so breakpointSites_ can be modified by
     455             :     // destroyBreakpointSite calls.
     456           0 :     Vector<WasmBreakpointSite*> sites(cx);
     457           0 :     if (!sites.resize(breakpointSites_.count()))
     458           0 :         return false;
     459           0 :     size_t i = 0;
     460           0 :     for (WasmBreakpointSiteMap::Range r = breakpointSites_.all(); !r.empty(); r.popFront())
     461           0 :         sites[i++] = r.front().value();
     462             : 
     463           0 :     for (WasmBreakpointSite* site : sites) {
     464             :         Breakpoint* nextbp;
     465           0 :         for (Breakpoint* bp = site->firstBreakpoint(); bp; bp = nextbp) {
     466           0 :             nextbp = bp->nextInSite();
     467           0 :             if (bp->asWasm()->wasmInstance == instance &&
     468           0 :                 (!dbg || bp->debugger == dbg) &&
     469           0 :                 (!handler || bp->getHandler() == handler))
     470             :             {
     471           0 :                 bp->destroy(cx->runtime()->defaultFreeOp());
     472             :             }
     473             :         }
     474             :     }
     475           0 :     return true;
     476             : }
     477             : 
     478             : void
     479           0 : DebugState::toggleDebugTrap(uint32_t offset, bool enabled)
     480             : {
     481           0 :     MOZ_ASSERT(offset);
     482           0 :     uint8_t* trap = code_->segment(Tier::Debug).base() + offset;
     483           0 :     const Uint32Vector& farJumpOffsets = metadata(Tier::Debug).debugTrapFarJumpOffsets;
     484           0 :     if (enabled) {
     485           0 :         MOZ_ASSERT(farJumpOffsets.length() > 0);
     486           0 :         size_t i = 0;
     487           0 :         while (i < farJumpOffsets.length() && offset < farJumpOffsets[i])
     488           0 :             i++;
     489           0 :         if (i >= farJumpOffsets.length() ||
     490           0 :             (i > 0 && offset - farJumpOffsets[i - 1] < farJumpOffsets[i] - offset))
     491           0 :             i--;
     492           0 :         uint8_t* farJump = code_->segment(Tier::Debug).base() + farJumpOffsets[i];
     493           0 :         MacroAssembler::patchNopToCall(trap, farJump);
     494             :     } else {
     495           0 :         MacroAssembler::patchCallToNop(trap);
     496             :     }
     497           0 : }
     498             : 
     499             : void
     500           0 : DebugState::adjustEnterAndLeaveFrameTrapsState(JSContext* cx, bool enabled)
     501             : {
     502           0 :     MOZ_ASSERT(debugEnabled());
     503           0 :     MOZ_ASSERT_IF(!enabled, enterAndLeaveFrameTrapsCounter_ > 0);
     504             : 
     505           0 :     bool wasEnabled = enterAndLeaveFrameTrapsCounter_ > 0;
     506           0 :     if (enabled)
     507           0 :         ++enterAndLeaveFrameTrapsCounter_;
     508             :     else
     509           0 :         --enterAndLeaveFrameTrapsCounter_;
     510           0 :     bool stillEnabled = enterAndLeaveFrameTrapsCounter_ > 0;
     511           0 :     if (wasEnabled == stillEnabled)
     512           0 :         return;
     513             : 
     514           0 :     const CodeSegment& codeSegment = code_->segment(Tier::Debug);
     515           0 :     AutoWritableJitCode awjc(cx->runtime(), codeSegment.base(), codeSegment.length());
     516           0 :     AutoFlushICache afc("Code::adjustEnterAndLeaveFrameTrapsState");
     517           0 :     AutoFlushICache::setRange(uintptr_t(codeSegment.base()), codeSegment.length());
     518           0 :     for (const CallSite& callSite : callSites(Tier::Debug)) {
     519           0 :         if (callSite.kind() != CallSite::EnterFrame && callSite.kind() != CallSite::LeaveFrame)
     520           0 :             continue;
     521           0 :         toggleDebugTrap(callSite.returnAddressOffset(), stillEnabled);
     522             :     }
     523             : }
     524             : 
     525             : bool
     526           0 : DebugState::debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t* argsLength)
     527             : {
     528           0 :     MOZ_ASSERT(debugEnabled());
     529             : 
     530           0 :     const ValTypeVector& args = metadata().debugFuncArgTypes[funcIndex];
     531           0 :     *argsLength = args.length();
     532           0 :     if (!locals->appendAll(args))
     533           0 :         return false;
     534             : 
     535             :     // Decode local var types from wasm binary function body.
     536           0 :     const CodeRange& range = codeRanges(Tier::Debug)[debugFuncToCodeRangeIndex(funcIndex)];
     537             :     // In wasm, the Code points to the function start via funcLineOrBytecode.
     538           0 :     MOZ_ASSERT(!metadata().isAsmJS() && maybeBytecode_);
     539           0 :     size_t offsetInModule = range.funcLineOrBytecode();
     540           0 :     Decoder d(maybeBytecode_->begin() + offsetInModule,  maybeBytecode_->end(),
     541           0 :               offsetInModule, /* error = */ nullptr);
     542           0 :     return DecodeLocalEntries(d, metadata().kind, locals);
     543             : }
     544             : 
     545             : ExprType
     546           0 : DebugState::debugGetResultType(uint32_t funcIndex)
     547             : {
     548           0 :     MOZ_ASSERT(debugEnabled());
     549           0 :     return metadata().debugFuncReturnTypes[funcIndex];
     550             : }
     551             : 
     552             : JSString*
     553           0 : DebugState::debugDisplayURL(JSContext* cx) const
     554             : {
     555             :     // Build wasm module URL from following parts:
     556             :     // - "wasm:" as protocol;
     557             :     // - URI encoded filename from metadata (if can be encoded), plus ":";
     558             :     // - 64-bit hash of the module bytes (as hex dump).
     559           0 :     js::StringBuffer result(cx);
     560           0 :     if (!result.append("wasm:"))
     561           0 :         return nullptr;
     562           0 :     if (const char* filename = metadata().filename.get()) {
     563           0 :         js::StringBuffer filenamePrefix(cx);
     564             :         // EncodeURI returns false due to invalid chars or OOM -- fail only
     565             :         // during OOM.
     566           0 :         if (!EncodeURI(cx, filenamePrefix, filename, strlen(filename))) {
     567           0 :             if (!cx->isExceptionPending())
     568           0 :                 return nullptr;
     569           0 :             cx->clearPendingException(); // ignore invalid URI
     570           0 :         } else if (!result.append(filenamePrefix.finishString()) || !result.append(":")) {
     571           0 :             return nullptr;
     572             :         }
     573             :     }
     574             : 
     575           0 :     const ModuleHash& hash = metadata().hash;
     576           0 :     for (size_t i = 0; i < sizeof(ModuleHash); i++) {
     577           0 :         char digit1 = hash[i] / 16, digit2 = hash[i] % 16;
     578           0 :         if (!result.append((char)(digit1 < 10 ? digit1 + '0' : digit1 + 'a' - 10)))
     579           0 :             return nullptr;
     580           0 :         if (!result.append((char)(digit2 < 10 ? digit2 + '0' : digit2 + 'a' - 10)))
     581           0 :             return nullptr;
     582             :     }
     583           0 :     return result.finishString();
     584             : }
     585             : 
     586             : bool
     587           0 : DebugState::getSourceMappingURL(JSContext* cx, MutableHandleString result) const
     588             : {
     589           0 :     result.set(nullptr);
     590           0 :     if (!maybeBytecode_)
     591           0 :         return true;
     592             : 
     593           0 :     for (const CustomSection& customSection : metadata().customSections) {
     594           0 :         const NameInBytecode& sectionName = customSection.name;
     595           0 :         if (strlen(SourceMappingURLSectionName) != sectionName.length ||
     596           0 :             memcmp(SourceMappingURLSectionName, maybeBytecode_->begin() + sectionName.offset,
     597           0 :                    sectionName.length) != 0)
     598             :         {
     599           0 :             continue;
     600             :         }
     601             : 
     602             :         // Parse found "SourceMappingURL" custom section.
     603           0 :         Decoder d(maybeBytecode_->begin() + customSection.offset,
     604           0 :                   maybeBytecode_->begin() + customSection.offset + customSection.length,
     605           0 :                   customSection.offset,
     606           0 :                   /* error = */ nullptr);
     607             :         uint32_t nchars;
     608           0 :         if (!d.readVarU32(&nchars))
     609           0 :             return true; // ignoring invalid section data
     610             :         const uint8_t* chars;
     611           0 :         if (!d.readBytes(nchars, &chars) || d.currentPosition() != d.end())
     612           0 :             return true; // ignoring invalid section data
     613             : 
     614           0 :         UTF8Chars utf8Chars(reinterpret_cast<const char*>(chars), nchars);
     615           0 :         JSString* str = JS_NewStringCopyUTF8N(cx, utf8Chars);
     616           0 :         if (!str)
     617           0 :             return false;
     618           0 :         result.set(str);
     619           0 :         break;
     620             :     }
     621           0 :     return true;
     622             : }
     623             : 
     624             : void
     625           0 : DebugState::addSizeOfMisc(MallocSizeOf mallocSizeOf,
     626             :                           Metadata::SeenSet* seenMetadata,
     627             :                           ShareableBytes::SeenSet* seenBytes,
     628             :                           Code::SeenSet* seenCode,
     629             :                           size_t* code,
     630             :                           size_t* data) const
     631             : {
     632           0 :     code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenCode, code, data);
     633           0 :     if (maybeSourceMap_)
     634           0 :         *data += maybeSourceMap_->sizeOfExcludingThis(mallocSizeOf);
     635           0 :     if (maybeBytecode_)
     636           0 :         *data += maybeBytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
     637           0 : }

Generated by: LCOV version 1.13