• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #include "ecmascript/dfx/stackinfo/js_stackinfo.h"
17 #include "ecmascript/base/builtins_base.h"
18 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/interpreter/frame_handler.h"
20 #include "ecmascript/interpreter/interpreter.h"
21 #include "ecmascript/jspandafile/js_pandafile_manager.h"
22 #include "ecmascript/jspandafile/program_object.h"
23 #include "ecmascript/mem/heap-inl.h"
24 #include "ecmascript/message_string.h"
25 #include "ecmascript/platform/os.h"
26 #if defined(PANDA_TARGET_OHOS)
27 #include "ecmascript/extractortool/src/extractor.h"
28 #include "ecmascript/extractortool/src/source_map.h"
29 #endif
30 #if defined(ENABLE_EXCEPTION_BACKTRACE)
31 #include "ecmascript/platform/backtrace.h"
32 #endif
33 
34 namespace panda::ecmascript {
BuildMethodTrace(Method * method,uint32_t pcOffset,bool enableStackSourceFile)35 std::string JsStackInfo::BuildMethodTrace(Method *method, uint32_t pcOffset, bool enableStackSourceFile)
36 {
37     std::string data;
38     data.append("    at ");
39     std::string name = method->ParseFunctionName();
40     if (name.empty()) {
41         name = "anonymous";
42     }
43     data += name;
44     data.append(" (");
45     // source file
46     DebugInfoExtractor *debugExtractor =
47         JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile());
48     if (enableStackSourceFile) {
49         const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
50         if (sourceFile.empty()) {
51             data.push_back('?');
52         } else {
53             data += sourceFile;
54         }
55     } else {
56         data.append("hidden");
57     }
58 
59     data.push_back(':');
60     // line number and column number
61     auto callbackLineFunc = [&data](int32_t line) -> bool {
62         data += std::to_string(line + 1);
63         data.push_back(':');
64         return true;
65     };
66     auto callbackColumnFunc = [&data](int32_t column) -> bool {
67         data += std::to_string(column + 1);
68         return true;
69     };
70     panda_file::File::EntityId methodId = method->GetMethodId();
71     if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, pcOffset) ||
72         !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, pcOffset)) {
73         data.push_back('?');
74     }
75     data.push_back(')');
76     data.push_back('\n');
77     return data;
78 }
79 
BuildInlinedMethodTrace(const JSPandaFile * pf,std::map<uint32_t,uint32_t> & methodOffsets)80 std::string JsStackInfo::BuildInlinedMethodTrace(const JSPandaFile *pf, std::map<uint32_t, uint32_t> &methodOffsets)
81 {
82     std::string data;
83     std::map<uint32_t, uint32_t>::reverse_iterator it;
84     for (it = methodOffsets.rbegin(); it != methodOffsets.rend(); it++) {
85         uint32_t methodId = it->second;
86         std::string name;
87         if (methodId == 0) {
88             name = "unknown";
89         } else {
90             name = std::string(MethodLiteral::GetMethodName(pf, EntityId(methodId)));
91             if (name == "") {
92                 name = "anonymous";
93             }
94         }
95         data.append("    at ");
96         data.append(name);
97         data.append(" (maybe inlined).");
98         data.append(" depth: ");
99         data.append(std::to_string(it->first));
100 
101         data.push_back('\n');
102     }
103     return data;
104 }
105 
BuildJsStackTrace(JSThread * thread,bool needNative)106 std::string JsStackInfo::BuildJsStackTrace(JSThread *thread, bool needNative)
107 {
108     std::string data;
109     JSTaggedType *current = const_cast<JSTaggedType *>(thread->GetCurrentFrame());
110     FrameIterator it(current, thread);
111     for (; !it.Done(); it.Advance<GCVisitedFlag::HYBRID_STACK>()) {
112         if (!it.IsJSFrame()) {
113             continue;
114         }
115         auto method = it.CheckAndGetMethod();
116         if (method == nullptr) {
117             continue;
118         }
119         if (!method->IsNativeWithCallField()) {
120             auto pcOffset = it.GetBytecodeOffset();
121             const JSPandaFile *pf = method->GetJSPandaFile();
122             std::map<uint32_t, uint32_t> methodOffsets = it.GetInlinedMethodInfo();
123             data += BuildInlinedMethodTrace(pf, methodOffsets);
124             data += BuildMethodTrace(method, pcOffset, thread->GetEnableStackSourceFile());
125         } else if (needNative) {
126             auto addr = method->GetNativePointer();
127             std::stringstream strm;
128             strm << addr;
129             data.append("    at native method (").append(strm.str()).append(")\n");
130         }
131     }
132     if (data.empty()) {
133 #if defined(ENABLE_EXCEPTION_BACKTRACE)
134         std::ostringstream stack;
135         Backtrace(stack, false, true);
136         data = stack.str();
137 #endif
138     }
139     return data;
140 }
141 
BuildJsStackInfo(JSThread * thread)142 std::vector<struct JsFrameInfo> JsStackInfo::BuildJsStackInfo(JSThread *thread)
143 {
144     std::vector<struct JsFrameInfo> jsFrame;
145     uintptr_t *native = nullptr;
146     JSTaggedType *current = const_cast<JSTaggedType *>(thread->GetCurrentFrame());
147     FrameIterator it(current, thread);
148     for (; !it.Done(); it.Advance<GCVisitedFlag::HYBRID_STACK>()) {
149         if (!it.IsJSFrame()) {
150             continue;
151         }
152         auto method = it.CheckAndGetMethod();
153         if (method == nullptr) {
154             continue;
155         }
156         struct JsFrameInfo frameInfo;
157         if (native != nullptr) {
158             frameInfo.nativePointer = native;
159             native = nullptr;
160         }
161         if (!method->IsNativeWithCallField()) {
162             std::string name = method->ParseFunctionName();
163             if (name.empty()) {
164                 frameInfo.functionName = "anonymous";
165             } else {
166                 frameInfo.functionName = name;
167             }
168             // source file
169             DebugInfoExtractor *debugExtractor =
170                 JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile());
171             const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
172             if (sourceFile.empty()) {
173                 frameInfo.fileName = "?";
174             } else {
175                 frameInfo.fileName = sourceFile;
176             }
177             // line number and column number
178             int lineNumber = 0;
179             auto callbackLineFunc = [&frameInfo, &lineNumber](int32_t line) -> bool {
180                 lineNumber = line + 1;
181                 frameInfo.pos = std::to_string(lineNumber) + ":";
182                 return true;
183             };
184             auto callbackColumnFunc = [&frameInfo](int32_t column) -> bool {
185                 frameInfo.pos += std::to_string(column + 1);
186                 return true;
187             };
188             panda_file::File::EntityId methodId = method->GetMethodId();
189             uint32_t offset = it.GetBytecodeOffset();
190             if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) ||
191                 !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) {
192                 frameInfo.pos = "?";
193             }
194             jsFrame.push_back(frameInfo);
195         } else {
196             JSTaggedValue function = it.GetFunction();
197             JSHandle<JSTaggedValue> extraInfoValue(
198                 thread, JSFunction::Cast(function.GetTaggedObject())->GetFunctionExtraInfo());
199             if (extraInfoValue->IsJSNativePointer()) {
200                 JSHandle<JSNativePointer> extraInfo(extraInfoValue);
201                 native = reinterpret_cast<uintptr_t *>(extraInfo->GetExternalPointer());
202             }
203         }
204     }
205     return jsFrame;
206 }
207 
CrashCallback(char * buf,size_t len,void * ucontext)208 void CrashCallback(char *buf __attribute__((unused)), size_t len __attribute__((unused)),
209                    void *ucontext __attribute__((unused)))
210 {
211 #if defined(__aarch64__) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS)
212     if (ucontext == nullptr) {
213         // should not happen
214         return;
215     }
216     auto uctx = static_cast<ucontext_t *>(ucontext);
217     uintptr_t pc = uctx->uc_mcontext.pc;
218     uintptr_t fp = uctx->uc_mcontext.regs[29];  // 29: fp
219     // 1. check pc is between ark code heap
220     // 2. assemble crash info for ark code with signal-safe code
221     // 3. do not do much things inside callback, stack size is limited
222     // 4. do not use normal log
223     if (JsStackInfo::loader == nullptr) {
224         return;
225     }
226     if (!JsStackInfo::loader->InsideStub(pc) && !JsStackInfo::loader->InsideAOT(pc)) {
227         return;
228     }
229     LOG_ECMA(ERROR) << std::hex << "CrashCallback pc:" << pc << " fp:" << fp;
230     FrameIterator frame(reinterpret_cast<JSTaggedType *>(fp));
231     bool isBuiltinStub = (frame.GetFrameType() == FrameType::OPTIMIZED_FRAME);
232     Method *method = frame.CheckAndGetMethod();
233     while (method == nullptr) {
234         frame.Advance();
235         if (frame.Done()) {
236             break;
237         }
238         method = frame.CheckAndGetMethod();
239     }
240     std::string faultInfo;
241     if (method != nullptr) {
242         std::string methodName = method->GetMethodName();
243         std::string recordName = method->GetRecordNameStr().c_str();
244         faultInfo = "Method Name:" + methodName + " Record Name:" + recordName;
245     } else {
246         faultInfo = "method is nullptr!";
247     }
248     if (isBuiltinStub) {
249         uintptr_t func = uctx->uc_mcontext.regs[2];  // 2: func
250         JSTaggedValue builtinMethod = JSFunction::Cast(reinterpret_cast<TaggedObject *>(func))->GetMethod();
251         uint8_t builtinId = Method::Cast(builtinMethod.GetTaggedObject())->GetBuiltinId();
252         size_t builtinStart = static_cast<size_t>(GET_MESSAGE_STRING_ID(StringCharCodeAt) - 1);  // 1: offset NONE
253         std::string builtinStr = MessageString::GetMessageString(builtinStart + builtinId);
254         faultInfo += " " + builtinStr;
255     }
256     if (memcpy_s(buf, len, faultInfo.c_str(), faultInfo.length()) != EOK) {
257         LOG_ECMA(ERROR) << "memcpy_s fail in CrashCallback()!";  // not FATAL to avoid further crash
258     }
259 #endif
260 }
261 
ReadUintptrFromAddr(int pid,uintptr_t addr,uintptr_t & value,bool needCheckRegion)262 bool ReadUintptrFromAddr(int pid, uintptr_t addr, uintptr_t &value, bool needCheckRegion)
263 {
264     if (pid == getpid()) {
265         if (needCheckRegion) {
266             bool flag = false;
267             auto callback = [addr, &flag](Region *region) {
268                 uintptr_t regionBegin = region->GetBegin();
269                 uintptr_t regionEnd = region->GetEnd();
270                 if (regionBegin <= addr && addr <= regionEnd) {
271                     flag = true;
272                 }
273             };
274             if (JsStackInfo::loader != nullptr) {
275                 const Heap *heap = JsStackInfo::loader->GetHeap();
276                 if (heap != nullptr) {
277                     heap->EnumerateRegions(callback);
278                 }
279             }
280             if (!flag) {
281                 LOG_ECMA(ERROR) << "addr not in Region, addr: " << addr;
282                 return false;
283             }
284         }
285         value = *(reinterpret_cast<uintptr_t *>(addr));
286         return true;
287     }
288     long *retAddr = reinterpret_cast<long *>(&value);
289     // note: big endian
290     for (size_t i = 0; i < sizeof(uintptr_t) / sizeof(long); i++) {
291         *retAddr = PtracePeektext(pid, addr);
292         if (*retAddr == -1) {
293             LOG_ECMA(ERROR) << "ReadFromAddr ERROR, addr: " << addr;
294             return false;
295         }
296         addr += sizeof(long);
297         retAddr++;
298     }
299     return true;
300 }
301 
GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType,uintptr_t & typeOffset,uintptr_t & prevOffset)302 bool GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType, uintptr_t &typeOffset, uintptr_t &prevOffset)
303 {
304     FrameType type = static_cast<FrameType>(frameType);
305     switch (type) {
306         case FrameType::OPTIMIZED_FRAME:
307             typeOffset = OptimizedFrame::GetTypeOffset();
308             prevOffset = OptimizedFrame::GetPrevOffset();
309             break;
310         case FrameType::OPTIMIZED_ENTRY_FRAME:
311             typeOffset = OptimizedEntryFrame::GetTypeOffset();
312             prevOffset = OptimizedEntryFrame::GetLeaveFrameFpOffset();
313             break;
314         case FrameType::ASM_BRIDGE_FRAME:
315             typeOffset = AsmBridgeFrame::GetTypeOffset();
316             prevOffset = AsmBridgeFrame::GetPrevOffset();
317             break;
318         case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
319             typeOffset = OptimizedJSFunctionUnfoldArgVFrame::GetTypeOffset();
320             prevOffset = OptimizedJSFunctionUnfoldArgVFrame::GetPrevOffset();
321             break;
322         case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
323         case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
324         case FrameType::OPTIMIZED_JS_FUNCTION_FRAME:
325             typeOffset = OptimizedJSFunctionFrame::GetTypeOffset();
326             prevOffset = OptimizedJSFunctionFrame::GetPrevOffset();
327             break;
328         case FrameType::LEAVE_FRAME:
329             typeOffset = OptimizedLeaveFrame::GetTypeOffset();
330             prevOffset = OptimizedLeaveFrame::GetPrevOffset();
331             break;
332         case FrameType::LEAVE_FRAME_WITH_ARGV:
333             typeOffset = OptimizedWithArgvLeaveFrame::GetTypeOffset();
334             prevOffset = OptimizedWithArgvLeaveFrame::GetPrevOffset();
335             break;
336         case FrameType::BUILTIN_CALL_LEAVE_FRAME:
337             typeOffset = OptimizedBuiltinLeaveFrame::GetTypeOffset();
338             prevOffset = OptimizedBuiltinLeaveFrame::GetPrevOffset();
339             break;
340         case FrameType::INTERPRETER_FRAME:
341         case FrameType::INTERPRETER_FAST_NEW_FRAME:
342             typeOffset = InterpretedFrame::GetTypeOffset();
343             prevOffset = InterpretedFrame::GetPrevOffset();
344             break;
345         case FrameType::INTERPRETER_BUILTIN_FRAME:
346             typeOffset = InterpretedBuiltinFrame::GetTypeOffset();
347             prevOffset = InterpretedBuiltinFrame::GetPrevOffset();
348             break;
349         case FrameType::INTERPRETER_CONSTRUCTOR_FRAME:
350         case FrameType::ASM_INTERPRETER_FRAME:
351             typeOffset = AsmInterpretedFrame::GetTypeOffset();
352             prevOffset = AsmInterpretedFrame::GetPrevOffset();
353             break;
354         case FrameType::BUILTIN_FRAME:
355         case FrameType::BUILTIN_ENTRY_FRAME:
356             typeOffset = BuiltinFrame::GetTypeOffset();
357             prevOffset = BuiltinFrame::GetPrevOffset();
358             break;
359         case FrameType::BUILTIN_FRAME_WITH_ARGV:
360         case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME:
361             typeOffset = BuiltinWithArgvFrame::GetTypeOffset();
362             prevOffset = BuiltinWithArgvFrame::GetPrevOffset();
363             break;
364         case FrameType::INTERPRETER_ENTRY_FRAME:
365             typeOffset = InterpretedEntryFrame::GetTypeOffset();
366             prevOffset = InterpretedEntryFrame::GetPrevOffset();
367             break;
368         case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
369             typeOffset = AsmInterpretedEntryFrame::GetTypeOffset();
370             prevOffset = AsmInterpretedEntryFrame::GetPrevOffset();
371             break;
372         case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
373             typeOffset = AsmInterpretedBridgeFrame::GetTypeOffset();
374             prevOffset = AsmInterpretedBridgeFrame::GetPrevOffset();
375             break;
376         default:
377             return false;
378     }
379     return true;
380 }
381 
382 #if defined(PANDA_TARGET_OHOS)
ArkGetFunction(int pid,uintptr_t currentPtr,uintptr_t frameType)383 uintptr_t ArkGetFunction(int pid, uintptr_t currentPtr, uintptr_t frameType)
384 {
385     FrameType type = static_cast<FrameType>(frameType);
386     uintptr_t funcAddr = currentPtr;
387     switch (type) {
388         case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
389         case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
390             funcAddr -= OptimizedJSFunctionFrame::GetTypeOffset();
391             funcAddr += OptimizedJSFunctionFrame::GetFunctionOffset();
392             break;
393         }
394         case FrameType::ASM_INTERPRETER_FRAME:
395         case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
396             funcAddr -= AsmInterpretedFrame::GetTypeOffset();
397             funcAddr += AsmInterpretedFrame::GetFunctionOffset(false);
398             break;
399         }
400         case FrameType::INTERPRETER_FRAME:
401         case FrameType::INTERPRETER_FAST_NEW_FRAME: {
402             funcAddr -= InterpretedFrame::GetTypeOffset();
403             funcAddr += InterpretedFrame::GetFunctionOffset();
404             break;
405         }
406         case FrameType::INTERPRETER_BUILTIN_FRAME: {
407             funcAddr -= InterpretedBuiltinFrame::GetTypeOffset();
408             funcAddr += InterpretedBuiltinFrame::GetFunctionOffset();
409             break;
410         }
411         case FrameType::BUILTIN_FRAME_WITH_ARGV: {
412             funcAddr += sizeof(FrameType);
413             auto topAddress = funcAddr +
414                 (static_cast<int>(BuiltinWithArgvFrame::Index::StackArgsTopIndex) * sizeof(uintptr_t));
415             uintptr_t argcAddress = static_cast<uintptr_t>(funcAddr + (static_cast<int>
416                                     (BuiltinWithArgvFrame::Index::NumArgsIndex) * sizeof(uintptr_t)));
417             if (!ReadUintptrFromAddr(pid, argcAddress, argcAddress, true)) {
418                 return 0;
419             }
420             auto numberArgs = argcAddress + NUM_MANDATORY_JSFUNC_ARGS;
421             funcAddr = topAddress - static_cast<uint32_t>(numberArgs) * sizeof(uintptr_t);
422             break;
423         }
424         case FrameType::BUILTIN_ENTRY_FRAME:
425         case FrameType::BUILTIN_FRAME: {
426             funcAddr -= BuiltinFrame::GetTypeOffset();
427             funcAddr += BuiltinFrame::GetStackArgsOffset();
428             break;
429         }
430         case FrameType::BUILTIN_CALL_LEAVE_FRAME: {
431             funcAddr -= OptimizedBuiltinLeaveFrame::GetTypeOffset();
432             funcAddr += OptimizedBuiltinLeaveFrame::GetFunctionOffset();
433             break;
434         }
435         case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME :
436         case FrameType::OPTIMIZED_FRAME:
437         case FrameType::OPTIMIZED_ENTRY_FRAME:
438         case FrameType::ASM_BRIDGE_FRAME:
439         case FrameType::LEAVE_FRAME:
440         case FrameType::LEAVE_FRAME_WITH_ARGV:
441         case FrameType::INTERPRETER_ENTRY_FRAME:
442         case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
443         case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
444         case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
445         case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME: {
446             return 0;
447         }
448         default: {
449             LOG_FULL(FATAL) << "Unknown frame type: " << static_cast<uintptr_t>(type);
450             UNREACHABLE();
451         }
452     }
453     uintptr_t function = 0;
454     if (!ReadUintptrFromAddr(pid, funcAddr, function, true)) {
455         return 0;
456     }
457     return function;
458 }
459 
ArkCheckIsJSFunctionBaseOrJSProxy(int pid,uintptr_t objAddr,bool & isJSFunctionBase)460 bool ArkCheckIsJSFunctionBaseOrJSProxy(int pid, uintptr_t objAddr, bool &isJSFunctionBase)
461 {
462     bool isHeapObj = ((objAddr & JSTaggedValue::TAG_HEAPOBJECT_MASK) == 0U);
463     bool isInvalidValue = (objAddr <= JSTaggedValue::INVALID_VALUE_LIMIT);
464     if (isHeapObj && !isInvalidValue) {
465         ASSERT_PRINT(((objAddr & JSTaggedValue::TAG_WEAK) == 0U),
466                      "can not convert JSTaggedValue to HeapObject :" << std::hex << objAddr);
467         uintptr_t hclassAddr = objAddr + TaggedObject::HCLASS_OFFSET;
468         uintptr_t hclass = 0;
469         if (!ReadUintptrFromAddr(pid, hclassAddr, hclass, true)) {
470             return false;
471         }
472         if (hclass != 0) {
473             uintptr_t bitsAddr = reinterpret_cast<uintptr_t>(hclass + JSHClass::BIT_FIELD_OFFSET);
474             uintptr_t bits = 0;
475             if (!ReadUintptrFromAddr(pid, bitsAddr, bits, true)) {
476                 return false;
477             }
478             JSType jsType = JSHClass::ObjectTypeBits::Decode(bits);
479             isJSFunctionBase = (jsType >= JSType::JS_FUNCTION_BASE && jsType <= JSType::JS_BOUND_FUNCTION);
480             bool isJSProxy = (jsType == JSType::JS_PROXY);
481             return isJSFunctionBase || isJSProxy;
482         }
483     }
484     return false;
485 }
486 
ArkCheckAndGetMethod(int pid,uintptr_t value)487 uintptr_t ArkCheckAndGetMethod(int pid, uintptr_t value)
488 {
489     bool isJSFunctionBase = 0;
490     if (ArkCheckIsJSFunctionBaseOrJSProxy(pid, value, isJSFunctionBase)) {
491         if (isJSFunctionBase) {
492             value += JSFunctionBase::METHOD_OFFSET;
493         } else {
494             value += JSProxy::METHOD_OFFSET;
495         }
496         uintptr_t method = 0;
497         if (!ReadUintptrFromAddr(pid, value, method, true)) {
498             return 0;
499         }
500         return method;
501     }
502     return 0;
503 }
504 
ArkGetMethodIdandJSPandaFileAddr(int pid,uintptr_t method,uintptr_t & methodId,uintptr_t & jsPandaFileAddr)505 bool ArkGetMethodIdandJSPandaFileAddr(int pid, uintptr_t method, uintptr_t &methodId, uintptr_t &jsPandaFileAddr)
506 {
507     uintptr_t methodLiteralAddr = method + Method::LITERAL_INFO_OFFSET;
508     uintptr_t methodLiteral = 0;
509     if (!ReadUintptrFromAddr(pid, methodLiteralAddr, methodLiteral, true)) {
510             return false;
511     }
512     methodId = MethodLiteral::MethodIdBits::Decode(methodLiteral);
513     uintptr_t constantpoolAddr = method + Method::CONSTANT_POOL_OFFSET;
514     uintptr_t constantpool = 0;
515     if (!ReadUintptrFromAddr(pid, constantpoolAddr, constantpool, true)) {
516         return false;
517     }
518     if (constantpool == JSTaggedValue::VALUE_UNDEFINED) {
519         return false;
520     }
521     uintptr_t lengthAddr = constantpool + TaggedArray::LENGTH_OFFSET;
522     uintptr_t length = 0;
523     if (!ReadUintptrFromAddr(pid, lengthAddr, length, true)) {
524         return false;
525     }
526     jsPandaFileAddr = constantpool + TaggedArray::DATA_OFFSET +
527                     JSTaggedValue::TaggedTypeSize() * (length - ConstantPool::JS_PANDA_FILE_INDEX);
528     if (!ReadUintptrFromAddr(pid, jsPandaFileAddr, jsPandaFileAddr, true)) {
529         return false;
530     }
531     return true;
532 }
533 
ArkGetOffsetFromMethod(int pid,uintptr_t currentPtr,uintptr_t method)534 uint32_t ArkGetOffsetFromMethod(int pid, uintptr_t currentPtr, uintptr_t method)
535 {
536     uintptr_t pc = 0;
537     if (!ReadUintptrFromAddr(pid, currentPtr, pc, true)) {
538         return 0;
539     }
540     uintptr_t byteCodeArrayAddr = method + Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET;
541     uintptr_t byteCodeArray = 0;
542     if (!ReadUintptrFromAddr(pid, byteCodeArrayAddr, byteCodeArray, true)) {
543         return 0;
544     }
545     uintptr_t offset = pc - byteCodeArray;
546     return static_cast<uint32_t>(offset);
547 }
548 
ArkGetBytecodeOffset(int pid,uintptr_t method,uintptr_t frameType,uintptr_t currentPtr)549 uint32_t ArkGetBytecodeOffset(int pid, uintptr_t method, uintptr_t frameType, uintptr_t currentPtr)
550 {
551     FrameType type = static_cast<FrameType>(frameType);
552     switch (type) {
553         case FrameType::ASM_INTERPRETER_FRAME:
554         case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
555             currentPtr -= AsmInterpretedFrame::GetTypeOffset();
556             currentPtr += AsmInterpretedFrame::GetPcOffset(false);
557             return ArkGetOffsetFromMethod(pid, currentPtr, method);
558         }
559         case FrameType::INTERPRETER_FRAME:
560         case FrameType::INTERPRETER_FAST_NEW_FRAME: {
561             currentPtr -= InterpretedFrame::GetTypeOffset();
562             currentPtr += InterpretedFrame::GetPcOffset(false);
563             return ArkGetOffsetFromMethod(pid, currentPtr, method);
564         }
565         // ato need stackmaps
566         case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
567         case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
568             break;
569         }
570         default: {
571             break;
572         }
573     }
574     return 0;
575 }
576 
ArkReadData(const std::string & hapPath,const std::string & sourceMapPath,char ** data,size_t & dataSize)577 bool ArkReadData(const std::string &hapPath, const std::string &sourceMapPath, char **data, size_t &dataSize)
578 {
579     // Source map relative path, FA: "/assets/js", Stage: "/ets"
580     if (hapPath.empty()) {
581         LOG_ECMA(ERROR) << "hapPath is empty";
582         return false;
583     }
584     bool newCreate = false;
585     std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(
586         ExtractorUtil::GetLoadFilePath(hapPath), newCreate);
587     if (extractor == nullptr) {
588         LOG_ECMA(ERROR) << "hap's path: " << hapPath;
589         return false;
590     }
591     std::unique_ptr<uint8_t[]> dataPtr = nullptr;
592     if (!extractor->ExtractToBufByName(sourceMapPath, dataPtr, dataSize)) {
593         LOG_ECMA(DEBUG) << "can't find source map, and switch to stage model.";
594         return false;
595     }
596     *data = (char*)malloc(sizeof(char)*dataSize);
597     if (memcpy_s(*data, dataSize, dataPtr.get(), dataSize) != EOK) {
598         LOG_ECMA(FATAL) << "memcpy_s failed";
599         UNREACHABLE();
600     }
601     return true;
602 }
603 
ArkGetMapPath(std::string & fileName)604 std::string ArkGetMapPath(std::string &fileName)
605 {
606     auto lastSlash = fileName.rfind("/");
607     if (lastSlash == std::string::npos) {
608         LOG_ECMA(ERROR) << "ArkGetMapPath can't find fisrt /: " << fileName;
609         return "";
610     }
611 
612     auto secondLastSlash = fileName.rfind("/", lastSlash - 1);
613     if (secondLastSlash == std::string::npos) {
614         LOG_ECMA(ERROR) << "ArkGetMapPath can't second fisrt /: " << fileName;
615         return "";
616     }
617 
618     std::string mapPath = fileName.substr(secondLastSlash + 1);
619     return mapPath;
620 }
621 
ArkIsNativeWithCallField(int pid,uintptr_t method)622 bool ArkIsNativeWithCallField(int pid, uintptr_t method)
623 {
624     uintptr_t callFieldAddr = method + Method::CALL_FIELD_OFFSET;
625     uintptr_t callField = 0;
626     if (!ReadUintptrFromAddr(pid, callFieldAddr, callField, true)) {
627         return true;
628     }
629     return Method::IsNativeBit::Decode(callField);
630 }
631 
ArkReadCStringFromAddr(int pid,uintptr_t descAddr)632 std::string ArkReadCStringFromAddr(int pid, uintptr_t descAddr)
633 {
634     std::string name;
635     while (true) {
636         uintptr_t desc = 0;
637         if (!ReadUintptrFromAddr(pid, descAddr, desc, true)) {
638             LOG_ECMA(ERROR) << "ArkReadCStringFromAddr failed, descAddr: " << descAddr;
639             return name;
640         }
641         bool key = 1;
642         size_t shiftAmount = 8;
643         for (size_t i = 0; i < sizeof(long); i++) {
644             char bottomEightBits = desc;
645             desc = desc >> shiftAmount;
646             if (!bottomEightBits) {
647                 key = 0;
648                 break;
649             }
650             name += bottomEightBits;
651         }
652         if (!key) {
653             break;
654         }
655         descAddr += sizeof(long);
656     }
657     return name;
658 }
659 
ArkGetFileName(int pid,uintptr_t jsPandaFileAddr,std::string & hapPath)660 std::string ArkGetFileName(int pid, uintptr_t jsPandaFileAddr, std::string &hapPath)
661 {
662     size_t size = sizeof(JSPandaFile) / sizeof(long);
663     uintptr_t *jsPandaFilePart = new uintptr_t[size]();
664     for (size_t i = 0; i < size; i++) {
665         if (!ReadUintptrFromAddr(pid, jsPandaFileAddr, jsPandaFilePart[i], true)) {
666             LOG_ECMA(ERROR) << "ArkGetFileName failed, jsPandaFileAddr: " << jsPandaFileAddr;
667             return "";
668         }
669         jsPandaFileAddr += sizeof(long);
670     }
671     JSPandaFile *jsPandaFile = reinterpret_cast<JSPandaFile *>(jsPandaFilePart);
672 
673     uintptr_t hapPathAddr = reinterpret_cast<uintptr_t>(
674         const_cast<char *>(jsPandaFile->GetJSPandaFileHapPath().c_str()));
675     hapPath = ArkReadCStringFromAddr(pid, hapPathAddr);
676 
677     uintptr_t descAddr = reinterpret_cast<uintptr_t>(
678         const_cast<char *>(jsPandaFile->GetJSPandaFileDesc().c_str()));
679     delete []jsPandaFilePart;
680     return ArkReadCStringFromAddr(pid, descAddr);
681 }
682 
ArkParseJsFrameInfo(const panda_file::File * pf,std::string & fileName,uintptr_t preMethodId,uintptr_t offset,std::string hapPath)683 JsFrame ArkParseJsFrameInfo(const panda_file::File *pf, std::string &fileName,
684                             uintptr_t preMethodId, uintptr_t offset, std::string hapPath)
685 {
686     std::shared_ptr<JSPandaFile> newJsPandaFile =
687             JSPandaFileManager::GetInstance()->NewJSPandaFile(pf, fileName.c_str());
688     auto debugExtractor = std::make_unique<DebugInfoExtractor>(newJsPandaFile.get());
689     auto methodId = EntityId(preMethodId);
690     std::string name = MethodLiteral::ParseFunctionName(newJsPandaFile.get(), methodId);
691     name = name.empty() ? "anonymous" : name;
692     std::string url = debugExtractor->GetSourceFile(methodId);
693 
694     // line number and column number
695     int lineNumber = 0;
696     int columnNumber = 0;
697     auto callbackLineFunc = [&lineNumber](int32_t line) -> bool {
698         lineNumber = line + 1;
699         return true;
700     };
701     auto callbackColumnFunc = [&columnNumber](int32_t column) -> bool {
702         columnNumber = column + 1;
703         return true;
704     };
705     if (offset > 0) {
706         if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) ||
707             !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) {
708             lineNumber = 0;
709             columnNumber = 0;
710         }
711     }
712     SourceMap sourceMapObj;
713     sourceMapObj.Init(url, hapPath);
714     sourceMapObj.TranslateUrlPositionBySourceMap(url, lineNumber, columnNumber);
715     JsFrame jsFrame;
716     size_t urlSize = url.size() + 1;
717     size_t nameSize = name.size() + 1;
718     if (strcpy_s(jsFrame.url, urlSize, url.c_str()) != EOK ||
719         strcpy_s(jsFrame.functionName, nameSize, name.c_str()) != EOK) {
720         LOG_FULL(FATAL) << "strcpy_s failed";
721         UNREACHABLE();
722     }
723     jsFrame.line = lineNumber;
724     jsFrame.column = columnNumber;
725     return jsFrame;
726 }
727 
ArkGetNextFrame(uintptr_t & currentPtr,uintptr_t typeOffset,uintptr_t prevOffset,int pid)728 bool ArkGetNextFrame(uintptr_t &currentPtr, uintptr_t typeOffset,
729                      uintptr_t prevOffset, int pid)
730 {
731     currentPtr -= typeOffset;
732     currentPtr += prevOffset;
733     if (!ReadUintptrFromAddr(pid, currentPtr, currentPtr, true)) {
734         return false;
735     }
736     if (currentPtr == 0) {
737         LOG_ECMA(ERROR) << "currentPtr is nullptr in GetArkNativeFrameInfo()!";
738         return false;
739     }
740     return true;
741 }
742 
ArkFrameCheck(uintptr_t frameType)743 bool ArkFrameCheck(uintptr_t frameType)
744 {
745     return static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_ENTRY_FRAME ||
746            static_cast<FrameType>(frameType) == FrameType::ASM_INTERPRETER_ENTRY_FRAME;
747 }
748 
GetArkNativeFrameInfo(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,panda::ecmascript::JsFrame * jsFrame,size_t & size)749 bool GetArkNativeFrameInfo(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp,
750                            panda::ecmascript::JsFrame *jsFrame, size_t &size)
751 {
752     constexpr size_t FP_SIZE = 8;
753     constexpr size_t LR_SIZE = 8;
754     uintptr_t currentPtr = *fp;
755     if (currentPtr == 0) {
756         LOG_ECMA(ERROR) << "fp is nullptr in GetArkNativeFrameInfo()!";
757         return false;
758     }
759     if (pid == getpid() && JsStackInfo::loader != nullptr &&
760         !JsStackInfo::loader->InsideStub(*pc) && !JsStackInfo::loader->InsideAOT(*pc)) {
761         LOG_ECMA(ERROR) << "invalid pc in GetArkNativeFrameInfo()!";
762         return false;
763     }
764     std::vector<JsFrame> frames;
765     while (true) {
766         currentPtr -= sizeof(FrameType);
767         uintptr_t frameType = 0;
768         if (!ReadUintptrFromAddr(pid, currentPtr, frameType, true)) {
769             return false;
770         }
771         uintptr_t typeOffset = 0;
772         uintptr_t prevOffset = 0;
773         if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) {
774             LOG_ECMA(ERROR) << "FrameType ERROR, addr: " << currentPtr << ", frameType: " << frameType;
775             return false;
776         }
777         if (ArkFrameCheck(frameType)) {
778             break;
779         }
780         uintptr_t function = ArkGetFunction(pid, currentPtr, frameType);
781         if (!function) {
782             if (!ArkGetNextFrame(currentPtr, typeOffset, prevOffset, pid)) {
783                 return false;
784             }
785             continue;
786         }
787         uintptr_t method = ArkCheckAndGetMethod(pid, function);
788         if (!method || ArkIsNativeWithCallField(pid, method)) {
789             if (!ArkGetNextFrame(currentPtr, typeOffset, prevOffset, pid)) {
790                 return false;
791             }
792             continue;
793         }
794         uintptr_t jsPandaFileAddr = 0;
795         uintptr_t preMethodId = 0;
796         if (!ArkGetMethodIdandJSPandaFileAddr(pid, method, preMethodId, jsPandaFileAddr)) {
797             LOG_ECMA(ERROR) << "Method ERROR, method: " << method;
798             if (!ArkGetNextFrame(currentPtr, typeOffset, prevOffset, pid)) {
799                 return false;
800             }
801             continue;
802         }
803         uintptr_t offset = ArkGetBytecodeOffset(pid, method, frameType, currentPtr);
804         std::string hapPath;
805         std::string fileName = ArkGetFileName(pid, jsPandaFileAddr, hapPath);
806         if (fileName.empty()) {
807             LOG_ECMA(ERROR) << "fileName is empty, hapPath: " << hapPath;
808             if (!ArkGetNextFrame(currentPtr, typeOffset, prevOffset, pid)) {
809                 return false;
810             }
811             continue;
812         }
813         std::string mapPath = ArkGetMapPath(fileName);
814         char *data = nullptr;
815         size_t dataSize = 0;
816         if (!ArkReadData(hapPath, mapPath, &data, dataSize)) {
817             if (!ArkGetNextFrame(currentPtr, typeOffset, prevOffset, pid)) {
818                 return false;
819             }
820             free(data);
821             continue;
822         }
823         auto pf = panda_file::OpenPandaFileFromMemory(data, dataSize);
824         free(data);
825         if (!pf.get()) {
826             LOG_ECMA(ERROR) << "OpenPandaFileFromMemory ERROR, hapPath: " << hapPath
827                             << ", mapPath: " << mapPath << ", fileName: " << fileName
828                             << ", dataSize: " << dataSize;
829             if (!ArkGetNextFrame(currentPtr, typeOffset, prevOffset, pid)) {
830                 return false;
831             }
832             continue;
833         }
834         JsFrame frame = ArkParseJsFrameInfo(pf.release(), fileName, preMethodId, offset, hapPath);
835         frames.push_back(frame);
836 
837         if (!ArkGetNextFrame(currentPtr, typeOffset, prevOffset, pid)) {
838             return false;
839         }
840     }
841     currentPtr += sizeof(FrameType);
842     *fp = currentPtr;
843     currentPtr += FP_SIZE;
844     if (!ReadUintptrFromAddr(pid, currentPtr, *pc, true)) {
845         return false;
846     }
847     currentPtr += LR_SIZE;
848     *sp = currentPtr;
849 
850     size = frames.size() > size ? size : frames.size();
851     for (size_t i = 0; i < size ; ++i) {
852         jsFrame[i] = frames[i];
853     }
854     return true;
855 }
856 #endif
857 
StepArkManagedNativeFrame(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,char * buf,size_t buf_sz)858 bool StepArkManagedNativeFrame(int pid, uintptr_t *pc, uintptr_t *fp,
859     uintptr_t *sp, [[maybe_unused]] char *buf, [[maybe_unused]] size_t buf_sz)
860 {
861     constexpr size_t FP_SIZE = 8;
862     constexpr size_t LR_SIZE = 8;
863     uintptr_t currentPtr = *fp;
864     if (currentPtr == 0) {
865         LOG_ECMA(ERROR) << "fp is nullptr in StepArkManagedNativeFrame()!";
866         return false;
867     }
868     if (pid == getpid() && JsStackInfo::loader != nullptr &&
869         !JsStackInfo::loader->InsideStub(*pc) && !JsStackInfo::loader->InsideAOT(*pc)) {
870         LOG_ECMA(ERROR) << "invalid pc in StepArkManagedNativeFrame()!";
871         return false;
872     }
873     while (true) {
874         currentPtr -= sizeof(FrameType);
875         uintptr_t frameType = 0;
876         if (!ReadUintptrFromAddr(pid, currentPtr, frameType, true)) {
877             return false;
878         }
879         uintptr_t typeOffset = 0;
880         uintptr_t prevOffset = 0;
881         if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) {
882             LOG_ECMA(ERROR) << "FrameType ERROR, addr: " << currentPtr << ", frameType: " << frameType;
883             return false;
884         }
885         if (static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_ENTRY_FRAME ||
886             static_cast<FrameType>(frameType) == FrameType::ASM_INTERPRETER_ENTRY_FRAME ||
887             static_cast<FrameType>(frameType) == FrameType::BUILTIN_ENTRY_FRAME) {
888             break;
889         }
890         currentPtr -= typeOffset;
891         currentPtr += prevOffset;
892         if (!ReadUintptrFromAddr(pid, currentPtr, currentPtr, true)) {
893             return false;
894         }
895         if (currentPtr == 0) {
896             LOG_ECMA(ERROR) << "currentPtr is nullptr in StepArkManagedNativeFrame()!";
897             return false;
898         }
899     }
900     currentPtr += sizeof(FrameType);
901     *fp = currentPtr;
902     currentPtr += FP_SIZE;
903     if (!ReadUintptrFromAddr(pid, currentPtr, *pc, true)) {
904         return false;
905     }
906     currentPtr += LR_SIZE;
907     *sp = currentPtr;
908     return true;
909 }
910 
CopyBytecodeInfoToBuffer(const char * prefix,uintptr_t fullBytecode,size_t & strIdx,char * outStr,size_t strLen)911 void CopyBytecodeInfoToBuffer(const char *prefix, uintptr_t fullBytecode, size_t &strIdx, char *outStr, size_t strLen)
912 {
913     // note: big endian
914     for (size_t i = 0; prefix[i] != '\0' && strIdx < strLen - 1; i++) {  // 1: last '\0'
915         outStr[strIdx++] = prefix[i];
916     }
917     size_t start = static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleLdundefined));
918     size_t bytecode = fullBytecode & 0xff;  // 0xff: last byte
919     const char *bytecodeName = MessageString::GetMessageString(start + bytecode).c_str();
920     for (size_t i = 0; bytecodeName[i] != '\0' && strIdx < strLen - 1; i++) {  // 1: last '\0'
921         outStr[strIdx++] = bytecodeName[i];
922     }
923     if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleDeprecated)) ||
924         start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleWide)) ||
925         start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleThrow)) ||
926         start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleCallRuntime))) {
927         size_t startSecond = start;
928         if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleDeprecated))) {
929             startSecond = static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleDeprecatedLdlexenvPrefNone));
930         } else if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleWide))) {
931             startSecond = static_cast<size_t>(GET_MESSAGE_STRING_ID(
932                 HandleWideCreateobjectwithexcludedkeysPrefImm16V8V8));
933         } else if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleThrow))) {
934             startSecond = static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleThrowPrefNone));
935         } else if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleCallRuntime))) {
936             startSecond = static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleCallRuntimeNotifyConcurrentResultPrefNone));
937         }
938         size_t bytecodeSecond = (fullBytecode >> 8) & 0xff;  // 8, 0xff: second last byte
939         const char *bytecodeNameSecond = MessageString::GetMessageString(startSecond + bytecodeSecond).c_str();
940         if (strIdx < strLen - 1) {  // 1: last '\0'
941             outStr[strIdx++] = '/';
942         }
943         for (size_t i = 0; bytecodeNameSecond[i] != '\0' && strIdx < strLen - 1; i++) {  // 1: last '\0'
944             outStr[strIdx++] = bytecodeNameSecond[i];
945         }
946     }
947     outStr[strIdx] = '\0';
948 }
949 
GetArkJSHeapCrashInfo(int pid,uintptr_t * bytecodePc,uintptr_t * fp,bool outJSInfo,char * outStr,size_t strLen)950 bool GetArkJSHeapCrashInfo(int pid, uintptr_t *bytecodePc, uintptr_t *fp, bool outJSInfo, char *outStr, size_t strLen)
951 {
952     // bytecodePc: X20 in ARM
953     // fp: X29 in ARM
954     // outJSInfo: not async-safe, more info
955     uintptr_t currentPtr = *fp;
956     if (currentPtr == 0) {
957         LOG_ECMA(ERROR) << "fp is nullptr in GetArkJSHeapCrashInfo()!";
958         return false;
959     }
960     currentPtr -= sizeof(FrameType);
961     uintptr_t frameType = 0;
962     if (!ReadUintptrFromAddr(pid, currentPtr, frameType, false)) {
963         return false;
964     }
965     if (static_cast<FrameType>(frameType) != FrameType::ASM_INTERPRETER_FRAME) {
966         return false;
967     }
968     size_t strIndex = 0;
969     uintptr_t registerBytecode = 0;
970     if (!ReadUintptrFromAddr(pid, *bytecodePc, registerBytecode, false)) {
971         return false;
972     }
973     CopyBytecodeInfoToBuffer("RegisterBytecode:", registerBytecode, strIndex, outStr, strLen);
974     uintptr_t typeOffset = MEMBER_OFFSET(AsmInterpretedFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, type);
975     uintptr_t pcOffset = MEMBER_OFFSET(AsmInterpretedFrame, pc);
976     currentPtr -= typeOffset;
977     currentPtr += pcOffset;
978     uintptr_t framePc = 0;
979     uintptr_t frameBytecode = 0;
980     if (!ReadUintptrFromAddr(pid, currentPtr, framePc, false)) {
981         return false;
982     }
983     if (!ReadUintptrFromAddr(pid, framePc, frameBytecode, false)) {
984         return false;
985     }
986     CopyBytecodeInfoToBuffer(" FrameBytecode:", frameBytecode, strIndex, outStr, strLen);
987     if (outJSInfo) {
988         uintptr_t functionOffset = MEMBER_OFFSET(AsmInterpretedFrame, function);
989         currentPtr -= pcOffset;
990         currentPtr += functionOffset;
991         uintptr_t functionAddress = 0;
992         if (!ReadUintptrFromAddr(pid, currentPtr, functionAddress, false)) {
993             return false;
994         }
995         JSTaggedValue functionValue(static_cast<JSTaggedType>(functionAddress));
996         Method *method = ECMAObject::Cast(functionValue.GetTaggedObject())->GetCallTarget();
997         auto bytecodeOffset = static_cast<uint32_t>(reinterpret_cast<uint8_t *>(*bytecodePc) -
998                                                     method->GetBytecodeArray());
999         std::string info = JsStackInfo::BuildMethodTrace(method, bytecodeOffset);
1000         const char *infoChar = info.c_str();
1001         if (strIndex < strLen - 1) {  // 1: last '\0'
1002             outStr[strIndex++] = ' ';
1003         }
1004         for (size_t i = 0; infoChar[i] != '\0' && strIndex < strLen - 1; i++) {  // 1: last '\0'
1005             outStr[strIndex++] = infoChar[i];
1006         }
1007         outStr[strIndex] = '\0';
1008     }
1009     return true;
1010 }
1011 } // namespace panda::ecmascript
1012 
step_ark_managed_native_frame(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,char * buf,size_t buf_sz)1013 __attribute__((visibility("default"))) int step_ark_managed_native_frame(
1014     int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, char *buf, size_t buf_sz)
1015 {
1016     if (panda::ecmascript::StepArkManagedNativeFrame(pid, pc, fp, sp, buf, buf_sz)) {
1017         return 1;
1018     }
1019     return -1;
1020 }
1021 
get_ark_js_heap_crash_info(int pid,uintptr_t * x20,uintptr_t * fp,int outJsInfo,char * buf,size_t buf_sz)1022 __attribute__((visibility("default"))) int get_ark_js_heap_crash_info(
1023     int pid, uintptr_t *x20, uintptr_t *fp, int outJsInfo, char *buf, size_t buf_sz)
1024 {
1025     if (panda::ecmascript::GetArkJSHeapCrashInfo(pid, x20, fp, outJsInfo != 0, buf, buf_sz)) {
1026         return 1;
1027     }
1028     return -1;
1029 }
1030 
1031 #if defined(PANDA_TARGET_OHOS)
get_ark_native_frame_info(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,panda::ecmascript::JsFrame * jsFrame,size_t & size)1032 __attribute__((visibility("default"))) int get_ark_native_frame_info(int pid, uintptr_t *pc,
1033     uintptr_t *fp, uintptr_t *sp, panda::ecmascript::JsFrame *jsFrame, size_t &size)
1034 {
1035     if (GetArkNativeFrameInfo(pid, pc, fp, sp, jsFrame, size)) {
1036         LOG_ECMA(INFO) << "get_ark_native_frame_info success.";
1037         return 1;
1038     }
1039     return -1;
1040 }
1041 #endif