tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WasmDebug.h (7675B)


      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/ColumnNumber.h"  // JS::LimitedColumnNumberOneOrigin
     23 #include "js/HashTable.h"
     24 #include "wasm/AsmJS.h"  // CodeMetadataForAsmJS::SeenSet
     25 #include "wasm/WasmCode.h"
     26 #include "wasm/WasmCodegenTypes.h"
     27 #include "wasm/WasmConstants.h"
     28 #include "wasm/WasmExprType.h"
     29 #include "wasm/WasmModule.h"
     30 #include "wasm/WasmTypeDecls.h"
     31 #include "wasm/WasmValType.h"
     32 
     33 namespace js {
     34 
     35 class Debugger;
     36 class WasmBreakpointSite;
     37 class WasmInstanceObject;
     38 
     39 namespace wasm {
     40 
     41 // The generated source location for the AST node/expression. The offset field
     42 // refers an offset in an binary format file.
     43 
     44 struct ExprLoc {
     45  uint32_t lineno;
     46  uint32_t column;
     47  uint32_t offset;
     48  ExprLoc() : lineno(0), column(0), offset(0) {}
     49  ExprLoc(uint32_t lineno_, uint32_t column_, uint32_t offset_)
     50      : lineno(lineno_), column(column_), offset(offset_) {}
     51 };
     52 
     53 using StepperCounters =
     54    HashMap<uint32_t, uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy>;
     55 using WasmBreakpointSiteMap =
     56    HashMap<uint32_t, WasmBreakpointSite*, DefaultHasher<uint32_t>,
     57            SystemAllocPolicy>;
     58 
     59 /*
     60 * [SMDOC] Wasm debug traps
     61 *
     62 * There is a single debug-trap handler for the process, WasmHandleDebugTrap
     63 * in WasmBuiltins.cpp.  That function is invoked through the Debug Trap Stub,
     64 * of which there is one per module, generated by GenerateDebugStub in
     65 * WasmStubs.cpp.  When any function in an instance needs to debug-trap for
     66 * any reason (enter frame, leave frame, breakpoint, or single-stepping) then
     67 * a pointer to the Debug Trap Stub is installed in the Instance.
     68 * Debug-enabled code will look for this pointer and call it if (1) it is not
     69 * null and (2) subject to filtering as follows.
     70 *
     71 * WasmHandleDebugTrap may therefore be called very frequently when any
     72 * function in the instance is being debugged, and must filter the trap
     73 * against the tables in the DebugState.  It can make use of the return
     74 * address for the call, which identifies the site uniquely.
     75 *
     76 * In order to greatly reduce the frequency of calls to the Debug Trap Stub,
     77 * an array of flag bits, one per function, is attached to the instance.  The
     78 * code at the breakable point calls a stub at the end of the function (the
     79 * Per Function Debug Stub) to check whether the bit is set for the function.
     80 * If it is not set, the per-function stub can return to its caller
     81 * immediately; if the bit is set, the per-function stub will jump to the
     82 * installed (per-module) Debug Trap Stub.
     83 *
     84 * See also [SMDOC] "Wasm debug traps -- code details"
     85 */
     86 
     87 class DebugState {
     88  const SharedCode code_;
     89  const SharedModule module_;
     90 
     91  // State maintained when debugging is enabled.
     92 
     93  bool enterFrameTrapsEnabled_;
     94  uint32_t enterAndLeaveFrameTrapsCounter_;
     95  WasmBreakpointSiteMap breakpointSites_;
     96  StepperCounters stepperCounters_;
     97 
     98  void enableDebuggingForFunction(Instance* instance, uint32_t funcIndex);
     99  void disableDebuggingForFunction(Instance* instance, uint32_t funcIndex);
    100  void enableDebugTrapping(Instance* instance);
    101  void disableDebugTrapping(Instance* instance);
    102 
    103 public:
    104  DebugState(const Code& code, const Module& module);
    105 
    106  void trace(JSTracer* trc);
    107  void finalize(JS::GCContext* gcx);
    108 
    109  const BytecodeSource& bytecode() const { return module_->debugBytecode(); }
    110 
    111  [[nodiscard]] bool getLineOffsets(size_t lineno, Vector<uint32_t>* offsets);
    112  [[nodiscard]] bool getAllColumnOffsets(Vector<ExprLoc>* offsets);
    113  [[nodiscard]] bool getOffsetLocation(
    114      uint32_t offset, uint32_t* lineno,
    115      JS::LimitedColumnNumberOneOrigin* column);
    116 
    117  // The Code can track enter/leave frame events. Any such event triggers
    118  // debug trap. The enter/leave frame events enabled or disabled across
    119  // all functions.
    120 
    121  void adjustEnterAndLeaveFrameTrapsState(JSContext* cx, Instance* instance,
    122                                          bool enabled);
    123  void ensureEnterFrameTrapsState(JSContext* cx, Instance* instance,
    124                                  bool enabled);
    125  bool enterFrameTrapsEnabled() const { return enterFrameTrapsEnabled_; }
    126 
    127  // When the Code is debugEnabled, individual breakpoints can be enabled or
    128  // disabled at instruction offsets.
    129 
    130  bool hasBreakpointTrapAtOffset(uint32_t offset);
    131  void toggleBreakpointTrap(JSRuntime* rt, Instance* instance, uint32_t offset,
    132                            bool enabled);
    133  WasmBreakpointSite* getBreakpointSite(uint32_t offset) const;
    134  WasmBreakpointSite* getOrCreateBreakpointSite(JSContext* cx,
    135                                                Instance* instance,
    136                                                uint32_t offset);
    137  bool hasBreakpointSite(uint32_t offset);
    138  void destroyBreakpointSite(JS::GCContext* gcx, Instance* instance,
    139                             uint32_t offset);
    140  void clearBreakpointsIn(JS::GCContext* gcx, WasmInstanceObject* instance,
    141                          js::Debugger* dbg, JSObject* handler);
    142 
    143  // When the Code is debug-enabled, single-stepping mode can be toggled on
    144  // the granularity of individual functions.
    145 
    146  bool stepModeEnabled(uint32_t funcIndex) const;
    147  [[nodiscard]] bool incrementStepperCount(JSContext* cx, Instance* instance,
    148                                           uint32_t funcIndex);
    149  void decrementStepperCount(JS::GCContext* gcx, Instance* instance,
    150                             uint32_t funcIndex);
    151 
    152  // Stack inspection helpers.
    153 
    154  [[nodiscard]] bool debugGetLocalTypes(uint32_t funcIndex,
    155                                        ValTypeVector* locals,
    156                                        size_t* argsLength,
    157                                        StackResults* stackResults);
    158  [[nodiscard]] bool getGlobal(Instance& instance, uint32_t globalIndex,
    159                               MutableHandleValue vp);
    160 
    161  // Debug URL helpers.
    162 
    163  [[nodiscard]] bool getSourceMappingURL(JSContext* cx,
    164                                         MutableHandleString result) const;
    165 
    166  // Accessors for commonly used elements of linked structures.
    167 
    168  const CodeBlock& debugCode() const { return code_->debugCodeBlock(); }
    169  const CodeSegment& debugSegment() const {
    170    return *code_->debugCodeBlock().segment;
    171  }
    172  const CodeMetadata& codeMeta() const { return code_->codeMeta(); }
    173  const CodeTailMetadata& codeTailMeta() const { return code_->codeTailMeta(); }
    174  const CodeMetadataForAsmJS* codeMetaForAsmJS() const {
    175    return code_->codeMetaForAsmJS();
    176  }
    177 
    178  uint32_t funcToCodeRangeIndex(uint32_t funcIndex) const {
    179    return debugCode().funcToCodeRange[funcIndex];
    180  }
    181 
    182  // about:memory reporting:
    183 
    184  void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf,
    185                     CodeMetadata::SeenSet* seenCodeMeta,
    186                     CodeMetadataForAsmJS::SeenSet* seenCodeMetaForAsmJS,
    187                     Code::SeenSet* seenCode, size_t* code, size_t* data) const;
    188 };
    189 
    190 using UniqueDebugState = UniquePtr<DebugState>;
    191 
    192 }  // namespace wasm
    193 }  // namespace js
    194 
    195 #endif  // wasm_debug_h