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