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 ¤tPtr, 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