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
17 #include <sys/time.h>
18
19 #include "ecmascript/dfx/stackinfo/js_stackinfo.h"
20 #include "ecmascript/platform/aot_crash_info.h"
21 #include "ecmascript/platform/os.h"
22 #include "ecmascript/stubs/runtime_stubs-inl.h"
23 #include "ecmascript/jit/jit.h"
24 #if defined(PANDA_TARGET_OHOS)
25 #include "ecmascript/extractortool/src/extractor.h"
26 #endif
27 #if defined(ENABLE_EXCEPTION_BACKTRACE)
28 #include "ecmascript/platform/backtrace.h"
29 #endif
30 namespace panda::ecmascript {
31 [[maybe_unused]] static bool g_needCheck = true;
32
33 std::unordered_map<EntityId, std::string> JsStackInfo::nameMap;
34 std::unordered_map<EntityId, std::vector<uint8>> JsStackInfo::machineCodeMap;
35 JSStackTrace *JSStackTrace::trace_ = nullptr;
36 std::mutex JSStackTrace::mutex_;
37 size_t JSStackTrace::count_ = 0;
38
IsFastJitFunctionFrame(const FrameType frameType)39 bool IsFastJitFunctionFrame(const FrameType frameType)
40 {
41 return frameType == FrameType::FASTJIT_FUNCTION_FRAME || frameType == FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME;
42 }
43
BuildMethodTrace(Method * method,uint32_t pcOffset,LastBuilderCache & lastCache,bool enableStackSourceFile)44 std::string JsStackInfo::BuildMethodTrace(Method *method, uint32_t pcOffset, LastBuilderCache &lastCache,
45 bool enableStackSourceFile)
46 {
47 std::string data;
48 data.reserve(InitialLength);
49 data.append(" at ");
50 std::string name = method->ParseFunctionName();
51 if (name.empty()) {
52 data.append("anonymous (");
53 } else {
54 data.append(name).append(" (");
55 }
56 // source file
57 DebugInfoExtractor *debugExtractor = nullptr;
58 const JSPandaFile *pandaFile = method->GetJSPandaFile();
59 if (pandaFile == lastCache.pf) {
60 debugExtractor = lastCache.extractor;
61 } else {
62 debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(pandaFile);
63 lastCache.pf = pandaFile;
64 lastCache.extractor = debugExtractor;
65 }
66 if (enableStackSourceFile) {
67 const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
68 if (sourceFile.empty()) {
69 data.push_back('?');
70 } else {
71 data += sourceFile;
72 }
73 } else {
74 data.append("hidden");
75 }
76
77 data.push_back(':');
78 // line number and column number
79 auto callbackLineFunc = [&data](int32_t line) -> bool {
80 data += std::to_string(line + 1);
81 data.push_back(':');
82 return true;
83 };
84 auto callbackColumnFunc = [&data](int32_t column) -> bool {
85 data += std::to_string(column + 1);
86 return true;
87 };
88 panda_file::File::EntityId methodId = method->GetMethodId();
89 if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, pcOffset) ||
90 !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, pcOffset)) {
91 data.push_back('?');
92 }
93 data.append(")\n");
94 return data;
95 }
96
BuildInlinedMethodTrace(const JSPandaFile * pf,std::map<uint32_t,uint32_t> & methodOffsets)97 std::string JsStackInfo::BuildInlinedMethodTrace(const JSPandaFile *pf, std::map<uint32_t, uint32_t> &methodOffsets)
98 {
99 std::string data;
100 std::map<uint32_t, uint32_t>::reverse_iterator it;
101 for (it = methodOffsets.rbegin(); it != methodOffsets.rend(); it++) {
102 uint32_t methodId = it->second;
103 std::string name;
104 if (methodId == 0) {
105 name = "unknown";
106 } else {
107 name = std::string(MethodLiteral::GetMethodName(pf, EntityId(methodId)));
108 if (name == "") {
109 name = "anonymous";
110 }
111 }
112 data.append(" at ");
113 data.append(name);
114 data.append(" (maybe inlined).");
115 data.append(" depth: ");
116 data.append(std::to_string(it->first));
117
118 data.push_back('\n');
119 }
120 return data;
121 }
122
DumpJitCode(JSThread * thread)123 void JsStackInfo::DumpJitCode(JSThread *thread)
124 {
125 JSTaggedType exception = thread->GetException().GetRawData();
126 auto &jitCodeMaps = thread->GetJitCodeMaps();
127 auto jitCode = jitCodeMaps.find(exception);
128 if (jitCode == jitCodeMaps.end()) {
129 return;
130 }
131 std::set<MachineCode*> memos;
132 JsJitDumpElf jitDumpElf;
133 jitDumpElf.Init();
134 int64 idx = 0;
135 size_t offset = 0;
136 auto jitCodeVec = jitCodeMaps[exception];
137 for (size_t i = 0; i < jitCodeVec->size(); i++) {
138 auto item = (*jitCodeVec)[i];
139 auto machineCode = std::get<0>(item);
140 std::string methodName = std::get<1>(item);
141 uintptr_t pcOffset = std::get<2>(item);
142 auto res = memos.insert(machineCode);
143 if (res.second) {
144 LOG_ECMA(ERROR) << "jit : js crash at method : " << methodName << ", offset :" << pcOffset;
145 char *funcAddr = reinterpret_cast<char *>(machineCode->GetFuncAddr());
146 size_t len = machineCode->GetTextSize();
147 std::vector<uint8> vec(len);
148 if (memmove_s(vec.data(), len, funcAddr, len) != EOK) {
149 LOG_ECMA(ERROR) << "Fail to get machineCode on function addr: " << funcAddr;
150 }
151 jitDumpElf.AppendData(vec);
152 jitDumpElf.AppendSymbolToSymTab(idx++, offset, len, methodName);
153 offset += len;
154 }
155 }
156 std::string fileName = "jitCode-" + std::to_string(getpid());
157 std::string realOutPath;
158 std::string sanboxPath = panda::os::file::File::GetExtendedFilePath(AotCrashInfo::GetSandBoxPath());
159 if (!ecmascript::RealPath(sanboxPath, realOutPath, false)) {
160 return;
161 }
162 std::string outFile = realOutPath + "/" + fileName;
163 int fd = open(outFile.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
164 jitDumpElf.WriteJitElfFile(fd);
165 close(fd);
166 }
167
AssembleJitCodeMap(JSThread * thread,const JSHandle<JSObject> & jsErrorObj,JSFunction * func,Method * method,uintptr_t offset)168 void AssembleJitCodeMap(JSThread *thread, const JSHandle<JSObject> &jsErrorObj, JSFunction *func, Method *method,
169 uintptr_t offset)
170 {
171 ASSERT(!jsErrorObj.GetTaggedValue().IsUndefined());
172 JSTaggedValue machineCodeTagVal = func->GetMachineCode();
173 MachineCode *machineCode = MachineCode::Cast(machineCodeTagVal.GetTaggedObject());
174 std::string methodName = method->ParseFunctionName();
175 if (methodName.empty()) {
176 methodName = "anonymous";
177 }
178 thread->SetJitCodeMap(jsErrorObj.GetTaggedValue().GetRawData(), machineCode, methodName, offset);
179 }
180
BuildJsStackTrace(JSThread * thread,bool needNative,const JSHandle<JSObject> & jsErrorObj)181 std::string JsStackInfo::BuildJsStackTrace(JSThread *thread, bool needNative, const JSHandle<JSObject> &jsErrorObj)
182 {
183 std::string data;
184 data.reserve(InitialDeeps * InitialLength);
185 JSTaggedType *current = const_cast<JSTaggedType *>(thread->GetCurrentFrame());
186 FrameIterator it(current, thread);
187 uintptr_t baselineNativePc = 0;
188
189 LastBuilderCache lastCache;
190 for (; !it.Done(); it.Advance<GCVisitedFlag::HYBRID_STACK>()) {
191 if (it.GetFrameType() == FrameType::BASELINE_BUILTIN_FRAME) {
192 auto *frame = it.GetFrame<BaselineBuiltinFrame>();
193 baselineNativePc = frame->GetReturnAddr();
194 continue;
195 }
196 if (!it.IsJSFrame()) {
197 continue;
198 }
199 auto method = it.CheckAndGetMethod();
200 if (method == nullptr) {
201 continue;
202 }
203 if (!method->IsNativeWithCallField()) {
204 uint32_t pcOffset = 0;
205 if (it.GetFrameType() == FrameType::ASM_INTERPRETER_FRAME && baselineNativePc != 0) {
206 // the pcOffste in baseline frame slot is always uint64::max(), so pcOffset should be computed
207 JSHandle<JSFunction> function(thread, it.GetFunction());
208 pcOffset = RuntimeStubs::RuntimeGetBytecodePcOfstForBaseline(function, baselineNativePc);
209 baselineNativePc = 0;
210 } else {
211 pcOffset = it.GetBytecodeOffset();
212 }
213 data += BuildJsStackTraceInfo(thread, method, it, pcOffset, jsErrorObj, lastCache);
214 } else if (needNative) {
215 auto addr = method->GetNativePointer();
216 std::stringstream strm;
217 strm << addr;
218 data.append(" at native method (").append(strm.str()).append(")\n");
219 }
220 }
221 if (data.empty()) {
222 #if defined(ENABLE_EXCEPTION_BACKTRACE)
223 std::ostringstream stack;
224 Backtrace(stack);
225 data = stack.str();
226 #endif
227 }
228 return data;
229 }
230
BuildJsStackTraceInfo(JSThread * thread,Method * method,FrameIterator & it,uint32_t pcOffset,const JSHandle<JSObject> & jsErrorObj,LastBuilderCache & lastCache)231 std::string JsStackInfo::BuildJsStackTraceInfo(JSThread *thread, Method *method, FrameIterator &it,
232 uint32_t pcOffset, const JSHandle<JSObject> &jsErrorObj,
233 LastBuilderCache &lastCache)
234 {
235 const JSPandaFile *pf = method->GetJSPandaFile();
236 std::map<uint32_t, uint32_t> methodOffsets = it.GetInlinedMethodInfo();
237 FrameType frameType = it.GetFrameType();
238 if (IsFastJitFunctionFrame(frameType)) {
239 JSFunction *func = static_cast<JSFunction*>(it.GetFunction().GetTaggedObject());
240 if (!jsErrorObj.GetTaggedValue().IsUndefined()) {
241 AssembleJitCodeMap(thread, jsErrorObj, func, method, it.GetOptimizedReturnAddr());
242 }
243 }
244 return BuildInlinedMethodTrace(pf, methodOffsets) +
245 BuildMethodTrace(method, pcOffset, lastCache, thread->GetEnableStackSourceFile());
246 }
247
BuildCrashInfo(bool isJsCrash,uintptr_t pc,JSThread * thread)248 void JsStackInfo::BuildCrashInfo(bool isJsCrash, uintptr_t pc, JSThread *thread)
249 {
250 if (JsStackInfo::loader == nullptr) {
251 return;
252 }
253 if (!JsStackInfo::loader->IsEnableAOT() && !Jit::GetInstance()->IsEnableFastJit() &&
254 !pgo::PGOProfilerManager::GetInstance()->IsEnable()) {
255 return;
256 }
257 ohos::RuntimeInfoType type;
258 if (isJsCrash) {
259 type = ohos::RuntimeInfoType::JS;
260 } else if (pc != 0 && JsStackInfo::loader != nullptr && JsStackInfo::loader->InsideAOT(pc)) {
261 type = ohos::RuntimeInfoType::AOT_CRASH;
262 } else {
263 type = ohos::RuntimeInfoType::OTHERS;
264 }
265 ohos::AotRuntimeInfo::GetInstance().BuildCrashRuntimeInfo(type);
266 if (isJsCrash && thread != nullptr) {
267 DumpJitCode(thread);
268 }
269 }
270
BuildJsStackInfo(JSThread * thread,bool currentStack)271 std::vector<struct JsFrameInfo> JsStackInfo::BuildJsStackInfo(JSThread *thread, bool currentStack)
272 {
273 std::vector<struct JsFrameInfo> jsFrame;
274 uintptr_t *native = nullptr;
275 JSTaggedType *current = const_cast<JSTaggedType *>(thread->GetCurrentFrame());
276 FrameIterator it(current, thread);
277 for (; !it.Done(); it.Advance<GCVisitedFlag::HYBRID_STACK>()) {
278 if (!it.IsJSFrame()) {
279 continue;
280 }
281 auto method = it.CheckAndGetMethod();
282 if (method == nullptr) {
283 continue;
284 }
285 struct JsFrameInfo frameInfo;
286 if (native != nullptr) {
287 frameInfo.nativePointer = native;
288 native = nullptr;
289 }
290 if (!method->IsNativeWithCallField()) {
291 std::string name = method->ParseFunctionName();
292 if (name.empty()) {
293 frameInfo.functionName = "anonymous";
294 } else {
295 frameInfo.functionName = name;
296 }
297 // source file
298 DebugInfoExtractor *debugExtractor =
299 JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile());
300 const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
301 if (sourceFile.empty()) {
302 frameInfo.fileName = "?";
303 } else {
304 frameInfo.fileName = sourceFile;
305 }
306 // line number and column number
307 int lineNumber = 0;
308 auto callbackLineFunc = [&frameInfo, &lineNumber](int32_t line) -> bool {
309 lineNumber = line + 1;
310 frameInfo.pos = std::to_string(lineNumber) + ":";
311 return true;
312 };
313 auto callbackColumnFunc = [&frameInfo](int32_t column) -> bool {
314 frameInfo.pos += std::to_string(column + 1);
315 return true;
316 };
317 panda_file::File::EntityId methodId = method->GetMethodId();
318 uint32_t offset = it.GetBytecodeOffset();
319 if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) ||
320 !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) {
321 frameInfo.pos = "?";
322 }
323 jsFrame.push_back(std::move(frameInfo));
324 if (currentStack) {
325 return jsFrame;
326 }
327 } else {
328 JSTaggedValue function = it.GetFunction();
329 JSHandle<JSTaggedValue> extraInfoValue(
330 thread, JSFunction::Cast(function.GetTaggedObject())->GetFunctionExtraInfo());
331 if (extraInfoValue->IsJSNativePointer()) {
332 JSHandle<JSNativePointer> extraInfo(extraInfoValue);
333 native = reinterpret_cast<uintptr_t *>(extraInfo->GetData());
334 }
335 }
336 }
337 return jsFrame;
338 }
339
ReadUintptrFromAddr(int pid,uintptr_t addr,uintptr_t & value,bool needCheckRegion)340 bool ReadUintptrFromAddr(int pid, uintptr_t addr, uintptr_t &value, bool needCheckRegion)
341 {
342 if (pid == getpid()) {
343 if (needCheckRegion) {
344 bool flag = false;
345 auto callback = [addr, &flag](Region *region) {
346 uintptr_t regionBegin = region->GetBegin();
347 uintptr_t regionEnd = region->GetEnd();
348 if (regionBegin <= addr && addr <= regionEnd) {
349 flag = true;
350 }
351 };
352 if (JsStackInfo::loader != nullptr) {
353 const Heap *heap = JsStackInfo::loader->GetHeap();
354 if (heap != nullptr) {
355 heap->EnumerateRegions(callback);
356 }
357 }
358 if (!flag) {
359 LOG_ECMA(ERROR) << "addr not in Region, addr: " << addr;
360 return false;
361 }
362 }
363 value = *(reinterpret_cast<uintptr_t *>(addr));
364 return true;
365 }
366 long *retAddr = reinterpret_cast<long *>(&value);
367 // note: big endian
368 for (size_t i = 0; i < sizeof(uintptr_t) / sizeof(long); i++) {
369 *retAddr = PtracePeektext(pid, addr);
370 if (*retAddr == -1) {
371 LOG_ECMA(ERROR) << "ReadFromAddr ERROR, addr: " << addr;
372 return false;
373 }
374 addr += sizeof(long);
375 retAddr++;
376 }
377 return true;
378 }
379
GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType,uintptr_t & typeOffset,uintptr_t & prevOffset)380 bool GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType, uintptr_t &typeOffset, uintptr_t &prevOffset)
381 {
382 FrameType type = static_cast<FrameType>(frameType);
383 switch (type) {
384 case FrameType::OPTIMIZED_FRAME:
385 typeOffset = OptimizedFrame::GetTypeOffset();
386 prevOffset = OptimizedFrame::GetPrevOffset();
387 break;
388 case FrameType::OPTIMIZED_ENTRY_FRAME:
389 typeOffset = OptimizedEntryFrame::GetTypeOffset();
390 prevOffset = OptimizedEntryFrame::GetLeaveFrameFpOffset();
391 break;
392 case FrameType::BASELINE_BUILTIN_FRAME:
393 typeOffset = BaselineBuiltinFrame::GetTypeOffset();
394 prevOffset = BaselineBuiltinFrame::GetPrevOffset();
395 break;
396 case FrameType::ASM_BRIDGE_FRAME:
397 typeOffset = AsmBridgeFrame::GetTypeOffset();
398 prevOffset = AsmBridgeFrame::GetPrevOffset();
399 break;
400 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
401 typeOffset = OptimizedJSFunctionUnfoldArgVFrame::GetTypeOffset();
402 prevOffset = OptimizedJSFunctionUnfoldArgVFrame::GetPrevOffset();
403 break;
404 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
405 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
406 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME:
407 typeOffset = OptimizedJSFunctionFrame::GetTypeOffset();
408 prevOffset = OptimizedJSFunctionFrame::GetPrevOffset();
409 break;
410 case FrameType::LEAVE_FRAME:
411 typeOffset = OptimizedLeaveFrame::GetTypeOffset();
412 prevOffset = OptimizedLeaveFrame::GetPrevOffset();
413 break;
414 case FrameType::LEAVE_FRAME_WITH_ARGV:
415 typeOffset = OptimizedWithArgvLeaveFrame::GetTypeOffset();
416 prevOffset = OptimizedWithArgvLeaveFrame::GetPrevOffset();
417 break;
418 case FrameType::BUILTIN_CALL_LEAVE_FRAME:
419 typeOffset = OptimizedBuiltinLeaveFrame::GetTypeOffset();
420 prevOffset = OptimizedBuiltinLeaveFrame::GetPrevOffset();
421 break;
422 case FrameType::INTERPRETER_FRAME:
423 case FrameType::INTERPRETER_FAST_NEW_FRAME:
424 typeOffset = InterpretedFrame::GetTypeOffset();
425 prevOffset = InterpretedFrame::GetPrevOffset();
426 break;
427 case FrameType::INTERPRETER_BUILTIN_FRAME:
428 typeOffset = InterpretedBuiltinFrame::GetTypeOffset();
429 prevOffset = InterpretedBuiltinFrame::GetPrevOffset();
430 break;
431 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME:
432 case FrameType::ASM_INTERPRETER_FRAME:
433 typeOffset = AsmInterpretedFrame::GetTypeOffset();
434 prevOffset = AsmInterpretedFrame::GetPrevOffset();
435 break;
436 case FrameType::BUILTIN_FRAME:
437 case FrameType::BUILTIN_ENTRY_FRAME:
438 typeOffset = BuiltinFrame::GetTypeOffset();
439 prevOffset = BuiltinFrame::GetPrevOffset();
440 break;
441 case FrameType::BUILTIN_FRAME_WITH_ARGV:
442 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME:
443 typeOffset = BuiltinWithArgvFrame::GetTypeOffset();
444 prevOffset = BuiltinWithArgvFrame::GetPrevOffset();
445 break;
446 case FrameType::INTERPRETER_ENTRY_FRAME:
447 typeOffset = InterpretedEntryFrame::GetTypeOffset();
448 prevOffset = InterpretedEntryFrame::GetPrevOffset();
449 break;
450 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
451 typeOffset = AsmInterpretedEntryFrame::GetTypeOffset();
452 prevOffset = AsmInterpretedEntryFrame::GetPrevOffset();
453 break;
454 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
455 typeOffset = AsmInterpretedBridgeFrame::GetTypeOffset();
456 prevOffset = AsmInterpretedBridgeFrame::GetPrevOffset();
457 break;
458 case FrameType::FASTJIT_FUNCTION_FRAME:
459 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME:
460 typeOffset = FASTJITFunctionFrame::GetTypeOffset();
461 prevOffset = FASTJITFunctionFrame::GetPrevOffset();
462 break;
463 default:
464 return false;
465 }
466 return true;
467 }
468
ArkFrameCheck(uintptr_t frameType)469 bool ArkFrameCheck(uintptr_t frameType)
470 {
471 return static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_ENTRY_FRAME ||
472 static_cast<FrameType>(frameType) == FrameType::ASM_INTERPRETER_ENTRY_FRAME;
473 }
474
IsFunctionFrame(uintptr_t frameType)475 bool IsFunctionFrame(uintptr_t frameType)
476 {
477 return static_cast<FrameType>(frameType) == FrameType::ASM_INTERPRETER_FRAME ||
478 static_cast<FrameType>(frameType) == FrameType::INTERPRETER_CONSTRUCTOR_FRAME ||
479 static_cast<FrameType>(frameType) == FrameType::INTERPRETER_FRAME ||
480 static_cast<FrameType>(frameType) == FrameType::INTERPRETER_FAST_NEW_FRAME ||
481 static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_JS_FUNCTION_FRAME ||
482 static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME ||
483 static_cast<FrameType>(frameType) == FrameType::FASTJIT_FUNCTION_FRAME ||
484 static_cast<FrameType>(frameType) == FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME;
485 }
486
ReadMethodInfo(panda_file::MethodDataAccessor & mda)487 std::optional<MethodInfo> JSStackTrace::ReadMethodInfo(panda_file::MethodDataAccessor &mda)
488 {
489 uintptr_t methodId = mda.GetMethodId().GetOffset();
490 auto codeId = mda.GetCodeId();
491 if (!codeId) {
492 return std::nullopt;
493 }
494 panda_file::CodeDataAccessor cda(mda.GetPandaFile(), codeId.value());
495 uint32_t codeSize = cda.GetCodeSize();
496 uintptr_t codeBegin = reinterpret_cast<uintptr_t>(cda.GetInstructions());
497 return std::make_optional<MethodInfo>(methodId, codeBegin, codeSize);
498 }
499
ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaFile)500 CVector<MethodInfo> JSStackTrace::ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaFile)
501 {
502 CVector<MethodInfo> result;
503 if (jsPandaFile == nullptr) {
504 LOG_ECMA(ERROR) << "Read all methods info in file failed, file is nullptr.";
505 return result;
506 }
507 const panda_file::File *pf = jsPandaFile->GetPandaFile();
508 Span<const uint32_t> classIndexes = jsPandaFile->GetClasses();
509 for (const uint32_t index : classIndexes) {
510 panda_file::File::EntityId classId(index);
511 if (jsPandaFile->IsExternal(classId)) {
512 continue;
513 }
514 panda_file::ClassDataAccessor cda(*pf, classId);
515 cda.EnumerateMethods([&result, jsPandaFile](panda_file::MethodDataAccessor &mda) {
516 auto info = JSStackTrace::ReadMethodInfo(mda);
517 if (!info) {
518 return;
519 }
520 result.push_back(info.value());
521 });
522 }
523
524 std::sort(result.begin(), result.end());
525 return result;
526 }
527
TranslateByteCodePc(uintptr_t realPc,const CVector<MethodInfo> & vec)528 std::optional<CodeInfo> JSStackTrace::TranslateByteCodePc(uintptr_t realPc, const CVector<MethodInfo> &vec)
529 {
530 int32_t left = 0;
531 ASSERT(vec.size() > 0);
532 int32_t right = static_cast<int32_t>(vec.size()) - 1;
533 for (; left <= right;) {
534 int32_t mid = (left + right) / 2;
535 bool isRight = realPc >= (vec[mid].codeBegin + vec[mid].codeSize);
536 bool isLeft = realPc < vec[mid].codeBegin;
537 // codeBegin <= realPc < codeBegin + codeSize
538 if (!isRight && !isLeft) {
539 return std::make_optional<CodeInfo>(realPc - vec[mid].codeBegin, vec[mid].methodId, vec[mid].codeSize);
540 } else if (isRight) {
541 left = mid + 1;
542 } else {
543 right = mid -1;
544 }
545 }
546 return std::nullopt;
547 }
548
SaveFuncName(EntityId entityId,const std::string & name)549 void SaveFuncName(EntityId entityId, const std::string &name)
550 {
551 size_t length = 256; // maximum stack length
552 if (JsStackInfo::nameMap.size() > length) {
553 auto it = JsStackInfo::nameMap.begin();
554 JsStackInfo::nameMap.erase(it);
555 }
556 JsStackInfo::nameMap.emplace(entityId, name);
557 }
558
559 template<typename T>
ParseJsFrameInfo(JSPandaFile * jsPandaFile,DebugInfoExtractor * debugExtractor,EntityId methodId,uintptr_t offset,T & jsFrame,SourceMap * sourceMap=nullptr)560 void ParseJsFrameInfo(JSPandaFile *jsPandaFile, DebugInfoExtractor *debugExtractor,
561 EntityId methodId, uintptr_t offset, T &jsFrame, SourceMap *sourceMap = nullptr)
562 {
563 if (jsPandaFile == nullptr) {
564 LOG_ECMA(ERROR) << "Parse jsFrame info failed, jsPandaFile is nullptr.";
565 return;
566 }
567 std::string name = MethodLiteral::ParseFunctionName(jsPandaFile, methodId);
568 name = name.empty() ? "anonymous" : name;
569 SaveFuncName(methodId, name);
570 std::string url = debugExtractor->GetSourceFile(methodId);
571
572 // line number and column number
573 int lineNumber = 0;
574 int columnNumber = 0;
575 auto callbackLineFunc = [&lineNumber](int32_t line) -> bool {
576 lineNumber = line + 1;
577 return true;
578 };
579 auto callbackColumnFunc = [&columnNumber](int32_t column) -> bool {
580 columnNumber = column + 1;
581 return true;
582 };
583
584 if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) ||
585 !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) {
586 lineNumber = 0;
587 columnNumber = 0;
588 }
589
590 if (sourceMap != nullptr) {
591 sourceMap->TranslateUrlPositionBySourceMap(url, lineNumber, columnNumber);
592 }
593
594 size_t urlSize = url.size() + 1;
595 size_t nameSize = name.size() + 1;
596 if (strcpy_s(jsFrame.url, urlSize, url.c_str()) != EOK ||
597 strcpy_s(jsFrame.functionName, nameSize, name.c_str()) != EOK) {
598 LOG_ECMA(FATAL) << "jsFrame strcpy_s failed";
599 UNREACHABLE();
600 }
601 jsFrame.line = lineNumber;
602 jsFrame.column = columnNumber;
603 }
604
ArkParseJsFrameInfo(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,uintptr_t loadOffset,uint8_t * data,uint64_t dataSize,uintptr_t extractorptr,JsFunction * jsFunction)605 bool ArkParseJsFrameInfo(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset,
606 uint8_t *data, uint64_t dataSize, uintptr_t extractorptr, JsFunction *jsFunction)
607 {
608 if (data == nullptr) {
609 LOG_ECMA(ERROR) << "Parse JSframe info failed, buffer is nullptr.";
610 return false;
611 }
612 loadOffset = loadOffset % PageSize();
613 auto extractor = reinterpret_cast<JSSymbolExtractor*>(extractorptr);
614 if (extractor == nullptr) {
615 LOG_ECMA(ERROR) << "Parse JSframe info failed, extractor is nullptr.";
616 return false;
617 }
618 auto jsPandaFile = extractor->GetJSPandaFile(data, dataSize);
619 if (jsPandaFile == nullptr) {
620 LOG_ECMA(ERROR) << "Parse JSframe info failed, panda file is nullptr.";
621 return false;
622 }
623 auto debugExtractor = extractor->GetDebugExtractor();
624 auto methodInfos = extractor->GetMethodInfos();
625 if (methodInfos.empty()) {
626 LOG_ECMA(ERROR) << "Read all method info from JSPandaFile failed, methodInfos is empty.";
627 return false;
628 }
629 uintptr_t realOffset = byteCodePc - mapBase - loadOffset;
630 uintptr_t pfBasePtr = reinterpret_cast<uintptr_t>(jsPandaFile->GetBase());
631 auto codeInfo = JSStackTrace::TranslateByteCodePc(realOffset + pfBasePtr, methodInfos);
632 if (!codeInfo) {
633 LOG_ECMA(ERROR) << std::hex << "Failed to get methodId, pc: " << byteCodePc;
634 return false;
635 }
636 methodId = codeInfo->methodId;
637 auto offset = codeInfo->offset;
638 ParseJsFrameInfo(jsPandaFile, debugExtractor, EntityId(methodId), offset, *jsFunction, extractor->GetSourceMap());
639
640 jsFunction->codeBegin = byteCodePc - offset;
641 jsFunction->codeSize = codeInfo->codeSize;
642 return true;
643 }
644
ArkTranslateJsFrameInfo(uint8_t * data,size_t dataSize,JsFunction * jsFunction)645 bool ArkTranslateJsFrameInfo(uint8_t *data, size_t dataSize, JsFunction *jsFunction)
646 {
647 SourceMap sourceMap;
648 std::string strUrl = jsFunction->url;
649 sourceMap.Init(data, dataSize);
650 bool ret = sourceMap.TranslateUrlPositionBySourceMap(strUrl, jsFunction->line, jsFunction->column);
651 size_t strUrlSize = strUrl.size() + 1;
652 if (strcpy_s(jsFunction->url, strUrlSize, strUrl.c_str()) != EOK) {
653 LOG_FULL(FATAL) << "strcpy_s failed";
654 UNREACHABLE();
655 }
656 return ret;
657 }
658
GetBytecodeOffset(void * ctx,ReadMemFunc readMem,uintptr_t frameType,uintptr_t currentPtr)659 uintptr_t GetBytecodeOffset(void *ctx, ReadMemFunc readMem, uintptr_t frameType, uintptr_t currentPtr)
660 {
661 // currentPtr points to the frametype.
662 uintptr_t bytecodePc = 0;
663 FrameType type = static_cast<FrameType>(frameType);
664 switch (type) {
665 case FrameType::ASM_INTERPRETER_FRAME:
666 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
667 currentPtr -= AsmInterpretedFrame::GetTypeOffset();
668 currentPtr += AsmInterpretedFrame::GetPcOffset(false);
669 readMem(ctx, currentPtr, &bytecodePc);
670 return bytecodePc;
671 }
672 case FrameType::INTERPRETER_FRAME:
673 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
674 currentPtr -= InterpretedFrame::GetTypeOffset();
675 currentPtr += InterpretedFrame::GetPcOffset(false);
676 readMem(ctx, currentPtr, &bytecodePc);
677 return bytecodePc;
678 }
679 // aot get native pc
680 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
681 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
682 currentPtr -= OptimizedJSFunctionFrame::GetTypeOffset();
683 currentPtr += OptimizedJSFunctionFrame::GetReturnAddrOffset();
684 readMem(ctx, currentPtr, &bytecodePc);
685 return bytecodePc;
686 }
687 case FrameType::FASTJIT_FUNCTION_FRAME:
688 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
689 currentPtr -= FASTJITFunctionFrame::GetTypeOffset();
690 readMem(ctx, currentPtr, &bytecodePc);
691 return bytecodePc;
692 }
693 default: {
694 break;
695 }
696 }
697 return 0;
698 }
699
ArkGetFunction(void * ctx,ReadMemFunc readMem,uintptr_t currentPtr,uintptr_t frameType)700 uintptr_t ArkGetFunction(void *ctx, ReadMemFunc readMem, uintptr_t currentPtr, uintptr_t frameType)
701 {
702 FrameType type = static_cast<FrameType>(frameType);
703 uintptr_t funcAddr = currentPtr;
704 switch (type) {
705 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
706 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
707 funcAddr -= OptimizedJSFunctionFrame::GetTypeOffset();
708 funcAddr += OptimizedJSFunctionFrame::GetFunctionOffset();
709 break;
710 }
711 case FrameType::ASM_INTERPRETER_FRAME:
712 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
713 funcAddr -= AsmInterpretedFrame::GetTypeOffset();
714 funcAddr += AsmInterpretedFrame::GetFunctionOffset(false);
715 break;
716 }
717 case FrameType::INTERPRETER_FRAME:
718 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
719 funcAddr -= InterpretedFrame::GetTypeOffset();
720 funcAddr += InterpretedFrame::GetFunctionOffset();
721 break;
722 }
723 case FrameType::FASTJIT_FUNCTION_FRAME:
724 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
725 funcAddr -= FASTJITFunctionFrame::GetTypeOffset();
726 funcAddr += FASTJITFunctionFrame::GetFunctionOffset();
727 break;
728 }
729 default: {
730 return 0;
731 }
732 }
733 uintptr_t function = 0;
734 if (!readMem(ctx, funcAddr, &function)) {
735 return 0;
736 }
737 return function;
738 }
739
ArkCheckIsJSFunctionBaseOrJSProxy(void * ctx,ReadMemFunc readMem,uintptr_t objAddr,bool & isJSFunctionBase)740 bool ArkCheckIsJSFunctionBaseOrJSProxy(void *ctx, ReadMemFunc readMem, uintptr_t objAddr, bool &isJSFunctionBase)
741 {
742 bool isHeapObj = ((objAddr & JSTaggedValue::TAG_HEAPOBJECT_MASK) == 0U);
743 bool isInvalidValue = (objAddr <= JSTaggedValue::INVALID_VALUE_LIMIT);
744 if (isHeapObj && !isInvalidValue) {
745 ASSERT_PRINT(((objAddr & JSTaggedValue::TAG_WEAK) == 0U),
746 "can not convert JSTaggedValue to HeapObject :" << std::hex << objAddr);
747 uintptr_t hclassAddr = objAddr + TaggedObject::HCLASS_OFFSET;
748 uintptr_t hclass = 0;
749 if (!readMem(ctx, hclassAddr, &hclass)) {
750 return false;
751 }
752 if (hclass != 0) {
753 uintptr_t bitsAddr = reinterpret_cast<uintptr_t>(hclass + JSHClass::BIT_FIELD_OFFSET);
754 uintptr_t bits = 0;
755 if (!readMem(ctx, bitsAddr, &bits)) {
756 return false;
757 }
758 JSType jsType = JSHClass::ObjectTypeBits::Decode(bits);
759 isJSFunctionBase = (jsType >= JSType::JS_FUNCTION_BASE && jsType <= JSType::JS_BOUND_FUNCTION);
760 bool isJSProxy = (jsType == JSType::JS_PROXY);
761 return isJSFunctionBase || isJSProxy;
762 }
763 }
764 return false;
765 }
766
ArkCheckAndGetMethod(void * ctx,ReadMemFunc readMem,uintptr_t value)767 uintptr_t ArkCheckAndGetMethod(void *ctx, ReadMemFunc readMem, uintptr_t value)
768 {
769 bool isJSFunctionBase = 0;
770 if (ArkCheckIsJSFunctionBaseOrJSProxy(ctx, readMem, value, isJSFunctionBase)) {
771 if (isJSFunctionBase) {
772 value += JSFunctionBase::METHOD_OFFSET;
773 } else {
774 value += JSProxy::METHOD_OFFSET;
775 }
776 uintptr_t method = 0;
777 if (!readMem(ctx, value, &method)) {
778 return 0;
779 }
780 return method;
781 }
782 return 0;
783 }
784
ArkGetMethodIdFromMethod(void * ctx,ReadMemFunc readMem,uintptr_t method,uintptr_t & methodId)785 bool ArkGetMethodIdFromMethod(void *ctx, ReadMemFunc readMem, uintptr_t method, uintptr_t &methodId)
786 {
787 uintptr_t methodLiteralAddr = method + Method::LITERAL_INFO_OFFSET;
788 uintptr_t methodLiteral = 0;
789 if (!readMem(ctx, methodLiteralAddr, &methodLiteral)) {
790 return false;
791 }
792 methodId = MethodLiteral::MethodIdBits::Decode(methodLiteral);
793 return true;
794 }
795
ArkGetMethodId(void * ctx,ReadMemFunc readMem,uintptr_t frameType,uintptr_t currentPtr,uintptr_t & methodId)796 bool ArkGetMethodId(void *ctx, ReadMemFunc readMem, uintptr_t frameType, uintptr_t currentPtr, uintptr_t &methodId)
797 {
798 uintptr_t function = ArkGetFunction(ctx, readMem, currentPtr, frameType);
799 if (!function) {
800 LOG_ECMA(DEBUG) << "Failed to get function";
801 return false;
802 }
803
804 uintptr_t method = ArkCheckAndGetMethod(ctx, readMem, function);
805 if (!method) {
806 LOG_ECMA(DEBUG) << std::hex << "Failed to get method: " << function;
807 return false;
808 }
809
810 if (!ArkGetMethodIdFromMethod(ctx, readMem, method, methodId)) {
811 LOG_ECMA(DEBUG) << std::hex << "ArkGetJsFrameDebugInfo failed, method: " << method;
812 return false;
813 }
814 return true;
815 }
816
ArkGetNextFrame(void * ctx,ReadMemFunc readMem,uintptr_t & currentPtr,uintptr_t & frameType,uintptr_t & pc,uintptr_t * methodId)817 bool ArkGetNextFrame(void *ctx, ReadMemFunc readMem, uintptr_t ¤tPtr,
818 uintptr_t &frameType, uintptr_t &pc, uintptr_t *methodId)
819 {
820 currentPtr -= sizeof(FrameType);
821 if (!readMem(ctx, currentPtr, &frameType)) {
822 return false;
823 }
824 if (ArkFrameCheck(frameType)) {
825 return true;
826 }
827 bool ret = false;
828 if (IsFunctionFrame(frameType)) {
829 pc = GetBytecodeOffset(ctx, readMem, frameType, currentPtr);
830 ret = true;
831 if (methodId != nullptr) {
832 ret = ArkGetMethodId(ctx, readMem, frameType, currentPtr, *methodId);
833 }
834 }
835
836 uintptr_t typeOffset = 0;
837 uintptr_t prevOffset = 0;
838 if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) {
839 return false;
840 }
841 currentPtr -= typeOffset;
842 currentPtr += prevOffset;
843 if (!readMem(ctx, currentPtr, ¤tPtr)) {
844 return false;
845 }
846
847 if (ret) {
848 return true;
849 }
850 return ArkGetNextFrame(ctx, readMem, currentPtr, frameType, pc, methodId);
851 }
852
ArkGetMethodIdWithJit(ArkUnwindParam * arkUnwindParam,uintptr_t frameType,uintptr_t currentPtr)853 bool ArkGetMethodIdWithJit(ArkUnwindParam *arkUnwindParam, uintptr_t frameType, uintptr_t currentPtr)
854 {
855 uintptr_t function = ArkGetFunction(arkUnwindParam->ctx, arkUnwindParam->readMem, currentPtr, frameType);
856 if (!function) {
857 LOG_ECMA(DEBUG) << "Failed to get function";
858 return false;
859 }
860
861 uintptr_t method = ArkCheckAndGetMethod(arkUnwindParam->ctx, arkUnwindParam->readMem, function);
862 if (!method) {
863 LOG_ECMA(DEBUG) << std::hex << "Failed to get method: " << function;
864 return false;
865 }
866
867 if (!ArkGetMethodIdFromMethod(arkUnwindParam->ctx, arkUnwindParam->readMem, method, *arkUnwindParam->methodId)) {
868 LOG_ECMA(DEBUG) << std::hex << "ArkGetJsFrameDebugInfo failed, method: " << method;
869 return false;
870 }
871
872 if (IsFastJitFunctionFrame(static_cast<FrameType>(frameType))) {
873 uintptr_t machineCode = 0;
874 uintptr_t functionAddr = function + JSFunction::MACHINECODE_OFFSET;
875 arkUnwindParam->readMem(arkUnwindParam->ctx, functionAddr, &machineCode);
876 uintptr_t size = 0;
877 uintptr_t funcAddr = 0;
878 if (machineCode) {
879 arkUnwindParam->readMem(arkUnwindParam->ctx, machineCode + MachineCode::INSTRSIZ_OFFSET, &size);
880 arkUnwindParam->readMem(arkUnwindParam->ctx, machineCode + MachineCode::FUNCADDR_OFFSET, &funcAddr);
881 }
882 if (size && funcAddr) {
883 // take the lower four bytes
884 size &= 0xFFFFFFFF;
885 std::vector<uint8> codeVec;
886 for (size_t l = 0; l < size; l++) {
887 uintptr_t tmp = 0;
888 arkUnwindParam->readMem(arkUnwindParam->ctx, funcAddr + l, &tmp);
889 codeVec.push_back(tmp);
890 }
891 arkUnwindParam->jitCache.push_back(*arkUnwindParam->methodId);
892 JsStackInfo::machineCodeMap[EntityId(*arkUnwindParam->methodId)] = codeVec;
893 }
894 }
895 return true;
896 }
897
ArkGetNextFrameWithJit(ArkUnwindParam * arkUnwindParam,uintptr_t & currentPtr,uintptr_t & frameType)898 bool ArkGetNextFrameWithJit(ArkUnwindParam *arkUnwindParam, uintptr_t ¤tPtr, uintptr_t &frameType)
899 {
900 currentPtr -= sizeof(FrameType);
901 if (!arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, &frameType)) {
902 return false;
903 }
904 if (ArkFrameCheck(frameType)) {
905 return true;
906 }
907 bool ret = false;
908 if (IsFunctionFrame(frameType)) {
909 *arkUnwindParam->pc = GetBytecodeOffset(arkUnwindParam->ctx, arkUnwindParam->readMem, frameType, currentPtr);
910 ret = true;
911 if (arkUnwindParam->methodId != nullptr) {
912 ret = ArkGetMethodIdWithJit(arkUnwindParam, frameType, currentPtr);
913 }
914 }
915
916 uintptr_t typeOffset = 0;
917 uintptr_t prevOffset = 0;
918 if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) {
919 return false;
920 }
921 currentPtr -= typeOffset;
922 currentPtr += prevOffset;
923 if (!arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, ¤tPtr)) {
924 return false;
925 }
926
927 if (ret) {
928 return true;
929 }
930 return ArkGetNextFrameWithJit(arkUnwindParam, currentPtr, frameType);
931 }
932
ArkWriteJitCode(void * ctx,ReadMemFunc readMem,int fd,const uintptr_t * const jitCodeArray,const size_t jitSize)933 bool ArkWriteJitCode([[maybe_unused]] void *ctx, [[maybe_unused]] ReadMemFunc readMem,
934 int fd, const uintptr_t *const jitCodeArray, const size_t jitSize)
935 {
936 JsJitDumpElf jitDumpElf;
937 jitDumpElf.Init();
938 std::set<uintptr_t> memos;
939 int64 idx = 0;
940 size_t offset = 0;
941 for (size_t i = 0; i < jitSize; i++) {
942 uintptr_t methodId = jitCodeArray[i];
943 auto res = memos.insert(methodId);
944 if (res.second) {
945 std::vector<uint8> codeVec = JsStackInfo::machineCodeMap[EntityId(methodId)];
946 std::string name = JsStackInfo::nameMap[EntityId(methodId)];
947 size_t len = codeVec.size();
948 jitDumpElf.AppendData(codeVec);
949 jitDumpElf.AppendSymbolToSymTab(idx++, offset, len, name);
950 offset += len;
951 }
952 }
953 jitDumpElf.WriteJitElfFile(fd);
954 JsStackInfo::nameMap.clear();
955 JsStackInfo::machineCodeMap.clear();
956 return true;
957 }
958
StepArkWithRecordJit(ArkUnwindParam * arkUnwindParam)959 bool StepArkWithRecordJit(ArkUnwindParam *arkUnwindParam)
960 {
961 constexpr size_t FP_SIZE = sizeof(uintptr_t);
962 uintptr_t currentPtr = *arkUnwindParam->fp;
963 if (currentPtr == 0) {
964 LOG_ECMA(ERROR) << "fp is nullptr in StepArkWithRecordJit()!";
965 return false;
966 }
967
968 uintptr_t frameType = 0;
969 if (ArkGetNextFrameWithJit(arkUnwindParam, currentPtr, frameType)) {
970 if (ArkFrameCheck(frameType)) {
971 currentPtr += sizeof(FrameType);
972 *arkUnwindParam->sp = currentPtr;
973 bool ret = arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, arkUnwindParam->fp);
974 currentPtr += FP_SIZE;
975 ret &= arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, arkUnwindParam->pc);
976 *arkUnwindParam->isJsFrame = false;
977 return ret;
978 } else {
979 *arkUnwindParam->fp = currentPtr;
980 *arkUnwindParam->sp = currentPtr;
981 *arkUnwindParam->isJsFrame = true;
982 }
983 } else {
984 LOG_ECMA(ERROR) << "ArkGetNextFrame failed, currentPtr: " << currentPtr << ", frameType: " << frameType;
985 return false;
986 }
987 return true;
988 }
989
StepArk(void * ctx,ReadMemFunc readMem,uintptr_t * fp,uintptr_t * sp,uintptr_t * pc,uintptr_t * methodId,bool * isJsFrame)990 bool StepArk(void *ctx, ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp,
991 uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame)
992 {
993 constexpr size_t FP_SIZE = sizeof(uintptr_t);
994 uintptr_t currentPtr = *fp;
995 if (currentPtr == 0) {
996 LOG_ECMA(ERROR) << "fp is nullptr in StepArk()!";
997 return false;
998 }
999
1000 uintptr_t frameType = 0;
1001 if (ArkGetNextFrame(ctx, readMem, currentPtr, frameType, *pc, methodId)) {
1002 if (ArkFrameCheck(frameType)) {
1003 currentPtr += sizeof(FrameType);
1004 *sp = currentPtr;
1005 bool ret = readMem(ctx, currentPtr, fp);
1006 currentPtr += FP_SIZE;
1007 ret &= readMem(ctx, currentPtr, pc);
1008 *isJsFrame = false;
1009 return ret;
1010 } else {
1011 *fp = currentPtr;
1012 *sp = currentPtr;
1013 *isJsFrame = true;
1014 }
1015 } else {
1016 LOG_ECMA(ERROR) << std::hex << "ArkGetNextFrame failed, addr: " << currentPtr;
1017 return false;
1018 }
1019
1020 return true;
1021 }
1022
ArkGetFunction(int pid,uintptr_t currentPtr,uintptr_t frameType)1023 uintptr_t ArkGetFunction(int pid, uintptr_t currentPtr, uintptr_t frameType)
1024 {
1025 FrameType type = static_cast<FrameType>(frameType);
1026 uintptr_t funcAddr = currentPtr;
1027 switch (type) {
1028 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
1029 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
1030 funcAddr -= OptimizedJSFunctionFrame::GetTypeOffset();
1031 funcAddr += OptimizedJSFunctionFrame::GetFunctionOffset();
1032 break;
1033 }
1034 case FrameType::ASM_INTERPRETER_FRAME:
1035 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
1036 funcAddr -= AsmInterpretedFrame::GetTypeOffset();
1037 funcAddr += AsmInterpretedFrame::GetFunctionOffset(false);
1038 break;
1039 }
1040 case FrameType::INTERPRETER_FRAME:
1041 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
1042 funcAddr -= InterpretedFrame::GetTypeOffset();
1043 funcAddr += InterpretedFrame::GetFunctionOffset();
1044 break;
1045 }
1046 case FrameType::INTERPRETER_BUILTIN_FRAME: {
1047 funcAddr -= InterpretedBuiltinFrame::GetTypeOffset();
1048 funcAddr += InterpretedBuiltinFrame::GetFunctionOffset();
1049 break;
1050 }
1051 case FrameType::BUILTIN_FRAME_WITH_ARGV: {
1052 funcAddr += sizeof(FrameType);
1053 auto topAddress = funcAddr +
1054 (static_cast<int>(BuiltinWithArgvFrame::Index::StackArgsTopIndex) * sizeof(uintptr_t));
1055 uintptr_t argcAddress = static_cast<uintptr_t>(funcAddr + (static_cast<int>
1056 (BuiltinWithArgvFrame::Index::NumArgsIndex) * sizeof(uintptr_t)));
1057 if (!ReadUintptrFromAddr(pid, argcAddress, argcAddress, g_needCheck)) {
1058 return 0;
1059 }
1060 auto numberArgs = argcAddress + NUM_MANDATORY_JSFUNC_ARGS;
1061 funcAddr = topAddress - static_cast<uint32_t>(numberArgs) * sizeof(uintptr_t);
1062 break;
1063 }
1064 case FrameType::BUILTIN_ENTRY_FRAME:
1065 case FrameType::BUILTIN_FRAME: {
1066 funcAddr -= BuiltinFrame::GetTypeOffset();
1067 funcAddr += BuiltinFrame::GetStackArgsOffset();
1068 break;
1069 }
1070 case FrameType::BUILTIN_CALL_LEAVE_FRAME: {
1071 funcAddr -= OptimizedBuiltinLeaveFrame::GetTypeOffset();
1072 funcAddr += OptimizedBuiltinLeaveFrame::GetFunctionOffset();
1073 break;
1074 }
1075 case FrameType::FASTJIT_FUNCTION_FRAME:
1076 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
1077 funcAddr -= FASTJITFunctionFrame::GetTypeOffset();
1078 funcAddr += FASTJITFunctionFrame::GetFunctionOffset();
1079 break;
1080 }
1081 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME :
1082 case FrameType::OPTIMIZED_FRAME:
1083 case FrameType::OPTIMIZED_ENTRY_FRAME:
1084 case FrameType::ASM_BRIDGE_FRAME:
1085 case FrameType::LEAVE_FRAME:
1086 case FrameType::LEAVE_FRAME_WITH_ARGV:
1087 case FrameType::INTERPRETER_ENTRY_FRAME:
1088 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
1089 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
1090 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
1091 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME: {
1092 return 0;
1093 }
1094 default: {
1095 LOG_FULL(FATAL) << "Unknown frame type: " << static_cast<uintptr_t>(type);
1096 UNREACHABLE();
1097 }
1098 }
1099 uintptr_t function = 0;
1100 if (!ReadUintptrFromAddr(pid, funcAddr, function, g_needCheck)) {
1101 return 0;
1102 }
1103 return function;
1104 }
1105
ArkCheckIsJSFunctionBaseOrJSProxy(int pid,uintptr_t objAddr,bool & isJSFunctionBase)1106 bool ArkCheckIsJSFunctionBaseOrJSProxy(int pid, uintptr_t objAddr, bool &isJSFunctionBase)
1107 {
1108 bool isHeapObj = ((objAddr & JSTaggedValue::TAG_HEAPOBJECT_MASK) == 0U);
1109 bool isInvalidValue = (objAddr <= JSTaggedValue::INVALID_VALUE_LIMIT);
1110 if (isHeapObj && !isInvalidValue) {
1111 ASSERT_PRINT(((objAddr & JSTaggedValue::TAG_WEAK) == 0U),
1112 "can not convert JSTaggedValue to HeapObject :" << std::hex << objAddr);
1113 uintptr_t hclassAddr = objAddr + TaggedObject::HCLASS_OFFSET;
1114 uintptr_t hclass = 0;
1115 if (!ReadUintptrFromAddr(pid, hclassAddr, hclass, g_needCheck)) {
1116 return false;
1117 }
1118 if (hclass != 0) {
1119 uintptr_t bitsAddr = reinterpret_cast<uintptr_t>(hclass + JSHClass::BIT_FIELD_OFFSET);
1120 uintptr_t bits = 0;
1121 if (!ReadUintptrFromAddr(pid, bitsAddr, bits, g_needCheck)) {
1122 return false;
1123 }
1124 JSType jsType = JSHClass::ObjectTypeBits::Decode(bits);
1125 isJSFunctionBase = (jsType >= JSType::JS_FUNCTION_BASE && jsType <= JSType::JS_BOUND_FUNCTION);
1126 bool isJSProxy = (jsType == JSType::JS_PROXY);
1127 return isJSFunctionBase || isJSProxy;
1128 }
1129 }
1130 return false;
1131 }
1132
ArkCheckAndGetMethod(int pid,uintptr_t value)1133 uintptr_t ArkCheckAndGetMethod(int pid, uintptr_t value)
1134 {
1135 bool isJSFunctionBase = 0;
1136 if (ArkCheckIsJSFunctionBaseOrJSProxy(pid, value, isJSFunctionBase)) {
1137 if (isJSFunctionBase) {
1138 value += JSFunctionBase::METHOD_OFFSET;
1139 } else {
1140 value += JSProxy::METHOD_OFFSET;
1141 }
1142 uintptr_t method = 0;
1143 if (!ReadUintptrFromAddr(pid, value, method, g_needCheck)) {
1144 return 0;
1145 }
1146 return method;
1147 }
1148 return 0;
1149 }
1150
ArkGetMethodIdandJSPandaFileAddr(int pid,uintptr_t method,uintptr_t & methodId,uintptr_t & jsPandaFileAddr)1151 bool ArkGetMethodIdandJSPandaFileAddr(int pid, uintptr_t method, uintptr_t &methodId, uintptr_t &jsPandaFileAddr)
1152 {
1153 uintptr_t methodLiteralAddr = method + Method::LITERAL_INFO_OFFSET;
1154 uintptr_t methodLiteral = 0;
1155 if (!ReadUintptrFromAddr(pid, methodLiteralAddr, methodLiteral, g_needCheck)) {
1156 return false;
1157 }
1158 methodId = MethodLiteral::MethodIdBits::Decode(methodLiteral);
1159 uintptr_t constantpoolAddr = method + Method::CONSTANT_POOL_OFFSET;
1160 uintptr_t constantpool = 0;
1161 if (!ReadUintptrFromAddr(pid, constantpoolAddr, constantpool, g_needCheck)) {
1162 return false;
1163 }
1164 if (constantpool == JSTaggedValue::VALUE_UNDEFINED) {
1165 return false;
1166 }
1167 uintptr_t lengthAddr = constantpool + TaggedArray::LENGTH_OFFSET;
1168 uintptr_t length = 0;
1169 if (!ReadUintptrFromAddr(pid, lengthAddr, length, g_needCheck)) {
1170 return false;
1171 }
1172 jsPandaFileAddr = constantpool + TaggedArray::DATA_OFFSET +
1173 JSTaggedValue::TaggedTypeSize() * (length - ConstantPool::JS_PANDA_FILE_INDEX);
1174 if (!ReadUintptrFromAddr(pid, jsPandaFileAddr, jsPandaFileAddr, g_needCheck)) {
1175 return false;
1176 }
1177 return true;
1178 }
1179
ArkGetOffsetFromMethod(int pid,uintptr_t currentPtr,uintptr_t method)1180 uint32_t ArkGetOffsetFromMethod(int pid, uintptr_t currentPtr, uintptr_t method)
1181 {
1182 uintptr_t pc = 0;
1183 if (!ReadUintptrFromAddr(pid, currentPtr, pc, g_needCheck)) {
1184 return 0;
1185 }
1186 uintptr_t byteCodeArrayAddr = method + Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET;
1187 uintptr_t byteCodeArray = 0;
1188 if (!ReadUintptrFromAddr(pid, byteCodeArrayAddr, byteCodeArray, g_needCheck)) {
1189 return 0;
1190 }
1191 uintptr_t offset = pc - byteCodeArray;
1192 return static_cast<uint32_t>(offset);
1193 }
1194
ArkGetBytecodeOffset(int pid,uintptr_t method,uintptr_t frameType,uintptr_t currentPtr)1195 uint32_t ArkGetBytecodeOffset(int pid, uintptr_t method, uintptr_t frameType, uintptr_t currentPtr)
1196 {
1197 FrameType type = static_cast<FrameType>(frameType);
1198 switch (type) {
1199 case FrameType::ASM_INTERPRETER_FRAME:
1200 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
1201 currentPtr -= AsmInterpretedFrame::GetTypeOffset();
1202 currentPtr += AsmInterpretedFrame::GetPcOffset(false);
1203 return ArkGetOffsetFromMethod(pid, currentPtr, method);
1204 }
1205 case FrameType::INTERPRETER_FRAME:
1206 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
1207 currentPtr -= InterpretedFrame::GetTypeOffset();
1208 currentPtr += InterpretedFrame::GetPcOffset(false);
1209 return ArkGetOffsetFromMethod(pid, currentPtr, method);
1210 }
1211 // aot need stackmaps
1212 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
1213 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME:
1214 case FrameType::FASTJIT_FUNCTION_FRAME:
1215 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
1216 break;
1217 }
1218 default: {
1219 break;
1220 }
1221 }
1222 return 0;
1223 }
1224
ArkGetFilePath(std::string & fileName)1225 std::string ArkGetFilePath(std::string &fileName)
1226 {
1227 auto lastSlash = fileName.rfind("/");
1228 if (lastSlash == std::string::npos) {
1229 LOG_ECMA(ERROR) << "ArkGetFilePath can't find fisrt /: " << fileName;
1230 return "";
1231 }
1232 if (lastSlash == 0) {
1233 LOG_ECMA(ERROR) << "ArkGetFilePath can't find second /: " << fileName;
1234 return "";
1235 }
1236
1237 auto secondLastSlash = fileName.rfind("/", lastSlash - 1);
1238 if (secondLastSlash == std::string::npos) {
1239 LOG_ECMA(ERROR) << "ArkGetFilePath can't find second /: " << fileName;
1240 return "";
1241 }
1242
1243 std::string mapPath = fileName.substr(secondLastSlash + 1);
1244 return mapPath;
1245 }
1246
ArkIsNativeWithCallField(int pid,uintptr_t method)1247 bool ArkIsNativeWithCallField(int pid, uintptr_t method)
1248 {
1249 uintptr_t callFieldAddr = method + Method::CALL_FIELD_OFFSET;
1250 uintptr_t callField = 0;
1251 if (!ReadUintptrFromAddr(pid, callFieldAddr, callField, g_needCheck)) {
1252 return true;
1253 }
1254 return Method::IsNativeBit::Decode(callField);
1255 }
1256
ArkReadCStringFromAddr(int pid,uintptr_t descAddr)1257 std::string ArkReadCStringFromAddr(int pid, uintptr_t descAddr)
1258 {
1259 std::string name;
1260 bool key = true;
1261 while (key) {
1262 uintptr_t desc = 0;
1263 if (!ReadUintptrFromAddr(pid, descAddr, desc, g_needCheck)) {
1264 LOG_ECMA(ERROR) << "ArkReadCStringFromAddr failed, descAddr: " << descAddr;
1265 return name;
1266 }
1267 size_t shiftAmount = 8;
1268 for (size_t i = 0; i < sizeof(long); i++) {
1269 char bottomEightBits = static_cast<char>(desc);
1270 desc = desc >> shiftAmount;
1271 if (!bottomEightBits) {
1272 key = false;
1273 break;
1274 }
1275 name += bottomEightBits;
1276 }
1277 if (!key) {
1278 break;
1279 }
1280 descAddr += sizeof(long);
1281 }
1282 return name;
1283 }
1284
ArkGetFileName(int pid,uintptr_t jsPandaFileAddr,std::string & hapPath)1285 std::string ArkGetFileName(int pid, uintptr_t jsPandaFileAddr, std::string &hapPath)
1286 {
1287 size_t size = sizeof(JSPandaFile) / sizeof(long);
1288 uintptr_t *jsPandaFilePart = new uintptr_t[size]();
1289 if (jsPandaFilePart == nullptr) {
1290 LOG_ECMA(FATAL) << "ArkGetFileName:jsPandaFilePart is nullptr";
1291 }
1292 for (size_t i = 0; i < size; i++) {
1293 if (!ReadUintptrFromAddr(pid, jsPandaFileAddr, jsPandaFilePart[i], g_needCheck)) {
1294 LOG_ECMA(ERROR) << "ArkGetFilePath failed, jsPandaFileAddr: " << jsPandaFileAddr;
1295 delete []jsPandaFilePart;
1296 return "";
1297 }
1298 jsPandaFileAddr += sizeof(long);
1299 }
1300 JSPandaFile *jsPandaFile = reinterpret_cast<JSPandaFile *>(jsPandaFilePart);
1301
1302 uintptr_t hapPathAddr = reinterpret_cast<uintptr_t>(
1303 const_cast<char *>(jsPandaFile->GetJSPandaFileHapPath().c_str()));
1304 hapPath = ArkReadCStringFromAddr(pid, hapPathAddr);
1305
1306 uintptr_t descAddr = reinterpret_cast<uintptr_t>(
1307 const_cast<char *>(jsPandaFile->GetJSPandaFileDesc().c_str()));
1308 delete []jsPandaFilePart;
1309 return ArkReadCStringFromAddr(pid, descAddr);
1310 }
1311
ArkReadData(const std::string & hapPath,const std::string & fileName,size_t & dataSize)1312 std::unique_ptr<uint8_t[]> ArkReadData([[maybe_unused]] const std::string &hapPath,
1313 [[maybe_unused]] const std::string &fileName,
1314 [[maybe_unused]] size_t &dataSize)
1315 {
1316 std::unique_ptr<uint8_t[]> dataPtr = nullptr;
1317 #if defined(PANDA_TARGET_OHOS)
1318 bool newCreate = false;
1319 std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(
1320 ExtractorUtil::GetLoadFilePath(hapPath), newCreate);
1321 if (extractor == nullptr) {
1322 LOG_ECMA(ERROR) << "Ark read data failed, hapPath: " << hapPath;
1323 return dataPtr;
1324 }
1325 if (!extractor->ExtractToBufByName(fileName, dataPtr, dataSize)) {
1326 LOG_ECMA(ERROR) << "Ark read data failed, hap/hsp path: " << hapPath << ", file name: " << fileName;
1327 return dataPtr;
1328 }
1329 #endif
1330 return dataPtr;
1331 }
1332
OpenJSPandaFileByReadData(const std::string & hapPath,const std::string & fileName)1333 std::shared_ptr<JSPandaFile> OpenJSPandaFileByReadData(const std::string &hapPath, const std::string &fileName)
1334 {
1335 size_t dataSize = 0;
1336 auto data = ArkReadData(hapPath, fileName, dataSize);
1337 if (data == nullptr) {
1338 return nullptr;
1339 }
1340 auto pf = panda_file::OpenPandaFileFromMemory(data.get(), dataSize);
1341 if (pf == nullptr) {
1342 return nullptr;
1343 }
1344 return std::make_shared<JSPandaFile>(pf.release(), fileName.c_str());
1345 }
1346
ArkParseJsFrameDebugInfos(const std::vector<JsFrameDebugInfo> & JsFrameDebugInfos,size_t size,JsFrame * jsFrame,size_t & jsFrameIndex)1347 void ArkParseJsFrameDebugInfos([[maybe_unused]] const std::vector<JsFrameDebugInfo> &JsFrameDebugInfos,
1348 [[maybe_unused]] size_t size, [[maybe_unused]] JsFrame *jsFrame,
1349 [[maybe_unused]] size_t &jsFrameIndex)
1350 {
1351 #if defined(PANDA_TARGET_OHOS)
1352 jsFrameIndex = 0;
1353 size = JsFrameDebugInfos.size() > size ? size : JsFrameDebugInfos.size();
1354 std::unordered_map<std::string, std::shared_ptr<JSPandaFile>> jsPandaFileTable;
1355 for (size_t i = 0; i < size; ++i) {
1356 auto fileIter = jsPandaFileTable.find(JsFrameDebugInfos[i].hapPath);
1357 if (fileIter == jsPandaFileTable.end()) {
1358 auto jsPandaFile = OpenJSPandaFileByReadData(JsFrameDebugInfos[i].hapPath, JsFrameDebugInfos[i].filePath);
1359 if (jsPandaFile != nullptr) {
1360 jsPandaFileTable.emplace(JsFrameDebugInfos[i].hapPath, jsPandaFile);
1361 auto debugExtractor = std::make_unique<DebugInfoExtractor>(jsPandaFile.get());
1362 ParseJsFrameInfo(jsPandaFile.get(), debugExtractor.get(), JsFrameDebugInfos[i].methodId,
1363 JsFrameDebugInfos[i].offset, jsFrame[jsFrameIndex]);
1364 jsFrameIndex++;
1365 }
1366 } else {
1367 auto jsPandaFile = fileIter->second;
1368 auto debugExtractor = std::make_unique<DebugInfoExtractor>(jsPandaFile.get());
1369 ParseJsFrameInfo(jsPandaFile.get(), debugExtractor.get(), JsFrameDebugInfos[i].methodId,
1370 JsFrameDebugInfos[i].offset, jsFrame[jsFrameIndex]);
1371 jsFrameIndex++;
1372 }
1373 }
1374 #endif
1375 }
1376
ArkGetJsFrameDebugInfo(int pid,uintptr_t currentPtr,uintptr_t frameType,std::vector<JsFrameDebugInfo> & JsFrameDebugInfos)1377 bool ArkGetJsFrameDebugInfo(int pid, uintptr_t currentPtr, uintptr_t frameType,
1378 std::vector<JsFrameDebugInfo> &JsFrameDebugInfos)
1379 {
1380 uintptr_t function = ArkGetFunction(pid, currentPtr, frameType);
1381 if (!function) {
1382 return false;
1383 }
1384
1385 uintptr_t method = ArkCheckAndGetMethod(pid, function);
1386 if (!method || ArkIsNativeWithCallField(pid, method)) {
1387 return false;
1388 }
1389 uintptr_t jsPandaFileAddr = 0;
1390 uintptr_t methodId = 0;
1391 if (!ArkGetMethodIdandJSPandaFileAddr(pid, method, methodId, jsPandaFileAddr)) {
1392 LOG_ECMA(ERROR) << "ArkGetJsFrameDebugInfo failed, method: " << method;
1393 return false;
1394 }
1395 uintptr_t offset = ArkGetBytecodeOffset(pid, method, frameType, currentPtr);
1396 std::string hapPath;
1397 std::string fileName = ArkGetFileName(pid, jsPandaFileAddr, hapPath);
1398 if (fileName.empty() || hapPath.empty()) {
1399 LOG_ECMA(DEBUG) << "ArkGetJsFrameDebugInfo get filename or hapPath failed, fileName: "
1400 << fileName << ", hapPath: "<< hapPath;
1401 return false;
1402 }
1403 std::string filePath = ArkGetFilePath(fileName);
1404 if (filePath.empty()) {
1405 return false;
1406 }
1407 JsFrameDebugInfo JsFrameDebugInfo(EntityId(methodId), offset, hapPath, filePath);
1408 JsFrameDebugInfos.push_back(std::move(JsFrameDebugInfo));
1409 return true;
1410 }
1411
ArkGetNextFrame(int pid,uintptr_t frameType,uintptr_t & currentPtr)1412 bool ArkGetNextFrame(int pid, uintptr_t frameType, uintptr_t ¤tPtr)
1413 {
1414 uintptr_t typeOffset = 0;
1415 uintptr_t prevOffset = 0;
1416 if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) {
1417 LOG_ECMA(ERROR) << "FrameType ERROR, addr: " << currentPtr << ", frameType: " << frameType;
1418 return false;
1419 }
1420 currentPtr -= typeOffset;
1421 currentPtr += prevOffset;
1422 if (!ReadUintptrFromAddr(pid, currentPtr, currentPtr, g_needCheck)) {
1423 return false;
1424 }
1425 if (currentPtr == 0) {
1426 LOG_ECMA(ERROR) << "currentPtr is nullptr in GetArkNativeFrameInfo()!";
1427 return false;
1428 }
1429 return true;
1430 }
1431
GetArkNativeFrameInfo(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,JsFrame * jsFrame,size_t & size)1432 bool GetArkNativeFrameInfo([[maybe_unused]] int pid, [[maybe_unused]] uintptr_t *pc,
1433 [[maybe_unused]] uintptr_t *fp, [[maybe_unused]] uintptr_t *sp,
1434 [[maybe_unused]] JsFrame *jsFrame, [[maybe_unused]] size_t &size)
1435 {
1436 #if defined(PANDA_TARGET_OHOS)
1437 constexpr size_t FP_SIZE = sizeof(uintptr_t);
1438 uintptr_t currentPtr = *fp;
1439 if (pid == getpid()) {
1440 g_needCheck = false;
1441 }
1442 if (currentPtr == 0) {
1443 LOG_ECMA(ERROR) << "fp is nullptr in GetArkNativeFrameInfo()!";
1444 return false;
1445 }
1446
1447 if (pid == getpid() && JsStackInfo::loader != nullptr &&
1448 !JsStackInfo::loader->InsideStub(*pc) && !JsStackInfo::loader->InsideAOT(*pc)) {
1449 LOG_ECMA(ERROR) << "invalid pc in StepArkManagedNativeFrame()!";
1450 return false;
1451 }
1452
1453 std::vector<JsFrameDebugInfo> JsFrameDebugInfos;
1454 bool ret = true;
1455 while (true) {
1456 currentPtr -= sizeof(FrameType);
1457 uintptr_t frameType = 0;
1458 if (!ReadUintptrFromAddr(pid, currentPtr, frameType, g_needCheck)) {
1459 return false;
1460 }
1461 if (g_needCheck && IsFunctionFrame(frameType)) {
1462 ArkGetJsFrameDebugInfo(pid, currentPtr, frameType, JsFrameDebugInfos);
1463 } else if (ArkFrameCheck(frameType)) {
1464 currentPtr += sizeof(FrameType);
1465 *sp = currentPtr;
1466 ret &= ReadUintptrFromAddr(pid, currentPtr, *fp, g_needCheck);
1467 currentPtr += FP_SIZE;
1468 ret &= ReadUintptrFromAddr(pid, currentPtr, *pc, g_needCheck);
1469 break;
1470 }
1471
1472 if (!ArkGetNextFrame(pid, frameType, currentPtr)) {
1473 return false;
1474 }
1475 }
1476 if (g_needCheck && !JsFrameDebugInfos.empty()) {
1477 ArkParseJsFrameDebugInfos(JsFrameDebugInfos, size, jsFrame, size);
1478 } else {
1479 size = 0;
1480 }
1481 return ret;
1482 #else
1483 return false;
1484 #endif
1485 }
1486
GetData()1487 uint8_t* JSSymbolExtractor::GetData()
1488 {
1489 return data_;
1490 }
1491
GetLoadOffset()1492 uintptr_t JSSymbolExtractor::GetLoadOffset()
1493 {
1494 return loadOffset_;
1495 }
1496
GetDataSize()1497 uintptr_t JSSymbolExtractor::GetDataSize()
1498 {
1499 return dataSize_;
1500 }
1501
ParseHapFileData(std::string & hapName)1502 bool JSSymbolExtractor::ParseHapFileData([[maybe_unused]] std::string& hapName)
1503 {
1504 bool ret = false;
1505 #if defined(PANDA_TARGET_OHOS)
1506 if (hapName.empty()) {
1507 LOG_ECMA(ERROR) << "Get file data failed, path empty.";
1508 return false;
1509 }
1510 bool newCreate = false;
1511 std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(hapName, newCreate);
1512 if (extractor == nullptr) {
1513 LOG_ECMA(ERROR) << "GetExtractor failed, hap path: " << hapName;
1514 return false;
1515 }
1516
1517 std::string pandaFilePath = "ets/modules.abc";
1518 auto data = extractor->GetSafeData(pandaFilePath);
1519 if (!data) {
1520 LOG_ECMA(ERROR) << "GetSafeData failed, hap path: " << hapName;
1521 return false;
1522 }
1523
1524 data_ = data->GetDataPtr();
1525 dataSize_ = data->GetDataLen();
1526 loadOffset_ = static_cast<uintptr_t>(data->GetOffset());
1527 ret = true;
1528 auto zipFile = std::make_unique<ZipFile>(hapName);
1529 if (zipFile == nullptr || !zipFile->Open()) {
1530 return false;
1531 }
1532 auto &entrys = zipFile->GetAllEntries();
1533 if (ret) {
1534 std::string filePath = "ets/sourceMaps.map";
1535 if (entrys.find(filePath) == entrys.end()) {
1536 LOG_ECMA(INFO) << "Can't find sourceMaps.map in hap/hsp";
1537 return ret;
1538 }
1539 CreateSourceMap(hapName);
1540 }
1541 #endif
1542 return ret;
1543 }
1544
ArkParseJSFileInfo(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,const char * filePath,uintptr_t extractorptr,JsFunction * jsFunction)1545 bool ArkParseJSFileInfo([[maybe_unused]] uintptr_t byteCodePc, [[maybe_unused]] uintptr_t methodId,
1546 [[maybe_unused]] uintptr_t mapBase, [[maybe_unused]] const char* filePath,
1547 [[maybe_unused]] uintptr_t extractorptr, [[maybe_unused]] JsFunction *jsFunction)
1548 {
1549 bool ret = false;
1550 #if defined(PANDA_TARGET_OHOS)
1551 if (filePath == nullptr) {
1552 LOG_ECMA(ERROR) << "FilePath from dfx is nullptr.";
1553 return false;
1554 }
1555 auto extractor = reinterpret_cast<JSSymbolExtractor*>(extractorptr);
1556 if (extractor == nullptr) {
1557 LOG_ECMA(ERROR) << "Parse JSframe info failed, extractor is nullptr.";
1558 return false;
1559 }
1560 if (extractor->GetJSPandaFile() == nullptr) {
1561 std::string hapName = std::string(filePath);
1562 extractor->ParseHapFileData(hapName);
1563 extractor->CreateJSPandaFile();
1564 }
1565 ret = ArkParseJsFrameInfo(byteCodePc, methodId, mapBase, extractor->GetLoadOffset(),
1566 extractor->GetData(), extractor->GetDataSize(), extractorptr, jsFunction);
1567 #endif
1568 return ret;
1569 }
1570
~JSSymbolExtractor()1571 JSSymbolExtractor::~JSSymbolExtractor()
1572 {
1573 if (sourceMap_ != nullptr) {
1574 sourceMap_.reset();
1575 }
1576 if (debugExtractor_ != nullptr) {
1577 debugExtractor_.reset();
1578 }
1579 if (jsPandaFile_ != nullptr) {
1580 jsPandaFile_.reset();
1581 }
1582 methodInfo_.clear();
1583 }
1584
Create()1585 JSSymbolExtractor* JSSymbolExtractor::Create()
1586 {
1587 auto extractor = new JSSymbolExtractor();
1588 return extractor;
1589 }
1590
Destory(JSSymbolExtractor * extractor)1591 bool JSSymbolExtractor::Destory(JSSymbolExtractor *extractor)
1592 {
1593 if (extractor == nullptr) {
1594 LOG_ECMA(ERROR) << "Destory ark symbol extractor failed, extractor is nullptr.";
1595 return false;
1596 }
1597 delete extractor;
1598 extractor = nullptr;
1599 return true;
1600 }
1601
GetMethodInfos()1602 CVector<MethodInfo> JSSymbolExtractor::GetMethodInfos()
1603 {
1604 if (methodInfo_.empty()) {
1605 methodInfo_ = JSStackTrace::ReadAllMethodInfos(jsPandaFile_);
1606 }
1607
1608 return methodInfo_;
1609 }
1610
GetJSPandaFile(uint8_t * data,size_t dataSize)1611 JSPandaFile* JSSymbolExtractor::GetJSPandaFile(uint8_t *data, size_t dataSize)
1612 {
1613 if (jsPandaFile_ == nullptr && data != nullptr) {
1614 CreateJSPandaFile(data, dataSize);
1615 }
1616 return jsPandaFile_.get();
1617 }
1618
CreateJSPandaFile()1619 void JSSymbolExtractor::CreateJSPandaFile()
1620 {
1621 auto pf = panda_file::OpenPandaFileFromSecureMemory(data_, dataSize_);
1622 if (pf == nullptr) {
1623 LOG_ECMA(ERROR) << "Failed to open panda file.";
1624 return;
1625 }
1626 jsPandaFile_ = std::make_shared<JSPandaFile>(pf.release(), "");
1627 }
1628
CreateJSPandaFile(uint8_t * data,size_t dataSize)1629 void JSSymbolExtractor::CreateJSPandaFile(uint8_t *data, size_t dataSize)
1630 {
1631 auto pf = panda_file::OpenPandaFileFromSecureMemory(data, dataSize);
1632 if (pf == nullptr) {
1633 LOG_ECMA(ERROR) << "Failed to open panda file.";
1634 return;
1635 }
1636 jsPandaFile_ = std::make_shared<JSPandaFile>(pf.release(), "");
1637 }
1638
GetSourceMap(uint8_t * data,size_t dataSize)1639 SourceMap* JSSymbolExtractor::GetSourceMap(uint8_t *data, size_t dataSize)
1640 {
1641 if (sourceMap_ == nullptr && data != nullptr) {
1642 JSSymbolExtractor::CreateSourceMap(data, dataSize);
1643 }
1644 return sourceMap_.get();
1645 }
1646
CreateSourceMap(const std::string & hapPath)1647 void JSSymbolExtractor::CreateSourceMap([[maybe_unused]] const std::string &hapPath)
1648 {
1649 #if defined(PANDA_TARGET_OHOS)
1650 if (sourceMap_ == nullptr) {
1651 sourceMap_ = std::make_shared<SourceMap>();
1652 sourceMap_->Init(hapPath);
1653 }
1654 #endif
1655 }
1656
CreateSourceMap(uint8_t * data,size_t dataSize)1657 void JSSymbolExtractor::CreateSourceMap(uint8_t *data, size_t dataSize)
1658 {
1659 sourceMap_ = std::make_shared<SourceMap>();
1660 sourceMap_->Init(data, dataSize);
1661 }
1662
GetDebugExtractor()1663 DebugInfoExtractor* JSSymbolExtractor::GetDebugExtractor()
1664 {
1665 if (debugExtractor_ == nullptr) {
1666 JSSymbolExtractor::CreateDebugExtractor();
1667 }
1668 return debugExtractor_.get();
1669 }
1670
CreateDebugExtractor()1671 void JSSymbolExtractor::CreateDebugExtractor()
1672 {
1673 debugExtractor_ = std::make_unique<DebugInfoExtractor>(jsPandaFile_.get());
1674 }
1675
ArkCreateJSSymbolExtractor()1676 uintptr_t ArkCreateJSSymbolExtractor()
1677 {
1678 auto extractor = JSSymbolExtractor::Create();
1679 auto extractorptr = reinterpret_cast<uintptr_t>(extractor);
1680 return extractorptr;
1681 }
1682
ArkDestoryJSSymbolExtractor(uintptr_t extractorptr)1683 bool ArkDestoryJSSymbolExtractor(uintptr_t extractorptr)
1684 {
1685 auto extractor = reinterpret_cast<JSSymbolExtractor*>(extractorptr);
1686 return JSSymbolExtractor::Destory(extractor);
1687 }
1688
AddReference()1689 void JSStackTrace::AddReference()
1690 {
1691 std::unique_lock<std::mutex> lock(mutex_);
1692 if (count_ == 0) {
1693 trace_ = new JSStackTrace();
1694 }
1695 ++count_;
1696 LOG_ECMA(INFO) << "Add reference, count: " << count_;
1697 }
1698
ReleaseReference()1699 void JSStackTrace::ReleaseReference()
1700 {
1701 std::unique_lock<std::mutex> lock(mutex_);
1702 if (trace_ == nullptr) {
1703 return ;
1704 }
1705 --count_;
1706 LOG_ECMA(INFO) << "Release reference, count: " << count_;
1707 if (count_ == 0) {
1708 delete trace_;
1709 trace_ = nullptr;
1710 }
1711 }
1712
~JSStackTrace()1713 JSStackTrace::~JSStackTrace()
1714 {
1715 {
1716 std::unique_lock<std::shared_mutex> lock(infosMutex_);
1717 methodInfos_.clear();
1718 }
1719 {
1720 std::unique_lock<std::shared_mutex> lock(pfMutex_);
1721 jsPandaFiles_.clear();
1722 }
1723 }
1724
InitializeMethodInfo(uintptr_t mapBase)1725 bool JSStackTrace::InitializeMethodInfo(uintptr_t mapBase)
1726 {
1727 auto pandafile = FindJSpandaFile(mapBase);
1728 if (pandafile != nullptr) {
1729 return true;
1730 }
1731 pandafile =
1732 JSPandaFileManager::GetInstance()->FindJSPandaFileByMapBase(mapBase);
1733 if (pandafile == nullptr) {
1734 LOG_ECMA(ERROR) << "Find pandafile failed, mapBase: " << std::hex << mapBase;
1735 return false;
1736 }
1737 auto methodInfos = ReadAllMethodInfos(pandafile);
1738 SetMethodInfos(mapBase, methodInfos);
1739 SetJSpandaFile(mapBase, pandafile);
1740 return true;
1741 }
1742
FindJSpandaFile(uintptr_t mapBase)1743 std::shared_ptr<JSPandaFile> JSStackTrace::FindJSpandaFile(uintptr_t mapBase)
1744 {
1745 std::shared_lock<std::shared_mutex> lock(pfMutex_);
1746 auto iter = jsPandaFiles_.find(mapBase);
1747 if (iter == jsPandaFiles_.end()) {
1748 return nullptr;
1749 }
1750 return iter->second;
1751 }
1752
SetJSpandaFile(uintptr_t mapBase,std::shared_ptr<JSPandaFile> pandafile)1753 void JSStackTrace::SetJSpandaFile(uintptr_t mapBase, std::shared_ptr<JSPandaFile> pandafile)
1754 {
1755 std::unique_lock<std::shared_mutex> lock(pfMutex_);
1756 jsPandaFiles_.emplace(mapBase, pandafile);
1757 }
1758
FindMethodInfos(uintptr_t mapBase)1759 const CVector<MethodInfo> &JSStackTrace::FindMethodInfos(uintptr_t mapBase)
1760 {
1761 std::shared_lock<std::shared_mutex> lock(infosMutex_);
1762 auto iter = methodInfos_.find(mapBase);
1763 if (iter == methodInfos_.end()) {
1764 return methodInfo_;
1765 }
1766 return iter->second;
1767 }
1768
SetMethodInfos(uintptr_t mapBase,CVector<MethodInfo> & infos)1769 void JSStackTrace::SetMethodInfos(uintptr_t mapBase, CVector<MethodInfo> &infos)
1770 {
1771 std::unique_lock<std::shared_mutex> lock(infosMutex_);
1772 methodInfos_.emplace(mapBase, std::move(infos));
1773 }
1774
GetJsFrameInfo(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,uintptr_t loadOffset,JsFunction * jsFunction)1775 bool JSStackTrace::GetJsFrameInfo(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase,
1776 uintptr_t loadOffset, JsFunction *jsFunction)
1777 {
1778 if (!InitializeMethodInfo(mapBase)) {
1779 return false;
1780 }
1781 loadOffset = loadOffset % PageSize();
1782 byteCodePc = byteCodePc - loadOffset;
1783 auto infos = FindMethodInfos(mapBase);
1784 auto codeInfo = TranslateByteCodePc(byteCodePc, infos);
1785 if (!codeInfo) {
1786 LOG_ECMA(ERROR) << std::hex << "Failed to get methodId, pc: " << byteCodePc;
1787 return false;
1788 }
1789 methodId = codeInfo->methodId;
1790 auto offset = codeInfo->offset;
1791 auto pandafile = FindJSpandaFile(mapBase);
1792 auto debugInfoExtractor =
1793 JSPandaFileManager::GetInstance()->GetJSPtExtractor(pandafile.get());
1794 ParseJsFrameInfo(pandafile.get(), debugInfoExtractor, EntityId(methodId), offset, *jsFunction);
1795 jsFunction->codeBegin = byteCodePc - offset;
1796 jsFunction->codeSize = codeInfo->codeSize;
1797 return true;
1798 }
1799
ArkCreateLocal()1800 void ArkCreateLocal()
1801 {
1802 JSStackTrace::AddReference();
1803 }
1804
ArkParseJsFrameInfoLocal(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,uintptr_t loadOffset,JsFunction * jsFunction)1805 bool ArkParseJsFrameInfoLocal(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase,
1806 uintptr_t loadOffset, JsFunction *jsFunction)
1807 {
1808 auto trace = JSStackTrace::GetInstance();
1809 if (trace == nullptr) {
1810 LOG_ECMA(ERROR) << "singleton is null, need create first.";
1811 return false;
1812 }
1813 return trace->GetJsFrameInfo(byteCodePc, methodId, mapBase, loadOffset, jsFunction);
1814 }
1815
ArkDestoryLocal()1816 void ArkDestoryLocal()
1817 {
1818 JSStackTrace::ReleaseReference();
1819 }
1820
1821 } // namespace panda::ecmascript
1822
ark_create_js_symbol_extractor(uintptr_t * extractorptr)1823 __attribute__((visibility("default"))) int ark_create_js_symbol_extractor(uintptr_t *extractorptr)
1824 {
1825 *extractorptr = panda::ecmascript::ArkCreateJSSymbolExtractor();
1826 return 1;
1827 }
1828
ark_destory_js_symbol_extractor(uintptr_t extractorptr)1829 __attribute__((visibility("default"))) int ark_destory_js_symbol_extractor(uintptr_t extractorptr)
1830 {
1831 if (panda::ecmascript::ArkDestoryJSSymbolExtractor(extractorptr)) {
1832 return 1;
1833 }
1834 return -1;
1835 }
1836
ark_destroy_local()1837 __attribute__((visibility("default"))) int ark_destroy_local()
1838 {
1839 panda::ecmascript::ArkDestoryLocal();
1840 return 1;
1841 }
1842
ark_create_local()1843 __attribute__((visibility("default"))) int ark_create_local()
1844 {
1845 panda::ecmascript::ArkCreateLocal();
1846 return 1;
1847 }
1848
step_ark_with_record_jit(panda::ecmascript::ArkUnwindParam * arkUnwindParam)1849 __attribute__((visibility("default"))) int step_ark_with_record_jit(panda::ecmascript::ArkUnwindParam *arkUnwindParam)
1850 {
1851 if (panda::ecmascript::StepArkWithRecordJit(arkUnwindParam)) {
1852 return 1;
1853 }
1854 return -1;
1855 }
1856
ark_write_jit_code(void * ctx,panda::ecmascript::ReadMemFunc readMem,int fd,const uintptr_t * const jitCodeArray,const size_t jitSize)1857 __attribute__((visibility("default"))) int ark_write_jit_code(
1858 void *ctx, panda::ecmascript::ReadMemFunc readMem, int fd, const uintptr_t *const jitCodeArray,
1859 const size_t jitSize)
1860 {
1861 if (panda::ecmascript::ArkWriteJitCode(ctx, readMem, fd, jitCodeArray, jitSize)) {
1862 return 1;
1863 }
1864 return -1;
1865 }
1866
step_ark(void * ctx,panda::ecmascript::ReadMemFunc readMem,uintptr_t * fp,uintptr_t * sp,uintptr_t * pc,uintptr_t * methodId,bool * isJsFrame)1867 __attribute__((visibility("default"))) int step_ark(
1868 void *ctx, panda::ecmascript::ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp,
1869 uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame)
1870 {
1871 if (panda::ecmascript::StepArk(ctx, readMem, fp, sp, pc, methodId, isJsFrame)) {
1872 return 1;
1873 }
1874 return -1;
1875 }
1876
ark_parse_js_frame_info(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,uintptr_t loadOffset,uint8_t * data,uint64_t dataSize,uintptr_t extractorptr,panda::ecmascript::JsFunction * jsFunction)1877 __attribute__((visibility("default"))) int ark_parse_js_frame_info(
1878 uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data,
1879 uint64_t dataSize, uintptr_t extractorptr, panda::ecmascript::JsFunction *jsFunction)
1880 {
1881 if (panda::ecmascript::ArkParseJsFrameInfo(byteCodePc, methodId, mapBase, loadOffset, data,
1882 dataSize, extractorptr, jsFunction)) {
1883 return 1;
1884 }
1885 return -1;
1886 }
1887
ark_parse_js_file_info(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,const char * filePath,uintptr_t extractorptr,panda::ecmascript::JsFunction * jsFunction)1888 __attribute__((visibility("default"))) int ark_parse_js_file_info(
1889 uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, const char* filePath, uintptr_t extractorptr,
1890 panda::ecmascript::JsFunction *jsFunction)
1891 {
1892 if (panda::ecmascript::ArkParseJSFileInfo(byteCodePc, methodId, mapBase, filePath, extractorptr, jsFunction)) {
1893 return 1;
1894 }
1895 return -1;
1896 }
1897
ark_translate_js_frame_info(uint8_t * data,size_t dataSize,panda::ecmascript::JsFunction * jsFunction)1898 __attribute__((visibility("default"))) int ark_translate_js_frame_info(
1899 uint8_t *data, size_t dataSize, panda::ecmascript::JsFunction *jsFunction)
1900 {
1901 if (panda::ecmascript::ArkTranslateJsFrameInfo(data, dataSize, jsFunction)) {
1902 return 1;
1903 }
1904 return -1;
1905 }
1906
get_ark_native_frame_info(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,panda::ecmascript::JsFrame * jsFrame,size_t & size)1907 __attribute__((visibility("default"))) int get_ark_native_frame_info(
1908 int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp,
1909 panda::ecmascript::JsFrame *jsFrame, size_t &size)
1910 {
1911 if (panda::ecmascript::GetArkNativeFrameInfo(pid, pc, fp, sp, jsFrame, size)) {
1912 return 1;
1913 }
1914 return -1;
1915 }
1916
ark_parse_js_frame_info_local(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,uintptr_t loadOffset,panda::ecmascript::JsFunction * jsFunction)1917 __attribute__((visibility("default"))) int ark_parse_js_frame_info_local(
1918 uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset,
1919 panda::ecmascript::JsFunction *jsFunction)
1920 {
1921 if (panda::ecmascript::ArkParseJsFrameInfoLocal(byteCodePc, methodId, mapBase, loadOffset, jsFunction)) {
1922 return 1;
1923 }
1924 return -1;
1925 }
1926