/* * Copyright (c) 2024-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/dfx/stackinfo/tests/js_stackinfo_test.h" void unwind_user_finish(unwind_user_context_s *ctx) {} void mem_zero_s(unwind_stack_frame_s &frame) { frame.fp = 0; frame.pc = 0; } bool is_entry_frame(unsigned int frame_type) { return is_frame_type(frame_type, FRAME_TYPE_MAX, OPTIMIZED_ENTRY_FRAME, ASM_INTERPRETER_ENTRY_FRAME); } bool is_js_function_frame(unsigned int frame_type) { return is_frame_type(frame_type, FRAME_TYPE_MAX, ASM_INTERPRETER_FRAME, INTERPRETER_CONSTRUCTOR_FRAME, INTERPRETER_FRAME, INTERPRETER_FAST_NEW_FRAME); } bool is_native_function_frame(unsigned int frame_type) { return is_frame_type(frame_type, FRAME_TYPE_MAX, OPTIMIZED_FRAME, BASELINE_BUILTIN_FRAME, ASM_BRIDGE_FRAME, OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME, OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME, OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME, OPTIMIZED_JS_FUNCTION_FRAME, LEAVE_FRAME, LEAVE_FRAME_WITH_ARGV, BUILTIN_CALL_LEAVE_FRAME, BUILTIN_FRAME, BUILTIN_ENTRY_FRAME, BUILTIN_FRAME_WITH_ARGV, BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME, ASM_INTERPRETER_BRIDGE_FRAME); } uintptr_t calc_pc_addr_from_fp_addr(uintptr_t fp_addr, unsigned int frame_type) { uintptr_t type_addr = fp_addr - sizeof(uintptr_t); uintptr_t addr = type_addr - (uintptr_t)frame_offset_table64[frame_type].type_offset; addr += (uintptr_t)frame_offset_table64[frame_type].pc_offset; return addr; } uintptr_t calc_fp_addr_from_fp_addr(uintptr_t fp_addr, unsigned int frame_type) { uintptr_t type_addr = fp_addr - sizeof(uintptr_t); uintptr_t addr = type_addr - (uintptr_t)frame_offset_table64[frame_type].type_offset; addr += (uintptr_t)frame_offset_table64[frame_type].fp_offset; return addr; } uintptr_t clear_lazy_deopt_flag(uintptr_t frame_type_raw) { return (frame_type_raw & (uintptr_t)(~(1UL << LAZY_DEOPT_FLAG_BIT1))); } int next_ark_frame(unwind_user_context_s *ctx, uintptr_t fp_addr, unsigned int curr_frame_type, unwind_stack_frame_s *frame, bool *ret_frame_avail) { int err = E_OK; uintptr_t next_pc_addr = 0; uintptr_t next_fp_addr = 0; uintptr_t pc = 0UL; uintptr_t fp = 0UL; if (is_entry_frame(curr_frame_type)) { next_fp_addr = fp_addr; next_pc_addr = (uintptr_t)(fp_addr + sizeof(uintptr_t)); } else { if (is_js_function_frame(curr_frame_type) || is_native_function_frame(curr_frame_type)) { next_pc_addr = calc_pc_addr_from_fp_addr(fp_addr, curr_frame_type); } next_fp_addr = calc_fp_addr_from_fp_addr(fp_addr, curr_frame_type); } if (err == E_OK) { if (next_fp_addr != 0UL) { err = ctx->read_mem(ctx, next_fp_addr, &fp, sizeof(uintptr_t)); } if (err == E_OK && next_pc_addr != 0UL) { err = ctx->read_mem(ctx, next_pc_addr, &pc, sizeof(uintptr_t)); *ret_frame_avail = (err == E_OK); } frame->fp = fp; frame->pc = pc; } return err; } int next_ark_frame(unwind_user_context_s *ctx, uintptr_t fp_addr, unwind_stack_frame_s *frame, unsigned int *ret_frame_type) { int err = E_OK; uintptr_t frame_type = 0UL; while (err == E_OK) { bool frame_avail = false; uintptr_t type_addr = (uintptr_t)(fp_addr - sizeof(uintptr_t)); err = ctx->read_mem(ctx, type_addr, &frame_type, sizeof(uintptr_t)); if (err == E_OK) { frame_type = clear_lazy_deopt_flag(frame_type); if (frame_type > BASELINE_BUILTIN_FRAME) { err = E_INVAL; break; } } if (err == E_OK) { err = next_ark_frame(ctx, fp_addr, (unsigned int)frame_type, frame, &frame_avail); } if (err == E_OK) { fp_addr = frame->fp; if (frame_avail) { *ret_frame_type = (unsigned int)frame_type; break; } } } return err; } unwind_stack_frame_s step_ark_frame(unwind_user_context_s *ctx, const unwind_stack_frame_s *cur_frame) { unsigned int frame_type = 0U; unwind_stack_frame_s frame = UNWIND_FRAME_EMPTY; int err = E_OK; err = next_ark_frame(ctx, cur_frame->fp, &frame, &frame_type); if (err == E_OK) { if (is_entry_frame(frame_type) || !is_js_function_frame(frame_type)) { unwind_user_finish(ctx); } } if (err != E_OK) { mem_zero_s(frame); } return frame; } unwind_stack_frame_s unwind_arkts(unwind_user_context_s *context, const unwind_stack_frame_s *cur_frame) { unwind_stack_frame_s frame = UNWIND_FRAME_EMPTY; if (context != NULL && cur_frame != NULL) { frame = step_ark_frame(context, cur_frame); } return frame; }