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,bool needCheckRegion)222 bool ReadUintptrFromAddr(int pid, uintptr_t addr, uintptr_t &value, bool needCheckRegion)
223 {
224 if (pid == getpid()) {
225 if (needCheckRegion) {
226 bool flag = false;
227 auto callback = [addr, &flag](Region *region) {
228 uintptr_t regionBegin = region->GetBegin();
229 uintptr_t regionEnd = region->GetEnd();
230 if (regionBegin <= addr && addr <= regionEnd) {
231 flag = true;
232 }
233 };
234 if (JsStackInfo::loader != nullptr) {
235 const Heap *heap = JsStackInfo::loader->GetHeap();
236 if (heap != nullptr) {
237 heap->EnumerateRegions(callback);
238 }
239 }
240 if (!flag) {
241 LOG_ECMA(ERROR) << "addr not in Region, addr: " << addr;
242 return false;
243 }
244 }
245 value = *(reinterpret_cast<uintptr_t *>(addr));
246 return true;
247 }
248 long *retAddr = reinterpret_cast<long *>(&value);
249 // note: big endian
250 for (size_t i = 0; i < sizeof(uintptr_t) / sizeof(long); i++) {
251 *retAddr = PtracePeektext(pid, addr);
252 if (*retAddr == -1) {
253 LOG_ECMA(ERROR) << "ReadFromAddr ERROR, addr: " << addr;
254 return false;
255 }
256 addr += sizeof(long);
257 retAddr++;
258 }
259 return true;
260 }
261
GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType,uintptr_t & typeOffset,uintptr_t & prevOffset)262 bool GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType, uintptr_t &typeOffset, uintptr_t &prevOffset)
263 {
264 FrameType type = static_cast<FrameType>(frameType);
265 switch (type) {
266 case FrameType::OPTIMIZED_FRAME:
267 typeOffset = OptimizedFrame::GetTypeOffset();
268 prevOffset = OptimizedFrame::GetPrevOffset();
269 break;
270 case FrameType::OPTIMIZED_ENTRY_FRAME:
271 typeOffset = OptimizedEntryFrame::GetTypeOffset();
272 prevOffset = OptimizedEntryFrame::GetLeaveFrameFpOffset();
273 break;
274 case FrameType::ASM_BRIDGE_FRAME:
275 typeOffset = AsmBridgeFrame::GetTypeOffset();
276 prevOffset = AsmBridgeFrame::GetPrevOffset();
277 break;
278 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
279 typeOffset = OptimizedJSFunctionUnfoldArgVFrame::GetTypeOffset();
280 prevOffset = OptimizedJSFunctionUnfoldArgVFrame::GetPrevOffset();
281 break;
282 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
283 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
284 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME:
285 typeOffset = OptimizedJSFunctionFrame::GetTypeOffset();
286 prevOffset = OptimizedJSFunctionFrame::GetPrevOffset();
287 break;
288 case FrameType::LEAVE_FRAME:
289 typeOffset = OptimizedLeaveFrame::GetTypeOffset();
290 prevOffset = OptimizedLeaveFrame::GetPrevOffset();
291 break;
292 case FrameType::LEAVE_FRAME_WITH_ARGV:
293 typeOffset = OptimizedWithArgvLeaveFrame::GetTypeOffset();
294 prevOffset = OptimizedWithArgvLeaveFrame::GetPrevOffset();
295 break;
296 case FrameType::BUILTIN_CALL_LEAVE_FRAME:
297 typeOffset = OptimizedBuiltinLeaveFrame::GetTypeOffset();
298 prevOffset = OptimizedBuiltinLeaveFrame::GetPrevOffset();
299 break;
300 case FrameType::INTERPRETER_FRAME:
301 case FrameType::INTERPRETER_FAST_NEW_FRAME:
302 typeOffset = InterpretedFrame::GetTypeOffset();
303 prevOffset = InterpretedFrame::GetPrevOffset();
304 break;
305 case FrameType::INTERPRETER_BUILTIN_FRAME:
306 typeOffset = InterpretedBuiltinFrame::GetTypeOffset();
307 prevOffset = InterpretedBuiltinFrame::GetPrevOffset();
308 break;
309 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME:
310 case FrameType::ASM_INTERPRETER_FRAME:
311 typeOffset = AsmInterpretedFrame::GetTypeOffset();
312 prevOffset = AsmInterpretedFrame::GetPrevOffset();
313 break;
314 case FrameType::BUILTIN_FRAME:
315 case FrameType::BUILTIN_ENTRY_FRAME:
316 typeOffset = BuiltinFrame::GetTypeOffset();
317 prevOffset = BuiltinFrame::GetPrevOffset();
318 break;
319 case FrameType::BUILTIN_FRAME_WITH_ARGV:
320 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME:
321 typeOffset = BuiltinWithArgvFrame::GetTypeOffset();
322 prevOffset = BuiltinWithArgvFrame::GetPrevOffset();
323 break;
324 case FrameType::INTERPRETER_ENTRY_FRAME:
325 typeOffset = InterpretedEntryFrame::GetTypeOffset();
326 prevOffset = InterpretedEntryFrame::GetPrevOffset();
327 break;
328 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
329 typeOffset = AsmInterpretedEntryFrame::GetTypeOffset();
330 prevOffset = AsmInterpretedEntryFrame::GetPrevOffset();
331 break;
332 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
333 typeOffset = AsmInterpretedBridgeFrame::GetTypeOffset();
334 prevOffset = AsmInterpretedBridgeFrame::GetPrevOffset();
335 break;
336 default:
337 return false;
338 }
339 return true;
340 }
341
StepArkManagedNativeFrame(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,char * buf,size_t bufSize)342 bool StepArkManagedNativeFrame(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp,
343 [[maybe_unused]] char *buf, [[maybe_unused]] size_t bufSize)
344 {
345 constexpr size_t FP_SIZE = 8;
346 constexpr size_t LR_SIZE = 8;
347 uintptr_t currentPtr = *fp;
348 if (currentPtr == 0) {
349 LOG_ECMA(ERROR) << "fp is nullptr in StepArkManagedNativeFrame()!";
350 return false;
351 }
352 if (pid == getpid() && JsStackInfo::loader != nullptr &&
353 !JsStackInfo::loader->InsideStub(*pc) && !JsStackInfo::loader->InsideAOT(*pc)) {
354 LOG_ECMA(ERROR) << "invalid pc in StepArkManagedNativeFrame()!";
355 return false;
356 }
357 while (true) {
358 currentPtr -= sizeof(FrameType);
359 uintptr_t frameType = 0;
360 if (!ReadUintptrFromAddr(pid, currentPtr, frameType, true)) {
361 return false;
362 }
363 uintptr_t typeOffset = 0;
364 uintptr_t prevOffset = 0;
365 if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) {
366 LOG_ECMA(ERROR) << "FrameType ERROR, addr: " << currentPtr << ", frameType: " << frameType;
367 return false;
368 }
369 if (static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_ENTRY_FRAME ||
370 static_cast<FrameType>(frameType) == FrameType::ASM_INTERPRETER_ENTRY_FRAME ||
371 static_cast<FrameType>(frameType) == FrameType::BUILTIN_ENTRY_FRAME) {
372 break;
373 }
374 currentPtr -= typeOffset;
375 currentPtr += prevOffset;
376 if (!ReadUintptrFromAddr(pid, currentPtr, currentPtr, true)) {
377 return false;
378 }
379 if (currentPtr == 0) {
380 LOG_ECMA(ERROR) << "currentPtr is nullptr in StepArkManagedNativeFrame()!";
381 return false;
382 }
383 }
384 currentPtr += sizeof(FrameType);
385 *fp = currentPtr;
386 currentPtr += FP_SIZE;
387 if (!ReadUintptrFromAddr(pid, currentPtr, *pc, true)) {
388 return false;
389 }
390 currentPtr += LR_SIZE;
391 *sp = currentPtr;
392 return true;
393 }
394
CopyBytecodeInfoToBuffer(const char * prefix,uintptr_t fullBytecode,size_t & strIdx,char * outStr,size_t strLen)395 void CopyBytecodeInfoToBuffer(const char *prefix, uintptr_t fullBytecode, size_t &strIdx, char *outStr, size_t strLen)
396 {
397 // note: big endian
398 for (size_t i = 0; prefix[i] != '\0' && strIdx < strLen - 1; i++) { // 1: last '\0'
399 outStr[strIdx++] = prefix[i];
400 }
401 size_t start = static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleLdundefined));
402 size_t bytecode = fullBytecode & 0xff; // 0xff: last byte
403 const char *bytecodeName = MessageString::GetMessageString(start + bytecode).c_str();
404 for (size_t i = 0; bytecodeName[i] != '\0' && strIdx < strLen - 1; i++) { // 1: last '\0'
405 outStr[strIdx++] = bytecodeName[i];
406 }
407 if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleDeprecated)) ||
408 start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleWide)) ||
409 start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleThrow)) ||
410 start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleCallRuntime))) {
411 size_t startSecond = start;
412 if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleDeprecated))) {
413 startSecond = static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleDeprecatedLdlexenvPrefNone));
414 } else if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleWide))) {
415 startSecond = static_cast<size_t>(GET_MESSAGE_STRING_ID(
416 HandleWideCreateobjectwithexcludedkeysPrefImm16V8V8));
417 } else if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleThrow))) {
418 startSecond = static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleThrowPrefNone));
419 } else if (start + bytecode == static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleCallRuntime))) {
420 startSecond = static_cast<size_t>(GET_MESSAGE_STRING_ID(HandleCallRuntimeNotifyConcurrentResultPrefNone));
421 }
422 size_t bytecodeSecond = (fullBytecode >> 8) & 0xff; // 8, 0xff: second last byte
423 const char *bytecodeNameSecond = MessageString::GetMessageString(startSecond + bytecodeSecond).c_str();
424 if (strIdx < strLen - 1) { // 1: last '\0'
425 outStr[strIdx++] = '/';
426 }
427 for (size_t i = 0; bytecodeNameSecond[i] != '\0' && strIdx < strLen - 1; i++) { // 1: last '\0'
428 outStr[strIdx++] = bytecodeNameSecond[i];
429 }
430 }
431 outStr[strIdx] = '\0';
432 }
433
GetArkJSHeapCrashInfo(int pid,uintptr_t * bytecodePc,uintptr_t * fp,bool outJSInfo,char * outStr,size_t strLen)434 bool GetArkJSHeapCrashInfo(int pid, uintptr_t *bytecodePc, uintptr_t *fp, bool outJSInfo, char *outStr, size_t strLen)
435 {
436 // bytecodePc: X20 in ARM
437 // fp: X29 in ARM
438 // outJSInfo: not async-safe, more info
439 uintptr_t currentPtr = *fp;
440 if (currentPtr == 0) {
441 LOG_ECMA(ERROR) << "fp is nullptr in GetArkJSHeapCrashInfo()!";
442 return false;
443 }
444 currentPtr -= sizeof(FrameType);
445 uintptr_t frameType = 0;
446 if (!ReadUintptrFromAddr(pid, currentPtr, frameType, false)) {
447 return false;
448 }
449 if (static_cast<FrameType>(frameType) != FrameType::ASM_INTERPRETER_FRAME) {
450 return false;
451 }
452 size_t strIndex = 0;
453 uintptr_t registerBytecode = 0;
454 if (!ReadUintptrFromAddr(pid, *bytecodePc, registerBytecode, false)) {
455 return false;
456 }
457 CopyBytecodeInfoToBuffer("RegisterBytecode:", registerBytecode, strIndex, outStr, strLen);
458 uintptr_t typeOffset = MEMBER_OFFSET(AsmInterpretedFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, type);
459 uintptr_t pcOffset = MEMBER_OFFSET(AsmInterpretedFrame, pc);
460 currentPtr -= typeOffset;
461 currentPtr += pcOffset;
462 uintptr_t framePc = 0;
463 uintptr_t frameBytecode = 0;
464 if (!ReadUintptrFromAddr(pid, currentPtr, framePc, false)) {
465 return false;
466 }
467 if (!ReadUintptrFromAddr(pid, framePc, frameBytecode, false)) {
468 return false;
469 }
470 CopyBytecodeInfoToBuffer(" FrameBytecode:", frameBytecode, strIndex, outStr, strLen);
471 if (outJSInfo) {
472 uintptr_t functionOffset = MEMBER_OFFSET(AsmInterpretedFrame, function);
473 currentPtr -= pcOffset;
474 currentPtr += functionOffset;
475 uintptr_t functionAddress = 0;
476 if (!ReadUintptrFromAddr(pid, currentPtr, functionAddress, false)) {
477 return false;
478 }
479 JSTaggedValue functionValue(static_cast<JSTaggedType>(functionAddress));
480 Method *method = ECMAObject::Cast(functionValue.GetTaggedObject())->GetCallTarget();
481 auto bytecodeOffset = static_cast<uint32_t>(reinterpret_cast<uint8_t *>(*bytecodePc) -
482 method->GetBytecodeArray());
483 std::string info = JsStackInfo::BuildMethodTrace(method, bytecodeOffset);
484 const char *infoChar = info.c_str();
485 if (strIndex < strLen - 1) { // 1: last '\0'
486 outStr[strIndex++] = ' ';
487 }
488 for (size_t i = 0; infoChar[i] != '\0' && strIndex < strLen - 1; i++) { // 1: last '\0'
489 outStr[strIndex++] = infoChar[i];
490 }
491 outStr[strIndex] = '\0';
492 }
493 return true;
494 }
495 } // namespace panda::ecmascript
496
step_ark_managed_native_frame(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,char * buf,size_t buf_sz)497 __attribute__((visibility("default"))) int step_ark_managed_native_frame(
498 int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, char *buf, size_t buf_sz)
499 {
500 if (panda::ecmascript::StepArkManagedNativeFrame(pid, pc, fp, sp, buf, buf_sz)) {
501 return 1;
502 }
503 return -1;
504 }
505
get_ark_js_heap_crash_info(int pid,uintptr_t * x20,uintptr_t * fp,int outJsInfo,char * buf,size_t buf_sz)506 __attribute__((visibility("default"))) int get_ark_js_heap_crash_info(
507 int pid, uintptr_t *x20, uintptr_t *fp, int outJsInfo, char *buf, size_t buf_sz)
508 {
509 if (panda::ecmascript::GetArkJSHeapCrashInfo(pid, x20, fp, outJsInfo != 0, buf, buf_sz)) {
510 return 1;
511 }
512 return -1;
513 }