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 #ifndef wasm_debug_h 20 #define wasm_debug_h 21 22 #include "js/HashTable.h" 23 #include "wasm/WasmCode.h" 24 #include "wasm/WasmTypes.h" 25 26 namespace js { 27 28 class Debugger; 29 class WasmBreakpoint; 30 class WasmBreakpointSite; 31 class WasmInstanceObject; 32 33 namespace wasm { 34 35 struct MetadataTier; 36 37 // The generated source location for the AST node/expression. The offset field 38 // refers an offset in an binary format file. 39 40 struct ExprLoc { 41 uint32_t lineno; 42 uint32_t column; 43 uint32_t offset; ExprLocExprLoc44 ExprLoc() : lineno(0), column(0), offset(0) {} ExprLocExprLoc45 ExprLoc(uint32_t lineno_, uint32_t column_, uint32_t offset_) 46 : lineno(lineno_), column(column_), offset(offset_) {} 47 }; 48 49 typedef Vector<ExprLoc, 0, SystemAllocPolicy> ExprLocVector; 50 typedef Vector<uint32_t, 0, SystemAllocPolicy> ExprLocIndexVector; 51 52 // The generated source map for WebAssembly binary file. This map is generated 53 // during building the text buffer (see BinaryToExperimentalText). 54 55 class GeneratedSourceMap { 56 ExprLocVector exprlocs_; 57 UniquePtr<ExprLocIndexVector> sortedByOffsetExprLocIndices_; 58 uint32_t totalLines_; 59 60 public: GeneratedSourceMap()61 explicit GeneratedSourceMap() : totalLines_(0) {} exprlocs()62 ExprLocVector& exprlocs() { return exprlocs_; } 63 totalLines()64 uint32_t totalLines() { return totalLines_; } setTotalLines(uint32_t val)65 void setTotalLines(uint32_t val) { totalLines_ = val; } 66 67 bool searchLineByOffset(JSContext* cx, uint32_t offset, size_t* exprlocIndex); 68 69 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 70 }; 71 72 typedef UniquePtr<GeneratedSourceMap> UniqueGeneratedSourceMap; 73 typedef HashMap<uint32_t, uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy> 74 StepModeCounters; 75 typedef HashMap<uint32_t, WasmBreakpointSite*, DefaultHasher<uint32_t>, 76 SystemAllocPolicy> 77 WasmBreakpointSiteMap; 78 79 class DebugState { 80 const SharedCode code_; 81 const SharedBytes maybeBytecode_; 82 UniqueGeneratedSourceMap maybeSourceMap_; 83 bool binarySource_; 84 85 // State maintained when debugging is enabled. In this case, the Code is 86 // not actually shared, but is referenced uniquely by the instance that is 87 // being debugged. 88 89 uint32_t enterAndLeaveFrameTrapsCounter_; 90 WasmBreakpointSiteMap breakpointSites_; 91 StepModeCounters stepModeCounters_; 92 93 void toggleDebugTrap(uint32_t offset, bool enabled); 94 bool ensureSourceMap(JSContext* cx); 95 96 public: 97 DebugState(SharedCode code, const ShareableBytes* maybeBytecode, 98 bool binarySource); 99 maybeBytecode()100 const Bytes* maybeBytecode() const { 101 return maybeBytecode_ ? &maybeBytecode_->bytes : nullptr; 102 } binarySource()103 bool binarySource() const { return binarySource_; } 104 105 // If the source bytecode was saved when this Code was constructed, this 106 // method will render the binary as text. Otherwise, a diagnostic string 107 // will be returned. 108 109 JSString* createText(JSContext* cx); 110 bool getLineOffsets(JSContext* cx, size_t lineno, Vector<uint32_t>* offsets); 111 bool getAllColumnOffsets(JSContext* cx, Vector<ExprLoc>* offsets); 112 bool getOffsetLocation(JSContext* cx, uint32_t offset, bool* found, 113 size_t* lineno, size_t* column); 114 bool totalSourceLines(JSContext* cx, uint32_t* count); 115 116 // The Code can track enter/leave frame events. Any such event triggers 117 // debug trap. The enter/leave frame events enabled or disabled across 118 // all functions. 119 120 void adjustEnterAndLeaveFrameTrapsState(JSContext* cx, bool enabled); 121 122 // When the Code is debugEnabled, individual breakpoints can be enabled or 123 // disabled at instruction offsets. 124 125 bool hasBreakpointTrapAtOffset(uint32_t offset); 126 void toggleBreakpointTrap(JSRuntime* rt, uint32_t offset, bool enabled); 127 WasmBreakpointSite* getOrCreateBreakpointSite(JSContext* cx, uint32_t offset); 128 bool hasBreakpointSite(uint32_t offset); 129 void destroyBreakpointSite(FreeOp* fop, uint32_t offset); 130 bool clearBreakpointsIn(JSContext* cx, WasmInstanceObject* instance, 131 js::Debugger* dbg, JSObject* handler); 132 133 // When the Code is debug-enabled, single-stepping mode can be toggled on 134 // the granularity of individual functions. 135 136 bool stepModeEnabled(uint32_t funcIndex) const; 137 bool incrementStepModeCount(JSContext* cx, uint32_t funcIndex); 138 bool decrementStepModeCount(FreeOp* fop, uint32_t funcIndex); 139 140 // Stack inspection helpers. 141 142 bool debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, 143 size_t* argsLength); 144 ExprType debugGetResultType(uint32_t funcIndex); 145 bool getGlobal(Instance& instance, uint32_t globalIndex, 146 MutableHandleValue vp); 147 148 // Debug URL helpers. 149 150 JSString* debugDisplayURL(JSContext* cx) const; 151 bool getSourceMappingURL(JSContext* cx, MutableHandleString result) const; 152 153 // Accessors for commonly used elements of linked structures. 154 metadata(Tier t)155 const MetadataTier& metadata(Tier t) const { return code_->metadata(t); } metadata()156 const Metadata& metadata() const { return code_->metadata(); } debugEnabled()157 bool debugEnabled() const { return metadata().debugEnabled; } codeRanges(Tier t)158 const CodeRangeVector& codeRanges(Tier t) const { 159 return metadata(t).codeRanges; 160 } callSites(Tier t)161 const CallSiteVector& callSites(Tier t) const { 162 return metadata(t).callSites; 163 } 164 debugFuncToCodeRangeIndex(uint32_t funcIndex)165 uint32_t debugFuncToCodeRangeIndex(uint32_t funcIndex) const { 166 return metadata(Tier::Debug).debugFuncToCodeRange[funcIndex]; 167 } 168 169 // about:memory reporting: 170 171 void addSizeOfMisc(MallocSizeOf mallocSizeOf, Metadata::SeenSet* seenMetadata, 172 ShareableBytes::SeenSet* seenBytes, 173 Code::SeenSet* seenCode, size_t* code, size_t* data) const; 174 }; 175 176 typedef UniquePtr<DebugState> UniqueDebugState; 177 178 } // namespace wasm 179 } // namespace js 180 181 #endif // wasm_debug_h 182