From 51f70fe3a345046c7c443b6b64182abdae4cb038 Mon Sep 17 00:00:00 2001 From: yuhaoqiang Date: Tue, 29 Apr 2025 16:09:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Efp=5Fbacktrace=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuhaoqiang Change-Id: I2b189c493698773c8e5a3b118d54c7d9443de1d1 Signed-off-by: yuhaoqiang --- common/dfxutil/dfx_util.cpp | 20 ++ common/dfxutil/dfx_util.h | 1 + interfaces/innerkits/backtrace/BUILD.gn | 1 + .../innerkits/backtrace/fp_backtrace.cpp | 170 ++++++++++++++++ .../backtrace/include/fp_backtrace.h | 33 ++++ .../backtrace/libbacktrace_local.map | 1 + interfaces/innerkits/unwinder/dfx_ark.cpp | 181 +++++++----------- interfaces/innerkits/unwinder/dfx_maps.cpp | 14 ++ .../innerkits/unwinder/include/dfx_ark.h | 24 +++ .../innerkits/unwinder/include/dfx_maps.h | 4 +- interfaces/innerkits/unwinder/libunwinder.map | 4 + interfaces/innerkits/unwinder/unwinder.cpp | 22 +-- test/unittest/backtrace/BUILD.gn | 10 +- test/unittest/backtrace/fp_backtrace_test.cpp | 58 ++++++ 14 files changed, 403 insertions(+), 140 deletions(-) create mode 100644 interfaces/innerkits/backtrace/fp_backtrace.cpp create mode 100644 interfaces/innerkits/backtrace/include/fp_backtrace.h create mode 100644 test/unittest/backtrace/fp_backtrace_test.cpp diff --git a/common/dfxutil/dfx_util.cpp b/common/dfxutil/dfx_util.cpp index ff0830b17..c91ad2b52 100644 --- a/common/dfxutil/dfx_util.cpp +++ b/common/dfxutil/dfx_util.cpp @@ -200,6 +200,26 @@ bool ReadFdToString(int fd, std::string& content) } return (n == 0); } + +uintptr_t StripPac(uintptr_t inAddr, uintptr_t pacMask) +{ + uintptr_t outAddr = inAddr; +#if defined(__aarch64__) + if (outAddr != 0) { + if (pacMask != 0) { + outAddr &= ~pacMask; + } else { + register uint64_t x30 __asm("x30") = inAddr; + asm("hint 0x7" : "+r"(x30)); + outAddr = x30; + } + if (outAddr != inAddr) { + LOGU("Strip pac in addr: %lx, out addr: %lx", (uint64_t)inAddr, (uint64_t)outAddr); + } + } +#endif + return outAddr; +} } // namespace HiviewDFX } // namespace OHOS diff --git a/common/dfxutil/dfx_util.h b/common/dfxutil/dfx_util.h index 6ebf60295..075897469 100644 --- a/common/dfxutil/dfx_util.h +++ b/common/dfxutil/dfx_util.h @@ -40,6 +40,7 @@ AT_SYMBOL_HIDDEN void ParseSiValue(siginfo_t& si, uint64_t& endTime, int& tid); #endif AT_SYMBOL_HIDDEN off_t GetFileSize(const int& fd); AT_SYMBOL_HIDDEN bool ReadFdToString(int fd, std::string& content); +AT_SYMBOL_HIDDEN uintptr_t StripPac(uintptr_t inAddr, uintptr_t pacMask); } // nameapace HiviewDFX } // nameapace OHOS diff --git a/interfaces/innerkits/backtrace/BUILD.gn b/interfaces/innerkits/backtrace/BUILD.gn index 9465d6cc8..538a7ccc5 100644 --- a/interfaces/innerkits/backtrace/BUILD.gn +++ b/interfaces/innerkits/backtrace/BUILD.gn @@ -17,6 +17,7 @@ backtrace_local_sources = [ "backtrace_local.cpp", "backtrace_local_thread.cpp", "dfx_kernel_stack.cpp", + "fp_backtrace.cpp", ] if (defined(ohos_lite)) { diff --git a/interfaces/innerkits/backtrace/fp_backtrace.cpp b/interfaces/innerkits/backtrace/fp_backtrace.cpp new file mode 100644 index 000000000..307c38de9 --- /dev/null +++ b/interfaces/innerkits/backtrace/fp_backtrace.cpp @@ -0,0 +1,170 @@ +/* +* Copyright (c) 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 "fp_backtrace.h" + +#if is_ohos && !is_mingw +#include +#include + +#include "dfx_ark.h" +#include "dfx_log.h" +#include "dfx_maps.h" +#include "dfx_symbols.h" +#include "dfx_util.h" +#include "unwinder.h" +#endif + +namespace OHOS { +namespace HiviewDFX { + +#if is_ohos && !is_mingw && __aarch64__ +#undef LOG_DOMAIN +#undef LOG_TAG +#define LOG_TAG "FpBacktrace" +#define LOG_DOMAIN 0xD002D11 + +class FpBacktraceImpl : public FpBacktrace { +public: + bool Init(); + uint32_t BacktraceFromFp(void* startFp, void** pcArray, uint32_t size) override; + DfxFrame* SymbolicAddress(void* pc) override; +private: + bool ReadProcMem(const uint64_t addr, void* data, size_t size) const; + std::shared_ptr maps_ = nullptr; + Unwinder unwinder_{false}; + uintptr_t arkStubBegin_ = 0; + uintptr_t arkStubEnd_ = 0; + std::map> cachedFrames_; + bool withArk_ = false; + pid_t pid_ = 0; + std::mutex mutex_; +}; + +bool FpBacktraceImpl::ReadProcMem(const uint64_t addr, void* data, size_t size) const +{ + uint64_t currentAddr = addr; + if (__builtin_add_overflow(currentAddr, size, ¤tAddr)) { + return false; + } + struct iovec remoteIov = { + .iov_base = reinterpret_cast(addr), + .iov_len = size, + }; + struct iovec dataIov = { + .iov_base = static_cast(data), + .iov_len = size, + }; + ssize_t readCount = process_vm_readv(pid_, &dataIov, 1, &remoteIov, 1, 0); + return static_cast(readCount) == size; +} + +bool FpBacktraceImpl::Init() +{ + maps_ = DfxMaps::Create(0, false); + if (maps_ == nullptr) { + LOGE("failed creat maps"); + return false; + } + withArk_ = maps_->GetArkStackRange(arkStubBegin_, arkStubEnd_) && + DfxArk::InitArkFunction(ArkFunction::STEP_ARK); + pid_ = getpid(); + return true; +} + +uint32_t FpBacktraceImpl::BacktraceFromFp(void* startFp, void** pcArray, uint32_t size) +{ + uint32_t index = 0; + bool isJsFrame = false; + constexpr auto pcIndex = 1; + constexpr auto fpIndex = 0; + uintptr_t registerState[] = {reinterpret_cast(startFp), 0}; + uintptr_t sp = 0 ; + while (index < size) { + uintptr_t preFp = registerState[fpIndex] ; + if (isJsFrame || + (withArk_ && registerState[pcIndex] >= arkStubBegin_ && registerState[pcIndex] < arkStubEnd_)) { + DfxArk::StepArkFrame(this, [](void* fpBacktrace, uintptr_t addr, uintptr_t *val) { + return reinterpret_cast(fpBacktrace)->ReadProcMem(addr, val, sizeof(uintptr_t)); + }, ®isterState[fpIndex], &sp, ®isterState[pcIndex], nullptr, &isJsFrame); + } else { + if (!ReadProcMem(registerState[fpIndex], registerState, sizeof(registerState))) { + break; + } + } + constexpr auto pcBound = 0x1000; + if (registerState[pcIndex] <= pcBound) { + break; + } + auto realPc = reinterpret_cast(StripPac(registerState[pcIndex], 0)); + if (realPc != nullptr) { + pcArray[index++] = realPc; + } + if (registerState[fpIndex] <= preFp || registerState[fpIndex] == 0) { + break; + } + } + return index; +} + +DfxFrame* FpBacktraceImpl::SymbolicAddress(void* pc) +{ + std::unique_lock lock(mutex_); + auto cachedFrame = cachedFrames_.emplace(pc, nullptr); + auto& frame = cachedFrame.first->second; + if (!cachedFrame.second) { + return frame.get(); + } + frame = std::unique_ptr(new (std::nothrow) DfxFrame()); + if (!frame) { + return nullptr; + } + unwinder_.GetFrameByPc(reinterpret_cast(pc), maps_, *(frame)); + if (frame->map == nullptr) { + frame = nullptr; + return nullptr; + } + frame->mapName = frame->map->GetElfName(); + frame->relPc = frame->map->GetRelPc(frame->pc); + frame->mapOffset = frame->map->offset; + auto elf = frame->map->GetElf(); + if (elf == nullptr) { + unwinder_.FillJsFrame(*frame); + if (!frame->funcName.empty()) { + return frame.get(); + } + } + DfxSymbols::GetFuncNameAndOffsetByPc(frame->relPc, elf, frame->funcName, frame->funcOffset); + frame->buildId = elf->GetBuildId(); + return frame.get(); +} +#endif + +FpBacktrace* FpBacktrace::CreateInstance() +{ +#if is_ohos && !is_mingw && __aarch64__ + auto fpBacktraceImpl = new (std::nothrow) FpBacktraceImpl(); + if (fpBacktraceImpl == nullptr) { + return nullptr; + } + if (fpBacktraceImpl->Init()) { + return fpBacktraceImpl; + } + delete fpBacktraceImpl; +#endif + return nullptr; +} +} +} diff --git a/interfaces/innerkits/backtrace/include/fp_backtrace.h b/interfaces/innerkits/backtrace/include/fp_backtrace.h new file mode 100644 index 000000000..daf6666d1 --- /dev/null +++ b/interfaces/innerkits/backtrace/include/fp_backtrace.h @@ -0,0 +1,33 @@ +/* +* Copyright (c) 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. + */ + +#ifndef FP_BACKTRACE_H +#define FP_BACKTRACE_H + +#include "dfx_frame.h" + +namespace OHOS { +namespace HiviewDFX { +class FpBacktrace { +public: + static FpBacktrace* CreateInstance(); + virtual ~FpBacktrace() = default; + virtual uint32_t BacktraceFromFp(void* startFp, void** pcArray, uint32_t size) = 0; + virtual DfxFrame* SymbolicAddress(void* pc) = 0; +}; +} +} + +#endif //FP_BACKTRACE_H diff --git a/interfaces/innerkits/backtrace/libbacktrace_local.map b/interfaces/innerkits/backtrace/libbacktrace_local.map index 7db039d54..c3c7220e8 100644 --- a/interfaces/innerkits/backtrace/libbacktrace_local.map +++ b/interfaces/innerkits/backtrace/libbacktrace_local.map @@ -11,6 +11,7 @@ OHOS::HiviewDFX::DfxGetKernelStack*; OHOS::HiviewDFX::FormatThreadKernelStack*; OHOS::HiviewDFX::FormatProcessKernelStack*; + OHOS::HiviewDFX::FpBacktrace*; }; extern "C" { PrintTrace*; diff --git a/interfaces/innerkits/unwinder/dfx_ark.cpp b/interfaces/innerkits/unwinder/dfx_ark.cpp index e97f92c65..071968196 100644 --- a/interfaces/innerkits/unwinder/dfx_ark.cpp +++ b/interfaces/innerkits/unwinder/dfx_ark.cpp @@ -32,11 +32,9 @@ namespace { #undef LOG_TAG #define LOG_DOMAIN 0xD002D11 #define LOG_TAG "DfxArk" - -const char ARK_LIB_NAME[] = "libark_jsruntime.so"; - +constexpr auto ARK_LIB_NAME = "libark_jsruntime.so"; void* g_handle = nullptr; -pthread_mutex_t g_mutex; +std::mutex g_mutex; int (*g_getArkNativeFrameInfoFn)(int, uintptr_t*, uintptr_t*, uintptr_t*, JsFrame*, size_t&); int (*g_stepArkFn)(void*, OHOS::HiviewDFX::ReadMemFunc, uintptr_t*, uintptr_t*, uintptr_t*, uintptr_t*, bool*); int (*g_stepArkWithJitFn)(OHOS::HiviewDFX::ArkUnwindParam*); @@ -64,34 +62,63 @@ bool GetLibArkHandle() } } -#define DLSYM_ARK_FUNC(FuncName, DlsymFuncName) { \ - pthread_mutex_lock(&g_mutex); \ - do { \ - if ((DlsymFuncName) != nullptr) { \ - break; \ - } \ - if (!GetLibArkHandle()) { \ - break; \ - } \ - *(void**)(&(DlsymFuncName)) = dlsym(g_handle, (FuncName)); \ - if ((DlsymFuncName) == NULL) { \ - LOGE("Failed to dlsym(%s), error: %s", (FuncName), dlerror()); \ - break; \ - } \ - } while (false); \ - pthread_mutex_unlock(&g_mutex); \ +bool DlsymArkFunc(const char* funcName, void** dlsymFuncName) +{ + if (dlsymFuncName == nullptr) { + return false; + } + if (*dlsymFuncName != nullptr) { + return true; + } + if (!GetLibArkHandle()) { + return false; + } + *dlsymFuncName = dlsym(g_handle, (funcName)); + if (*dlsymFuncName == nullptr) { + LOGE("Failed to dlsym(%s), error: %s", funcName, dlerror()); + return false; + } + return true; } -int DfxArk::ArkCreateJsSymbolExtractor(uintptr_t* extractorPtr) +bool DfxArk::InitArkFunction(ArkFunction arkFunction) { - if (g_arkCreateJsSymbolExtractorFn != nullptr) { - return g_arkCreateJsSymbolExtractorFn(extractorPtr); + std::unique_lock lock(g_mutex); + switch (arkFunction) { + case ArkFunction::ARK_CREATE_JS_SYMBOL_EXTRACTOR: + return DlsymArkFunc("ark_create_js_symbol_extractor", + reinterpret_cast(&g_arkCreateJsSymbolExtractorFn)); + case ArkFunction::ARK_DESTORY_JS_SYMBOL_EXTRACTOR: + return DlsymArkFunc("ark_destory_js_symbol_extractor", + reinterpret_cast(&g_arkDestoryJsSymbolExtractorFn)); + case ArkFunction::ARK_CREATE_LOCAL: + return DlsymArkFunc("ark_create_local", reinterpret_cast(&g_arkCreateLocalFn)); + case ArkFunction::ARK_DESTROY_LOCAL: + return DlsymArkFunc("ark_destroy_local", reinterpret_cast(&g_arkDestroyLocalFn)); + case ArkFunction::ARK_PARSE_JS_FILE_INFO: + return DlsymArkFunc("ark_parse_js_file_info", reinterpret_cast(&g_parseArkFileInfoFn)); + case ArkFunction::ARK_PARSE_JS_FRAME_INFO_LOCAL: + return DlsymArkFunc("ark_parse_js_frame_info_local", reinterpret_cast(&g_parseArkFrameInfoLocalFn)); + case ArkFunction::ARK_PARSE_JS_FRAME_INFO: + return DlsymArkFunc("ark_parse_js_frame_info", reinterpret_cast(&g_parseArkFrameInfoFn)); + case ArkFunction::STEP_ARK: + return DlsymArkFunc("step_ark", reinterpret_cast(&g_stepArkFn)); + case ArkFunction::STEP_ARK_WITH_RECORD_JIT: + return DlsymArkFunc("step_ark_with_record_jit", reinterpret_cast(&g_stepArkWithJitFn)); + case ArkFunction::ARK_WRITE_JIT_CODE: + return DlsymArkFunc("ark_write_jit_code", reinterpret_cast(&g_jitCodeWriteFileFn)); + case ArkFunction::GET_ARK_NATIVE_FRAME_INFO: + return DlsymArkFunc("get_ark_native_frame_info", reinterpret_cast(&g_getArkNativeFrameInfoFn)); + case ArkFunction::ARK_TRANSLATE_JS_FRAME_INFO: + return DlsymArkFunc("ark_translate_js_frame_info", reinterpret_cast(&g_translateArkFrameInfoFn)); + default: + return false; } +} - const char* arkFuncName = "ark_create_js_symbol_extractor"; - DLSYM_ARK_FUNC(arkFuncName, g_arkCreateJsSymbolExtractorFn) - - if (g_arkCreateJsSymbolExtractorFn != nullptr) { +int DfxArk::ArkCreateJsSymbolExtractor(uintptr_t* extractorPtr) +{ + if (g_arkCreateJsSymbolExtractorFn != nullptr || InitArkFunction(ArkFunction::ARK_CREATE_JS_SYMBOL_EXTRACTOR)) { return g_arkCreateJsSymbolExtractorFn(extractorPtr); } return -1; @@ -99,14 +126,7 @@ int DfxArk::ArkCreateJsSymbolExtractor(uintptr_t* extractorPtr) int DfxArk::ArkDestoryJsSymbolExtractor(uintptr_t extractorPtr) { - if (g_arkDestoryJsSymbolExtractorFn != nullptr) { - return g_arkDestoryJsSymbolExtractorFn(extractorPtr); - } - - const char* arkFuncName = "ark_destory_js_symbol_extractor"; - DLSYM_ARK_FUNC(arkFuncName, g_arkDestoryJsSymbolExtractorFn) - - if (g_arkDestoryJsSymbolExtractorFn != nullptr) { + if (g_arkDestoryJsSymbolExtractorFn != nullptr || InitArkFunction(ArkFunction::ARK_DESTORY_JS_SYMBOL_EXTRACTOR)) { return g_arkDestoryJsSymbolExtractorFn(extractorPtr); } return -1; @@ -114,14 +134,7 @@ int DfxArk::ArkDestoryJsSymbolExtractor(uintptr_t extractorPtr) int DfxArk::ArkCreateLocal() { - if (g_arkCreateLocalFn != nullptr) { - return g_arkCreateLocalFn(); - } - - const char* arkFuncName = "ark_create_local"; - DLSYM_ARK_FUNC(arkFuncName, g_arkCreateLocalFn) - - if (g_arkCreateLocalFn != nullptr) { + if (g_arkCreateLocalFn != nullptr || InitArkFunction(ArkFunction::ARK_CREATE_LOCAL)) { return g_arkCreateLocalFn(); } return -1; @@ -129,14 +142,7 @@ int DfxArk::ArkCreateLocal() int DfxArk::ArkDestroyLocal() { - if (g_arkDestroyLocalFn != nullptr) { - return g_arkDestroyLocalFn(); - } - - const char* arkFuncName = "ark_destroy_local"; - DLSYM_ARK_FUNC(arkFuncName, g_arkDestroyLocalFn) - - if (g_arkDestroyLocalFn != nullptr) { + if (g_arkDestroyLocalFn != nullptr || InitArkFunction(ArkFunction::ARK_DESTROY_LOCAL)) { return g_arkDestroyLocalFn(); } return -1; @@ -145,14 +151,7 @@ int DfxArk::ArkDestroyLocal() int DfxArk::ParseArkFileInfo(uintptr_t byteCodePc, uintptr_t methodid, uintptr_t mapBase, const char* name, uintptr_t extractorPtr, JsFunction *jsFunction) { - if (g_parseArkFileInfoFn != nullptr) { - return g_parseArkFileInfoFn(byteCodePc, methodid, mapBase, name, extractorPtr, jsFunction); - } - - const char* arkFuncName = "ark_parse_js_file_info"; - DLSYM_ARK_FUNC(arkFuncName, g_parseArkFileInfoFn) - - if (g_parseArkFileInfoFn != nullptr) { + if (g_parseArkFileInfoFn != nullptr || InitArkFunction(ArkFunction::ARK_PARSE_JS_FILE_INFO)) { return g_parseArkFileInfoFn(byteCodePc, methodid, mapBase, name, extractorPtr, jsFunction); } return -1; @@ -161,14 +160,7 @@ int DfxArk::ParseArkFileInfo(uintptr_t byteCodePc, uintptr_t methodid, uintptr_t int DfxArk::ParseArkFrameInfoLocal(uintptr_t byteCodePc, uintptr_t methodid, uintptr_t mapBase, uintptr_t offset, JsFunction *jsFunction) { - if (g_parseArkFrameInfoLocalFn != nullptr) { - return g_parseArkFrameInfoLocalFn(byteCodePc, methodid, mapBase, offset, jsFunction); - } - - const char* arkFuncName = "ark_parse_js_frame_info_local"; - DLSYM_ARK_FUNC(arkFuncName, g_parseArkFrameInfoLocalFn) - - if (g_parseArkFrameInfoLocalFn != nullptr) { + if (g_parseArkFrameInfoLocalFn != nullptr || InitArkFunction(ArkFunction::ARK_PARSE_JS_FRAME_INFO_LOCAL)) { return g_parseArkFrameInfoLocalFn(byteCodePc, methodid, mapBase, offset, jsFunction); } return -1; @@ -183,15 +175,7 @@ int DfxArk::ParseArkFrameInfo(uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t int DfxArk::ParseArkFrameInfo(uintptr_t byteCodePc, uintptr_t methodid, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data, uint64_t dataSize, uintptr_t extractorPtr, JsFunction *jsFunction) { - if (g_parseArkFrameInfoFn != nullptr) { - return g_parseArkFrameInfoFn(byteCodePc, methodid, mapBase, loadOffset, data, dataSize, - extractorPtr, jsFunction); - } - - const char* arkFuncName = "ark_parse_js_frame_info"; - DLSYM_ARK_FUNC(arkFuncName, g_parseArkFrameInfoFn) - - if (g_parseArkFrameInfoFn != nullptr) { + if (g_parseArkFrameInfoFn != nullptr || InitArkFunction(ArkFunction::ARK_PARSE_JS_FRAME_INFO)) { return g_parseArkFrameInfoFn(byteCodePc, methodid, mapBase, loadOffset, data, dataSize, extractorPtr, jsFunction); } @@ -200,14 +184,7 @@ int DfxArk::ParseArkFrameInfo(uintptr_t byteCodePc, uintptr_t methodid, uintptr_ int DfxArk::TranslateArkFrameInfo(uint8_t *data, uint64_t dataSize, JsFunction *jsFunction) { - if (g_translateArkFrameInfoFn != nullptr) { - return g_translateArkFrameInfoFn(data, dataSize, jsFunction); - } - - const char* arkFuncName = "ark_translate_js_frame_info"; - DLSYM_ARK_FUNC(arkFuncName, g_translateArkFrameInfoFn) - - if (g_translateArkFrameInfoFn != nullptr) { + if (g_translateArkFrameInfoFn != nullptr || InitArkFunction(ArkFunction::ARK_TRANSLATE_JS_FRAME_INFO)) { return g_translateArkFrameInfoFn(data, dataSize, jsFunction); } return -1; @@ -216,14 +193,7 @@ int DfxArk::TranslateArkFrameInfo(uint8_t *data, uint64_t dataSize, JsFunction * int DfxArk::StepArkFrame(void *obj, OHOS::HiviewDFX::ReadMemFunc readMemFn, uintptr_t *fp, uintptr_t *sp, uintptr_t *pc, uintptr_t* methodid, bool *isJsFrame) { - if (g_stepArkFn != nullptr) { - return g_stepArkFn(obj, readMemFn, fp, sp, pc, methodid, isJsFrame); - } - - const char* arkFuncName = "step_ark"; - DLSYM_ARK_FUNC(arkFuncName, g_stepArkFn) - - if (g_stepArkFn != nullptr) { + if (g_stepArkFn != nullptr || InitArkFunction(ArkFunction::STEP_ARK)) { return g_stepArkFn(obj, readMemFn, fp, sp, pc, methodid, isJsFrame); } return -1; @@ -231,14 +201,7 @@ int DfxArk::StepArkFrame(void *obj, OHOS::HiviewDFX::ReadMemFunc readMemFn, int DfxArk::StepArkFrameWithJit(OHOS::HiviewDFX::ArkUnwindParam* arkPrama) { - if (g_stepArkWithJitFn != nullptr) { - return g_stepArkWithJitFn(arkPrama); - } - - const char* const arkFuncName = "step_ark_with_record_jit"; - DLSYM_ARK_FUNC(arkFuncName, g_stepArkWithJitFn) - - if (g_stepArkWithJitFn != nullptr) { + if (g_stepArkWithJitFn != nullptr || InitArkFunction(ArkFunction::STEP_ARK_WITH_RECORD_JIT)) { return g_stepArkWithJitFn(arkPrama); } return -1; @@ -247,14 +210,7 @@ int DfxArk::StepArkFrameWithJit(OHOS::HiviewDFX::ArkUnwindParam* arkPrama) int DfxArk::JitCodeWriteFile(void* ctx, OHOS::HiviewDFX::ReadMemFunc readMemFn, int fd, const uintptr_t* const jitCodeArray, const size_t jitSize) { - if (g_jitCodeWriteFileFn != nullptr) { - return g_jitCodeWriteFileFn(ctx, readMemFn, fd, jitCodeArray, jitSize); - } - - const char* const arkFuncName = "ark_write_jit_code"; - DLSYM_ARK_FUNC(arkFuncName, g_jitCodeWriteFileFn) - - if (g_jitCodeWriteFileFn != nullptr) { + if (g_jitCodeWriteFileFn != nullptr || InitArkFunction(ArkFunction::ARK_WRITE_JIT_CODE)) { return g_jitCodeWriteFileFn(ctx, readMemFn, fd, jitCodeArray, jitSize); } return -1; @@ -262,14 +218,7 @@ int DfxArk::JitCodeWriteFile(void* ctx, OHOS::HiviewDFX::ReadMemFunc readMemFn, int DfxArk::GetArkNativeFrameInfo(int pid, uintptr_t& pc, uintptr_t& fp, uintptr_t& sp, JsFrame* frames, size_t& size) { - if (g_getArkNativeFrameInfoFn != nullptr) { - return g_getArkNativeFrameInfoFn(pid, &pc, &fp, &sp, frames, size); - } - - const char* arkFuncName = "get_ark_native_frame_info"; - DLSYM_ARK_FUNC(arkFuncName, g_getArkNativeFrameInfoFn) - - if (g_getArkNativeFrameInfoFn != nullptr) { + if (g_getArkNativeFrameInfoFn != nullptr || InitArkFunction(ArkFunction::GET_ARK_NATIVE_FRAME_INFO)) { return g_getArkNativeFrameInfoFn(pid, &pc, &fp, &sp, frames, size); } return -1; diff --git a/interfaces/innerkits/unwinder/dfx_maps.cpp b/interfaces/innerkits/unwinder/dfx_maps.cpp index 8644868ef..6b7220031 100644 --- a/interfaces/innerkits/unwinder/dfx_maps.cpp +++ b/interfaces/innerkits/unwinder/dfx_maps.cpp @@ -127,6 +127,10 @@ bool DfxMaps::Parse(const pid_t pid, const std::string& path) stackBottom_ = static_cast(map->begin); stackTop_ = static_cast(map->end); } + if (map->IsArkExecutable() || (map->IsMapExec() && map->name.find("stub.an") != std::string::npos)) { + arkStackStart_ = static_cast(map->begin); + arkStackEnd_ = static_cast(map->end); + } if (onlyExec_ && !map->IsMapExec()) { continue; } @@ -312,6 +316,16 @@ bool DfxMaps::GetStackRange(uintptr_t& bottom, uintptr_t& top) return true; } +bool DfxMaps::GetArkStackRange(uintptr_t& start, uintptr_t& end) +{ + if (arkStackStart_ == 0 || arkStackEnd_ == 0) { + return false; + } + start = arkStackStart_; + end = arkStackEnd_; + return true; +} + bool DfxMaps::IsArkExecutedMap(uintptr_t addr) { std::shared_ptr map = nullptr; diff --git a/interfaces/innerkits/unwinder/include/dfx_ark.h b/interfaces/innerkits/unwinder/include/dfx_ark.h index dc4bcbdfb..3fb220bcf 100644 --- a/interfaces/innerkits/unwinder/include/dfx_ark.h +++ b/interfaces/innerkits/unwinder/include/dfx_ark.h @@ -82,6 +82,22 @@ using JsFunction = panda::ecmascript::JsFunction; using ReadMemFunc = panda::ecmascript::ReadMemFunc; using ArkUnwindParam = panda::ecmascript::ArkUnwindParam; +enum class ArkFunction { + ARK_LIB_NAME, + ARK_CREATE_JS_SYMBOL_EXTRACTOR, + ARK_DESTORY_JS_SYMBOL_EXTRACTOR, + ARK_CREATE_LOCAL, + ARK_DESTROY_LOCAL, + ARK_PARSE_JS_FILE_INFO, + ARK_PARSE_JS_FRAME_INFO_LOCAL, + ARK_PARSE_JS_FRAME_INFO, + STEP_ARK, + STEP_ARK_WITH_RECORD_JIT, + ARK_WRITE_JIT_CODE, + GET_ARK_NATIVE_FRAME_INFO, + ARK_TRANSLATE_JS_FRAME_INFO, +}; + class DfxArk { public: static int GetArkNativeFrameInfo(int pid, uintptr_t& pc, uintptr_t& fp, uintptr_t& sp, @@ -107,6 +123,14 @@ public: static int ArkCreateJsSymbolExtractor(uintptr_t* extractorPtr); static int ArkDestoryJsSymbolExtractor(uintptr_t extractorPtr); + + /** + * @brief init ark function. + * + * @param arkFunction target function. + * @return + */ + static bool InitArkFunction(ArkFunction arkFunction); static int ArkCreateLocal(); static int ArkDestroyLocal(); }; diff --git a/interfaces/innerkits/unwinder/include/dfx_maps.h b/interfaces/innerkits/unwinder/include/dfx_maps.h index 3c1dbd4dd..2d068a365 100644 --- a/interfaces/innerkits/unwinder/include/dfx_maps.h +++ b/interfaces/innerkits/unwinder/include/dfx_maps.h @@ -50,7 +50,7 @@ public: const std::vector& GetMapIndexVec() const { return mapIndex_; } size_t GetMapsSize() const { return maps_.size(); } bool GetStackRange(uintptr_t& bottom, uintptr_t& top); - + bool GetArkStackRange(uintptr_t& start, uintptr_t& end); bool IsArkExecutedMap(uintptr_t addr); uint32_t filePathId_ {0}; // for maps item filePath id private: @@ -64,6 +64,8 @@ private: bool onlyExec_ = false; uintptr_t stackBottom_ = 0; uintptr_t stackTop_ = 0; + uintptr_t arkStackStart_ = 0; + uintptr_t arkStackEnd_ = 0; }; } // namespace HiviewDFX } // namespace OHOS diff --git a/interfaces/innerkits/unwinder/libunwinder.map b/interfaces/innerkits/unwinder/libunwinder.map index bd2ff3bf9..549e381d3 100644 --- a/interfaces/innerkits/unwinder/libunwinder.map +++ b/interfaces/innerkits/unwinder/libunwinder.map @@ -89,11 +89,15 @@ OHOS::HiviewDFX::DfxElf::GetElfName*; OHOS::HiviewDFX::DfxSymbols::ParseSymbols*; OHOS::HiviewDFX::DfxSymbols::AddSymbolsByPlt*; + OHOS::HiviewDFX::DfxSymbols::GetFuncNameAndOffsetByPc*; + OHOS::HiviewDFX::DfxArk::InitArkFunction*; OHOS::HiviewDFX::DfxArk::ArkCreateJsSymbolExtractor*; OHOS::HiviewDFX::DfxArk::ArkDestoryJsSymbolExtractor*; OHOS::HiviewDFX::DfxArk::ParseArkFrameInfo*; + OHOS::HiviewDFX::DfxArk::StepArkFrame*; OHOS::HiviewDFX::DfxMap::IsMapExec*; OHOS::HiviewDFX::DfxMaps::IsLegalMapItem*; + OHOS::HiviewDFX::DfxMaps::GetArkStackRange*; OHOS::HiviewDFX::DfxElf::GetMmapPtr*; }; local: diff --git a/interfaces/innerkits/unwinder/unwinder.cpp b/interfaces/innerkits/unwinder/unwinder.cpp index 514336af4..a709f811c 100644 --- a/interfaces/innerkits/unwinder/unwinder.cpp +++ b/interfaces/innerkits/unwinder/unwinder.cpp @@ -34,6 +34,7 @@ #include "dfx_regs_get.h" #include "dfx_symbols.h" #include "dfx_trace_dlsym.h" +#include "dfx_util.h" #include "dwarf_section.h" #include "fp_unwinder.h" #include "stack_util.h" @@ -242,7 +243,6 @@ private: #if defined(ENABLE_MIXSTACK) bool StepArkJsFrame(StepFrame& frame); #endif - static uintptr_t StripPac(uintptr_t inAddr, uintptr_t pacMask); inline void SetLocalStackCheck(void* ctx, bool check) const { if ((pid_ == UNWIND_TYPE_LOCAL) && (ctx != nullptr)) { @@ -1128,26 +1128,6 @@ void Unwinder::Impl::DoPcAdjust(uintptr_t& pc) pc -= sz; } -uintptr_t Unwinder::Impl::StripPac(uintptr_t inAddr, uintptr_t pacMask) -{ - uintptr_t outAddr = inAddr; -#if defined(__aarch64__) - if (outAddr != 0) { - if (pacMask != 0) { - outAddr &= ~pacMask; - } else { - register uint64_t x30 __asm("x30") = inAddr; - asm("hint 0x7" : "+r"(x30)); - outAddr = x30; - } - if (outAddr != inAddr) { - LOGU("Strip pac in addr: %lx, out addr: %lx", (uint64_t)inAddr, (uint64_t)outAddr); - } - } -#endif - return outAddr; -} - const std::vector& Unwinder::Impl::GetFrames() { if (enableFillFrames_) { diff --git a/test/unittest/backtrace/BUILD.gn b/test/unittest/backtrace/BUILD.gn index f29d045fc..f30f06497 100644 --- a/test/unittest/backtrace/BUILD.gn +++ b/test/unittest/backtrace/BUILD.gn @@ -50,7 +50,10 @@ ohos_unittest("backtrace_local_test") { "$faultloggerd_interfaces_path/innerkits/backtrace", "$faultloggerd_interfaces_path/innerkits/unwinder/include", ] - sources = [ "backtrace_local_test.cpp" ] + sources = [ + "backtrace_local_test.cpp", + "fp_backtrace_test.cpp", + ] deps = [ "$faultloggerd_common_path/dfxutil:dfx_util", "$faultloggerd_interfaces_path/innerkits/backtrace:libbacktrace_local", @@ -106,7 +109,10 @@ ohos_unittest("backtrace_local_test_static") { "BACKTRACE_LOCAL_TEST_STATIC", "DFX_LOG_HILOG_BASE", ] - sources = [ "backtrace_local_test.cpp" ] + sources = [ + "backtrace_local_test.cpp", + "fp_backtrace_test.cpp", + ] deps = [ "$faultloggerd_common_path/dfxlog:dfx_hilog_base", "$faultloggerd_common_path/dfxutil:dfx_util_static", diff --git a/test/unittest/backtrace/fp_backtrace_test.cpp b/test/unittest/backtrace/fp_backtrace_test.cpp new file mode 100644 index 000000000..fadaddce2 --- /dev/null +++ b/test/unittest/backtrace/fp_backtrace_test.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022-2024 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 +#include + +#include "fp_backtrace.h" + +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace HiviewDFX { + +#define DEFAULT_MAX_FRAME_NUM 256 +#define MIN_FRAME_NUM 2 + +class FpBacktraceTest : public testing::Test {}; + +/** + * @tc.name: FpBacktraceTestTest001 + * @tc.desc: test get backtrace of current thread by fp + * @tc.type: FUNC + */ +HWTEST_F(FpBacktraceTest, FpBacktraceTestTest001, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BacktraceLocalTest001: start."; + auto fpBacktrace = FpBacktrace::CreateInstance(); +#if is_ohos && !is_mingw && __aarch64__ + ASSERT_NE(nullptr, fpBacktrace); + void* pcArray[DEFAULT_MAX_FRAME_NUM]{0}; + int size = fpBacktrace->BacktraceFromFp(__builtin_frame_address(0), pcArray, DEFAULT_MAX_FRAME_NUM); + ASSERT_GE(size, 0); + for (int i = 0; i < size; i++) { + ASSERT_NE(fpBacktrace->SymbolicAddress(pcArray[i]), nullptr); + } + for (int i = 0; i < size; i++) { + ASSERT_NE(fpBacktrace->SymbolicAddress(pcArray[i]), nullptr); + } + GTEST_LOG_(INFO) << "BacktraceLocalTest001: end."; +#else + ASSERT_EQ(nullptr, fpBacktrace); +#endif +} +} // namespace HiviewDFX +} // namepsace OHOS -- Gitee