• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef JSVM_DFX_H
17 #define JSVM_DFX_H
18 
19 #include <cassert>
20 #include <unordered_set>
21 #include <vector>
22 
23 #include "jsvm_log.h"
24 #include "jsvm_version.h"
25 #include "platform/platform.h"
26 #include "jsvm_types.h"
27 
28 // v8 header
29 #include "v8.h"
30 
31 #define JSVM_FATAL(message)                                                                      \
32     do {                                                                                         \
33         /* Make sure that this struct does not end up in inline code, but      */                \
34         /* rather in a read-only data section when modifying this code.        */                \
35         jsvm::OnFatalError(STRINGIFY(__FILE__) ":" STRINGIFY(__LINE__) " ", STRINGIFY(message)); \
36     } while (0)
37 
38 namespace jsvm {
OnFatalError(const char * location,const char * message)39 [[noreturn]] inline void OnFatalError(const char* location, const char* message)
40 {
41     LOG(Fatal) << "JSVM Fatal Error Position : " << (location ? location : "Unkown");
42     LOG(Fatal) << "JSVM Fatal Error Message : " << (message ? message : "Unkown");
43     platform::OS::Abort();
44 }
45 
46 class DebugSealHandleScope {
47 public:
48     explicit inline DebugSealHandleScope(v8::Isolate* isolate = nullptr)
49 #ifdef DEBUG
50         : sealHandleScope(isolate != nullptr ? isolate : v8::Isolate::GetCurrent())
51 #endif
52     {}
53 
54 private:
55 #ifdef DEBUG
56     v8::SealHandleScope sealHandleScope;
57 #endif
58 };
59 
60 /* A ScopeLifecycleTracker can record the depths of different scopes and */
61 /* the JSVM_Value type variables within each scope.                      */
62 class ScopeLifecycleTracker {
63 public:
GetCurrentScopeDepth()64     uint32_t GetCurrentScopeDepth() const
65     {
66         return scopeDepthToVal.size();
67     }
68 
IncHandleScopeDepth()69     void IncHandleScopeDepth()
70     {
71         scopeDepthToVal.push_back(std::vector<JSVM_Value>());
72     }
73 
DecHandleScopeDepth()74     void DecHandleScopeDepth()
75     {
76         scopeDepthToVal.pop_back();
77     }
78 
ReleaseJSVMVals()79     void ReleaseJSVMVals()
80     {
81         if (scopeDepthToVal.size() == 0) {
82             JSVM_FATAL("Unpaired HandleScope detected after scope check is enabled!");
83         }
84         for (auto item : scopeDepthToVal[scopeDepthToVal.size() - 1]) {
85             addedVal.erase(item);
86         }
87     }
88 
89     void AddJSVMVal(JSVM_Value val, bool isEscape = false)
90     {
91         if (scopeDepthToVal.size() == 0) {
92             JSVM_FATAL("Unpaired HandleScope detected after scope check is enabled!");
93         }
94         addedVal.insert(val);
95         if (!isEscape) {
96             // Add JSVM value to current depth
97             scopeDepthToVal[scopeDepthToVal.size() - 1].push_back(val);
98         } else {
99             // Add JSVM value to parent depth
100             constexpr size_t depth = 2;
101             if (scopeDepthToVal.size() < depth) {
102                 JSVM_FATAL("Not in any scope!");
103             }
104             scopeDepthToVal[scopeDepthToVal.size() - depth].push_back(val);
105         }
106     }
107 
CheckJSVMVal(JSVM_Value val)108     bool CheckJSVMVal(JSVM_Value val)
109     {
110         auto it = addedVal.find(val);
111         if (it != addedVal.end()) {
112             return true;
113         } else {
114             return false;
115         }
116     }
117 
118 private:
119     std::unordered_set<JSVM_Value> addedVal;
120     std::vector<std::vector<JSVM_Value>> scopeDepthToVal;
121 };
122 
123 } // namespace jsvm
124 
125 constexpr uint16_t FUNCTIONNAME_MAX = 1024;
126 
127 struct JsvmStepParam {
128     uintptr_t *fp;
129     uintptr_t *sp;
130     uintptr_t *pc;
131     bool *isJsvmFrame;
132 
JsvmStepParamJsvmStepParam133     JsvmStepParam(uintptr_t *fp, uintptr_t *sp, uintptr_t *pc, bool *isJsvmFrame)
134         : fp(fp), sp(sp), pc(pc), isJsvmFrame(isJsvmFrame) {}
135 };
136 struct JsvmFunction {
137     char functionName[FUNCTIONNAME_MAX];
138 };
139 
140 typedef bool (*ReadMemFunc)(void *ctx, uintptr_t addr, uintptr_t *val);
141 
142 extern "C" int step_jsvm(void *ctx, ReadMemFunc readMem, JsvmStepParam *frame);
143 
144 extern "C" int create_jsvm_extractor(uintptr_t *extractorPptr, uint32_t pid);
145 
146 extern "C" int destroy_jsvm_extractor(uintptr_t extractorPtr);
147 
148 extern "C" int jsvm_parse_js_frame_info(uintptr_t pc,
149                                         uintptr_t jsvmExtractorPtr,
150                                         JsvmFunction *jsvmFunction);
151 
152 
153 #define UNREACHABLE(...) JSVM_FATAL("Unreachable code reached" __VA_OPT__(": ") __VA_ARGS__)
154 
155 #ifdef __GNUC__
156 #define LIKELY(expr) __builtin_expect(!!(expr), 1)
157 #define UNLIKELY(expr) __builtin_expect(!!(expr), 0)
158 #else
159 #define LIKELY(expr) expr
160 #define UNLIKELY(expr) expr
161 #endif
162 
163 #define CHECK(expr)              \
164     do {                         \
165         if (UNLIKELY(!(expr))) { \
166             JSVM_FATAL(expr);    \
167         }                        \
168     } while (0)
169 
170 #define CHECK_EQ(a, b) CHECK((a) == (b))
171 #define CHECK_NE(a, b) CHECK((a) != (b))
172 #define CHECK_LE(a, b) CHECK((a) <= (b))
173 #define CHECK_GE(a, b) CHECK((a) >= (b))
174 #define CHECK_LT(a, b) CHECK((a) < (b))
175 #define CHECK_GT(a, b) CHECK((a) > (b))
176 #define CHECK_NULL(val) CHECK((val) == nullptr)
177 #define CHECK_NOT_NULL(val) CHECK((val) != nullptr)
178 #define CHECK_IMPLIES(a, b) CHECK(!(a) || (b))
179 
180 #ifdef DEBUG
181 #define DCHECK(expr) CHECK(expr)
182 #define DCHECK_EQ(a, b) CHECK_EQ(a, b)
183 #define DCHECK_NE(a, b) CHECK_NE(a, b)
184 #define DCHECK_LE(a, b) CHECK_LE(a, b)
185 #define DCHECK_GE(a, b) CHECK_GE(a, b)
186 #define DCHECK_LT(a, b) CHECK_LT(a, b)
187 #define DCHECK_GT(a, b) CHECK_GT(a, b)
188 #define DCHECK_NULL(val) CHECK_NULL(val)
189 #define DCHECK_NOT_NULL(val) CHECK_NOT_NULL(val)
190 #define DCHECK_IMPLIES(a, b) CHECK_IMPLIES(a, b)
191 #else
192 #define DCHECK(expr)
193 #define DCHECK_EQ(a, b)
194 #define DCHECK_NE(a, b)
195 #define DCHECK_LE(a, b)
196 #define DCHECK_GE(a, b)
197 #define DCHECK_LT(a, b)
198 #define DCHECK_GT(a, b)
199 #define DCHECK_NULL(val)
200 #define DCHECK_NOT_NULL(val)
201 #define DCHECK_IMPLIES(a, b)
202 #endif
203 
204 #endif