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