1 /*
2 * Copyright (c) 2022 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/message_string.h"
23 #include "ecmascript/platform/os.h"
24 #if defined(ENABLE_EXCEPTION_BACKTRACE)
25 #include "ecmascript/platform/backtrace.h"
26 #endif
27
28 namespace panda::ecmascript {
BuildMethodTrace(Method * method,uint32_t pcOffset)29 std::string JsStackInfo::BuildMethodTrace(Method *method, uint32_t pcOffset)
30 {
31 std::string data;
32 data.append(" at ");
33 std::string name = method->ParseFunctionName();
34 if (name.empty()) {
35 name = "anonymous";
36 }
37 data += name;
38 data.append(" (");
39 // source file
40 DebugInfoExtractor *debugExtractor =
41 JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile());
42 const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
43 if (sourceFile.empty()) {
44 data.push_back('?');
45 } else {
46 data += sourceFile;
47 }
48 data.push_back(':');
49 // line number and column number
50 auto callbackLineFunc = [&data](int32_t line) -> bool {
51 data += std::to_string(line + 1);
52 data.push_back(':');
53 return true;
54 };
55 auto callbackColumnFunc = [&data](int32_t column) -> bool {
56 data += std::to_string(column + 1);
57 return true;
58 };
59 panda_file::File::EntityId methodId = method->GetMethodId();
60 if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, pcOffset) ||
61 !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, pcOffset)) {
62 data.push_back('?');
63 }
64 data.push_back(')');
65 data.push_back('\n');
66 return data;
67 }
68
BuildJsStackTrace(JSThread * thread,bool needNative)69 std::string JsStackInfo::BuildJsStackTrace(JSThread *thread, bool needNative)
70 {
71 std::string data;
72 JSTaggedType *current = const_cast<JSTaggedType *>(thread->GetCurrentFrame());
73 FrameIterator it(current, thread);
74 for (; !it.Done(); it.Advance<GCVisitedFlag::VISITED>()) {
75 if (!it.IsJSFrame()) {
76 continue;
77 }
78 auto method = it.CheckAndGetMethod();
79 if (method == nullptr) {
80 continue;
81 }
82 if (!method->IsNativeWithCallField()) {
83 auto pcOffset = it.GetBytecodeOffset();
84 data += BuildMethodTrace(method, pcOffset);
85 } else if (needNative) {
86 auto addr = method->GetNativePointer();
87 std::stringstream strm;
88 strm << addr;
89 data.append(" at native method (").append(strm.str()).append(")\n");
90 }
91 }
92 if (data.empty()) {
93 #if defined(ENABLE_EXCEPTION_BACKTRACE)
94 std::ostringstream stack;
95 Backtrace(stack);
96 data = stack.str();
97 #endif
98 }
99 return data;
100 }
101
BuildJsStackInfo(JSThread * thread)102 std::vector<struct JsFrameInfo> JsStackInfo::BuildJsStackInfo(JSThread *thread)
103 {
104 std::vector<struct JsFrameInfo> jsFrame;
105 uintptr_t *native = nullptr;
106 JSTaggedType *current = const_cast<JSTaggedType *>(thread->GetCurrentFrame());
107 FrameIterator it(current, thread);
108 for (; !it.Done(); it.Advance<GCVisitedFlag::HYBRID_STACK>()) {
109 if (!it.IsJSFrame()) {
110 continue;
111 }
112 auto method = it.CheckAndGetMethod();
113 if (method == nullptr) {
114 continue;
115 }
116 struct JsFrameInfo frameInfo;
117 if (native != nullptr) {
118 frameInfo.nativePointer = native;
119 native = nullptr;
120 }
121 if (!method->IsNativeWithCallField()) {
122 std::string name = method->ParseFunctionName();
123 if (name.empty()) {
124 frameInfo.functionName = "anonymous";
125 } else {
126 frameInfo.functionName = name;
127 }
128 // source file
129 DebugInfoExtractor *debugExtractor =
130 JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile());
131 const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
132 if (sourceFile.empty()) {
133 frameInfo.fileName = "?";
134 } else {
135 frameInfo.fileName = sourceFile;
136 }
137 // line number and column number
138 int lineNumber = 0;
139 auto callbackLineFunc = [&frameInfo, &lineNumber](int32_t line) -> bool {
140 lineNumber = line + 1;
141 frameInfo.pos = std::to_string(lineNumber) + ":";
142 return true;
143 };
144 auto callbackColumnFunc = [&frameInfo](int32_t column) -> bool {
145 frameInfo.pos += std::to_string(column + 1);
146 return true;
147 };
148 panda_file::File::EntityId methodId = method->GetMethodId();
149 uint32_t offset = it.GetBytecodeOffset();
150 if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) ||
151 !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) {
152 frameInfo.pos = "?";
153 }
154 jsFrame.push_back(frameInfo);
155 } else {
156 JSTaggedValue function = it.GetFunction();
157 JSHandle<JSTaggedValue> extraInfoValue(
158 thread, JSFunction::Cast(function.GetTaggedObject())->GetFunctionExtraInfo());
159 if (extraInfoValue->IsJSNativePointer()) {
160 JSHandle<JSNativePointer> extraInfo(extraInfoValue);
161 native = reinterpret_cast<uintptr_t *>(extraInfo->GetExternalPointer());
162 }
163 }
164 }
165 return jsFrame;
166 }
167
CrashCallback(char * buf,size_t len,void * ucontext)168 void CrashCallback(char *buf __attribute__((unused)), size_t len __attribute__((unused)),
169 void *ucontext __attribute__((unused)))
170 {
171 #if defined(__aarch64__) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS)
172 if (ucontext == nullptr) {
173 // should not happen
174 return;
175 }
176 auto uctx = static_cast<ucontext_t *>(ucontext);
177 uintptr_t pc = uctx->uc_mcontext.pc;
178 uintptr_t fp = uctx->uc_mcontext.regs[29]; // 29: fp
179 // 1. check pc is between ark code heap
180 // 2. assemble crash info for ark code with signal-safe code
181 // 3. do not do much things inside callback, stack size is limited
182 // 4. do not use normal log
183 if (JsStackInfo::loader == nullptr) {
184 return;
185 }
186 if (!JsStackInfo::loader->InsideStub(pc) && !JsStackInfo::loader->InsideAOT(pc)) {
187 return;
188 }
189 LOG_ECMA(ERROR) << std::hex << "CrashCallback pc:" << pc << " fp:" << fp;
190 FrameIterator frame(reinterpret_cast<JSTaggedType *>(fp));
191 bool isBuiltinStub = (frame.GetFrameType() == FrameType::OPTIMIZED_FRAME);
192 Method *method = frame.CheckAndGetMethod();
193 while (method == nullptr) {
194 frame.Advance();
195 if (frame.Done()) {
196 break;
197 }
198 method = frame.CheckAndGetMethod();
199 }
200 std::string faultInfo;
201 if (method != nullptr) {
202 std::string methodName = method->GetMethodName();
203 std::string recordName = method->GetRecordName().c_str();
204 faultInfo = "Method Name:" + methodName + " Record Name:" + recordName;
205 } else {
206 faultInfo = "method is nullptr!";
207 }
208 if (isBuiltinStub) {
209 uintptr_t func = uctx->uc_mcontext.regs[2]; // 2: func
210 JSTaggedValue builtinMethod = JSFunction::Cast(reinterpret_cast<TaggedObject *>(func))->GetMethod();
211 uint8_t builtinId = Method::Cast(builtinMethod.GetTaggedObject())->GetBuiltinId();
212 size_t builtinStart = static_cast<size_t>(GET_MESSAGE_STRING_ID(CharCodeAt) - 1); // 1: offset NONE
213 std::string builtinStr = MessageString::GetMessageString(builtinStart + builtinId);
214 faultInfo += " " + builtinStr;
215 }
216 if (memcpy_s(buf, len, faultInfo.c_str(), faultInfo.length()) != EOK) {
217 LOG_ECMA(ERROR) << "memcpy_s fail in CrashCallback()!"; // not FATAL to avoid further crash
218 }
219 #endif
220 }
221
ReadUintptrFromAddr(int pid,uintptr_t addr,uintptr_t & value)222 bool ReadUintptrFromAddr(int pid, uintptr_t addr, uintptr_t &value)
223 {
224 if (pid == getpid()) {
225 value = *(reinterpret_cast<uintptr_t *>(addr));
226 return true;
227 }
228 long *retAddr = reinterpret_cast<long *>(&value);
229 // note: big endian
230 for (size_t i = 0; i < sizeof(uintptr_t) / sizeof(long); i++) {
231 *retAddr = PtracePeektext(pid, addr);
232 if (*retAddr == -1) {
233 LOG_ECMA(ERROR) << "ReadFromAddr ERROR, addr: " << addr;
234 return false;
235 }
236 addr += sizeof(long);
237 retAddr++;
238 }
239 return true;
240 }
241
GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType,uintptr_t & typeOffset,uintptr_t & prevOffset)242 bool GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType, uintptr_t &typeOffset, uintptr_t &prevOffset)
243 {
244 FrameType type = static_cast<FrameType>(frameType);
245 switch (type) {
246 case FrameType::OPTIMIZED_FRAME:
247 typeOffset = OptimizedFrame::GetTypeOffset();
248 prevOffset = OptimizedFrame::GetPrevOffset();
249 break;
250 case FrameType::OPTIMIZED_ENTRY_FRAME:
251 typeOffset = OptimizedEntryFrame::GetTypeOffset();
252 prevOffset = OptimizedEntryFrame::GetLeaveFrameFpOffset();
253 break;
254 case FrameType::ASM_BRIDGE_FRAME:
255 typeOffset = AsmBridgeFrame::GetTypeOffset();
256 prevOffset = AsmBridgeFrame::GetPrevOffset();
257 break;
258 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
259 typeOffset = OptimizedJSFunctionUnfoldArgVFrame::GetTypeOffset();
260 prevOffset = OptimizedJSFunctionUnfoldArgVFrame::GetPrevOffset();
261 break;
262 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
263 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
264 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME:
265 typeOffset = OptimizedJSFunctionFrame::GetTypeOffset();
266 prevOffset = OptimizedJSFunctionFrame::GetPrevOffset();
267 break;
268 case FrameType::LEAVE_FRAME:
269 typeOffset = OptimizedLeaveFrame::GetTypeOffset();
270 prevOffset = OptimizedLeaveFrame::GetPrevOffset();
271 break;
272 case FrameType::LEAVE_FRAME_WITH_ARGV:
273 typeOffset = OptimizedWithArgvLeaveFrame::GetTypeOffset();
274 prevOffset = OptimizedWithArgvLeaveFrame::GetPrevOffset();
275 break;
276 case FrameType::BUILTIN_CALL_LEAVE_FRAME:
277 typeOffset = OptimizedBuiltinLeaveFrame::GetTypeOffset();
278 prevOffset = OptimizedBuiltinLeaveFrame::GetPrevOffset();
279 break;
280 case FrameType::INTERPRETER_FRAME:
281 case FrameType::INTERPRETER_FAST_NEW_FRAME:
282 typeOffset = InterpretedFrame::GetTypeOffset();
283 prevOffset = InterpretedFrame::GetPrevOffset();
284 break;
285 case FrameType::INTERPRETER_BUILTIN_FRAME:
286 typeOffset = InterpretedBuiltinFrame::GetTypeOffset();
287 prevOffset = InterpretedBuiltinFrame::GetPrevOffset();
288 break;
289 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME:
290 case FrameType::ASM_INTERPRETER_FRAME:
291 typeOffset = AsmInterpretedFrame::GetTypeOffset();
292 prevOffset = AsmInterpretedFrame::GetPrevOffset();
293 break;
294 case FrameType::BUILTIN_FRAME:
295 case FrameType::BUILTIN_ENTRY_FRAME:
296 typeOffset = BuiltinFrame::GetTypeOffset();
297 prevOffset = BuiltinFrame::GetPrevOffset();
298 break;
299 case FrameType::BUILTIN_FRAME_WITH_ARGV:
300 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME:
301 typeOffset = BuiltinWithArgvFrame::GetTypeOffset();
302 prevOffset = BuiltinWithArgvFrame::GetPrevOffset();
303 break;
304 case FrameType::INTERPRETER_ENTRY_FRAME:
305 typeOffset = InterpretedEntryFrame::GetTypeOffset();
306 prevOffset = InterpretedEntryFrame::GetPrevOffset();
307 break;
308 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
309 typeOffset = AsmInterpretedEntryFrame::GetTypeOffset();
310 prevOffset = AsmInterpretedEntryFrame::GetPrevOffset();
311 break;
312 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
313 typeOffset = AsmInterpretedBridgeFrame::GetTypeOffset();
314 prevOffset = AsmInterpretedBridgeFrame::GetPrevOffset();
315 break;
316 default:
317 return false;
318 }
319 return true;
320 }
321
StepArkManagedNativeFrame(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,char * buf,size_t bufSize)322 bool StepArkManagedNativeFrame(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp,
323 [[maybe_unused]] char *buf, [[maybe_unused]] size_t bufSize)
324 {
325 constexpr size_t FP_SIZE = 8;
326 constexpr size_t LR_SIZE = 8;
327 uintptr_t currentPtr = *fp;
328 if (currentPtr == 0) {
329 LOG_ECMA(ERROR) << "fp is nullptr in StepArkManagedNativeFrame()!";
330 return false;
331 }
332 while (true) {
333 currentPtr -= sizeof(FrameType);
334 uintptr_t frameType = 0;
335 if (!ReadUintptrFromAddr(pid, currentPtr, frameType)) {
336 return false;
337 }
338 uintptr_t typeOffset = 0;
339 uintptr_t prevOffset = 0;
340 if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) {
341 LOG_ECMA(ERROR) << "FrameType ERROR, addr: " << currentPtr << ", frameType: " << frameType;
342 return false;
343 }
344 if (static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_ENTRY_FRAME ||
345 static_cast<FrameType>(frameType) == FrameType::ASM_INTERPRETER_ENTRY_FRAME ||
346 static_cast<FrameType>(frameType) == FrameType::BUILTIN_ENTRY_FRAME) {
347 break;
348 }
349 currentPtr -= typeOffset;
350 currentPtr += prevOffset;
351 if (!ReadUintptrFromAddr(pid, currentPtr, currentPtr)) {
352 return false;
353 }
354 if (currentPtr == 0) {
355 LOG_ECMA(ERROR) << "currentPtr is nullptr in StepArkManagedNativeFrame()!";
356 return false;
357 }
358 }
359 currentPtr += sizeof(FrameType);
360 *fp = currentPtr;
361 currentPtr += FP_SIZE;
362 if (!ReadUintptrFromAddr(pid, currentPtr, *pc)) {
363 return false;
364 }
365 currentPtr += LR_SIZE;
366 *sp = currentPtr;
367 return true;
368 }
369
CopyBytecodeInfoToBuffer(const char * prefix,uintptr_t fullBytecode,size_t & strIdx,char * outStr,size_t strLen)370 void CopyBytecodeInfoToBuffer(const char *prefix, uintptr_t fullBytecode, size_t &strIdx, char *outStr, size_t strLen)
371 {
372 // note: big endian
373 for (size_t i = 0; prefix[i] != '\0' && strIdx < strLen - 1; i++) { // 1: last '\0'
374 outStr[strIdx++] = prefix[i];
375 }
376 size_t start = static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleLdundefined));
377 size_t bytecode = fullBytecode & 0xff; // 0xff: last byte
378 const char *bytecodeName = MessageString::GetMessageString(start + bytecode).c_str();
379 for (size_t i = 0; bytecodeName[i] != '\0' && strIdx < strLen - 1; i++) { // 1: last '\0'
380 outStr[strIdx++] = bytecodeName[i];
381 }
382 if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleDeprecated)) ||
383 start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleWide)) ||
384 start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleThrow)) ||
385 start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleCallRuntime))) {
386 size_t startSecond = start;
387 if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleDeprecated))) {
388 startSecond = static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleDeprecatedLdlexenvPrefNone));
389 } else if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleWide))) {
390 startSecond = static_cast<size_t>(GET_MESSAGE_STRING_ID(
391 HandleWideCreateobjectwithexcludedkeysPrefImm16V8V8));
392 } else if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleThrow))) {
393 startSecond = static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleThrowPrefNone));
394 } else if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleCallRuntime))) {
395 startSecond = static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleCallRuntimeNotifyConcurrentResultPrefNone));
396 }
397 size_t bytecodeSecond = (fullBytecode >> 8) & 0xff; // 8, 0xff: second last byte
398 const char *bytecodeNameSecond = MessageString::GetMessageString(startSecond + bytecodeSecond).c_str();
399 if (strIdx < strLen - 1) { // 1: last '\0'
400 outStr[strIdx++] = '/';
401 }
402 for (size_t i = 0; bytecodeNameSecond[i] != '\0' && strIdx < strLen - 1; i++) { // 1: last '\0'
403 outStr[strIdx++] = bytecodeNameSecond[i];
404 }
405 }
406 outStr[strIdx] = '\0';
407 }
408
GetArkJSHeapCrashInfo(int pid,uintptr_t * bytecodePc,uintptr_t * fp,bool outJSInfo,char * outStr,size_t strLen)409 bool GetArkJSHeapCrashInfo(int pid, uintptr_t *bytecodePc, uintptr_t *fp, bool outJSInfo, char *outStr, size_t strLen)
410 {
411 // bytecodePc: X20 in ARM
412 // fp: X29 in ARM
413 // outJSInfo: not async-safe, more info
414 uintptr_t currentPtr = *fp;
415 if (currentPtr == 0) {
416 LOG_ECMA(ERROR) << "fp is nullptr in GetArkJSHeapCrashInfo()!";
417 return false;
418 }
419 currentPtr -= sizeof(FrameType);
420 uintptr_t frameType = 0;
421 if (!ReadUintptrFromAddr(pid, currentPtr, frameType)) {
422 return false;
423 }
424 if (static_cast<FrameType>(frameType) != FrameType::ASM_INTERPRETER_FRAME) {
425 return false;
426 }
427 size_t strIndex = 0;
428 uintptr_t registerBytecode = 0;
429 if (!ReadUintptrFromAddr(pid, *bytecodePc, registerBytecode)) {
430 return false;
431 }
432 CopyBytecodeInfoToBuffer("RegisterBytecode:", registerBytecode, strIndex, outStr, strLen);
433 uintptr_t typeOffset = MEMBER_OFFSET(AsmInterpretedFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, type);
434 uintptr_t pcOffset = MEMBER_OFFSET(AsmInterpretedFrame, pc);
435 currentPtr -= typeOffset;
436 currentPtr += pcOffset;
437 uintptr_t framePc = 0;
438 uintptr_t frameBytecode = 0;
439 if (!ReadUintptrFromAddr(pid, currentPtr, framePc)) {
440 return false;
441 }
442 if (!ReadUintptrFromAddr(pid, framePc, frameBytecode)) {
443 return false;
444 }
445 CopyBytecodeInfoToBuffer(" FrameBytecode:", frameBytecode, strIndex, outStr, strLen);
446 if (outJSInfo) {
447 uintptr_t functionOffset = MEMBER_OFFSET(AsmInterpretedFrame, function);
448 currentPtr -= pcOffset;
449 currentPtr += functionOffset;
450 uintptr_t functionAddress = 0;
451 if (!ReadUintptrFromAddr(pid, currentPtr, functionAddress)) {
452 return false;
453 }
454 JSTaggedValue functionValue(static_cast<JSTaggedType>(functionAddress));
455 Method *method = ECMAObject::Cast(functionValue.GetTaggedObject())->GetCallTarget();
456 auto bytecodeOffset = static_cast<uint32_t>(reinterpret_cast<uint8_t *>(*bytecodePc) -
457 method->GetBytecodeArray());
458 std::string info = JsStackInfo::BuildMethodTrace(method, bytecodeOffset);
459 const char *infoChar = info.c_str();
460 if (strIndex < strLen - 1) { // 1: last '\0'
461 outStr[strIndex++] = ' ';
462 }
463 for (size_t i = 0; infoChar[i] != '\0' && strIndex < strLen - 1; i++) { // 1: last '\0'
464 outStr[strIndex++] = infoChar[i];
465 }
466 outStr[strIndex] = '\0';
467 }
468 return true;
469 }
470 } // namespace panda::ecmascript
471
step_ark_managed_native_frame(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,char * buf,size_t buf_sz)472 __attribute__((visibility("default"))) int step_ark_managed_native_frame(
473 int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, char *buf, size_t buf_sz)
474 {
475 if (panda::ecmascript::StepArkManagedNativeFrame(pid, pc, fp, sp, buf, buf_sz)) {
476 return 1;
477 }
478 return -1;
479 }
480
get_ark_js_heap_crash_info(int pid,uintptr_t * x20,uintptr_t * fp,int outJsInfo,char * buf,size_t buf_sz)481 __attribute__((visibility("default"))) int get_ark_js_heap_crash_info(
482 int pid, uintptr_t *x20, uintptr_t *fp, int outJsInfo, char *buf, size_t buf_sz)
483 {
484 if (panda::ecmascript::GetArkJSHeapCrashInfo(pid, x20, fp, outJsInfo != 0, buf, buf_sz)) {
485 return 1;
486 }
487 return -1;
488 }