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