1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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/WasmModule.h"
24 #include "wasm/WasmTypes.h"
25 
26 namespace js {
27 
28 class Debugger;
29 class WasmBreakpointSite;
30 class WasmInstanceObject;
31 
32 namespace wasm {
33 
34 struct MetadataTier;
35 
36 // The generated source location for the AST node/expression. The offset field
37 // refers an offset in an binary format file.
38 
39 struct ExprLoc {
40   uint32_t lineno;
41   uint32_t column;
42   uint32_t offset;
ExprLocExprLoc43   ExprLoc() : lineno(0), column(0), offset(0) {}
ExprLocExprLoc44   ExprLoc(uint32_t lineno_, uint32_t column_, uint32_t offset_)
45       : lineno(lineno_), column(column_), offset(offset_) {}
46 };
47 
48 using StepperCounters =
49     HashMap<uint32_t, uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy>;
50 using WasmBreakpointSiteMap =
51     HashMap<uint32_t, WasmBreakpointSite*, DefaultHasher<uint32_t>,
52             SystemAllocPolicy>;
53 
54 class DebugState {
55   const SharedCode code_;
56   const SharedModule module_;
57 
58   // State maintained when debugging is enabled. In this case, the Code is
59   // not actually shared, but is referenced uniquely by the instance that is
60   // being debugged.
61 
62   bool enterFrameTrapsEnabled_;
63   uint32_t enterAndLeaveFrameTrapsCounter_;
64   WasmBreakpointSiteMap breakpointSites_;
65   StepperCounters stepperCounters_;
66 
67   void toggleDebugTrap(uint32_t offset, bool enabled);
68 
69  public:
70   DebugState(const Code& code, const Module& module);
71 
72   void trace(JSTracer* trc);
73   void finalize(JSFreeOp* fop);
74 
bytecode()75   const Bytes& bytecode() const { return module_->debugBytecode(); }
76 
77   [[nodiscard]] bool getLineOffsets(size_t lineno, Vector<uint32_t>* offsets);
78   [[nodiscard]] bool getAllColumnOffsets(Vector<ExprLoc>* offsets);
79   [[nodiscard]] bool getOffsetLocation(uint32_t offset, size_t* lineno,
80                                        size_t* column);
81 
82   // The Code can track enter/leave frame events. Any such event triggers
83   // debug trap. The enter/leave frame events enabled or disabled across
84   // all functions.
85 
86   void adjustEnterAndLeaveFrameTrapsState(JSContext* cx, bool enabled);
87   void ensureEnterFrameTrapsState(JSContext* cx, bool enabled);
enterFrameTrapsEnabled()88   bool enterFrameTrapsEnabled() const { return enterFrameTrapsEnabled_; }
89 
90   // When the Code is debugEnabled, individual breakpoints can be enabled or
91   // disabled at instruction offsets.
92 
93   bool hasBreakpointTrapAtOffset(uint32_t offset);
94   void toggleBreakpointTrap(JSRuntime* rt, uint32_t offset, bool enabled);
95   WasmBreakpointSite* getBreakpointSite(uint32_t offset) const;
96   WasmBreakpointSite* getOrCreateBreakpointSite(JSContext* cx,
97                                                 Instance* instance,
98                                                 uint32_t offset);
99   bool hasBreakpointSite(uint32_t offset);
100   void destroyBreakpointSite(JSFreeOp* fop, Instance* instance,
101                              uint32_t offset);
102   void clearBreakpointsIn(JSFreeOp* fop, WasmInstanceObject* instance,
103                           js::Debugger* dbg, JSObject* handler);
104 
105   // When the Code is debug-enabled, single-stepping mode can be toggled on
106   // the granularity of individual functions.
107 
108   bool stepModeEnabled(uint32_t funcIndex) const;
109   [[nodiscard]] bool incrementStepperCount(JSContext* cx, uint32_t funcIndex);
110   void decrementStepperCount(JSFreeOp* fop, uint32_t funcIndex);
111 
112   // Stack inspection helpers.
113 
114   [[nodiscard]] bool debugGetLocalTypes(uint32_t funcIndex,
115                                         ValTypeVector* locals,
116                                         size_t* argsLength,
117                                         StackResults* stackResults);
118   // Invariant: the result of getDebugResultType can only be used as long as
119   // code_->metadata() is live.  See MetaData::getFuncResultType for more
120   // information.
debugGetResultType(uint32_t funcIndex)121   ResultType debugGetResultType(uint32_t funcIndex) const {
122     return metadata().getFuncResultType(funcIndex);
123   }
124   [[nodiscard]] bool getGlobal(Instance& instance, uint32_t globalIndex,
125                                MutableHandleValue vp);
126 
127   // Debug URL helpers.
128 
129   [[nodiscard]] bool getSourceMappingURL(JSContext* cx,
130                                          MutableHandleString result) const;
131 
132   // Accessors for commonly used elements of linked structures.
133 
metadata(Tier t)134   const MetadataTier& metadata(Tier t) const { return code_->metadata(t); }
metadata()135   const Metadata& metadata() const { return code_->metadata(); }
codeRanges(Tier t)136   const CodeRangeVector& codeRanges(Tier t) const {
137     return metadata(t).codeRanges;
138   }
callSites(Tier t)139   const CallSiteVector& callSites(Tier t) const {
140     return metadata(t).callSites;
141   }
142 
funcToCodeRangeIndex(uint32_t funcIndex)143   uint32_t funcToCodeRangeIndex(uint32_t funcIndex) const {
144     return metadata(Tier::Debug).funcToCodeRange[funcIndex];
145   }
146 
147   // about:memory reporting:
148 
149   void addSizeOfMisc(MallocSizeOf mallocSizeOf, Metadata::SeenSet* seenMetadata,
150                      Code::SeenSet* seenCode, size_t* code, size_t* data) const;
151 };
152 
153 using UniqueDebugState = UniquePtr<DebugState>;
154 
155 }  // namespace wasm
156 }  // namespace js
157 
158 #endif  // wasm_debug_h
159