Yyuhaoqiangfp回栈PC校准
a1e890d4创建于 28 天前历史提交
/*
* 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 && (defined(__aarch64__) || defined(__x86_64__))
#include <mutex>
#include "dfx_ark.h"
#include "dfx_log.h"
#include "dfx_maps.h"
#include "dfx_symbols.h"
#include "dfx_util.h"
#include "memory_reader.h"
#include "smart_fd.h"
#include "stack_utils.h"
#include "unwinder.h"
#endif

namespace OHOS {
namespace HiviewDFX {

#if is_ohos && !is_mingw && (defined(__aarch64__) || defined(__x86_64__))
namespace {

#undef LOG_DOMAIN
#undef LOG_TAG
#define LOG_TAG "FpBacktrace"
#define LOG_DOMAIN 0xD002D11

std::atomic<uintptr_t> g_arkStubBegin{0};
std::atomic<uintptr_t> g_arkStubEnd{0};
std::atomic_bool g_updateArkStubFlag{false};
}

extern "C" bool ffrt_get_current_coroutine_stack(void** stackAddr, size_t* size) __attribute__((weak));

class FpBacktraceImpl : public FpBacktrace {
public:
    bool Init();
    uint32_t BacktraceFromFp(void* startFp, void** pcArray, uint32_t size, bool adjustPc = false) override;
    DfxFrame* SymbolicAddress(void* pc) override;
private:
    void BacktraceArkFrame(ArkStepParam &arkParam, MemoryReader& memoryReader, uint64_t& staticArkFrameIndex) const;
    uint32_t BacktraceFromFp(void* startFp, void** pcArray, uint32_t size,
        MemoryReader& memoryReader, bool adjustPc) const;
    bool GetCurrentThreadRange(uintptr_t startFp, uintptr_t& threadBegin, uintptr_t& threadEnd);
    std::shared_ptr<DfxMaps> maps_ = nullptr;
    Unwinder unwinder_{false};
    uintptr_t mainStackBegin_{0};
    uintptr_t mainStackEnd_{0};
    uintptr_t staticArkBegin_{0};
    uintptr_t staticArkEnd_{0};
    std::map<void*, std::unique_ptr<DfxFrame>> cachedFrames_;
    std::mutex mutex_;
};

bool FpBacktraceImpl::Init()
{
    static std::once_flag flag;
    std::call_once(flag, []() {
        if (ffrt_get_current_coroutine_stack) {
            void* stackBegin = 0;
            size_t stackSize = 0;
            ffrt_get_current_coroutine_stack(&stackBegin, &stackSize);
        }
        DfxArk::Instance().InitArkFunction("step_ark");
    });
    maps_ = DfxMaps::Create(0, false);
    if (maps_ == nullptr) {
        DFXLOGI("failed creat maps");
        return false;
    }
    maps_->GetStackRange(mainStackBegin_, mainStackEnd_);
    maps_->GetStaticArkRange(staticArkBegin_, staticArkEnd_);
    return true;
}

uint32_t FpBacktraceImpl::BacktraceFromFp(void* startFp, void** pcArray, uint32_t size, bool adjustPc)
{
    if (!maps_ || startFp == nullptr || pcArray == nullptr || size == 0) {
        return 0;
    }
    uintptr_t stackBegin = 0;
    uintptr_t stackEnd = 0;
    if (GetCurrentThreadRange(reinterpret_cast<uintptr_t>(startFp), stackBegin, stackEnd)) {
        ThreadMemoryReader memoryReader(stackBegin, stackEnd);
        return BacktraceFromFp(startFp, pcArray, size, memoryReader, adjustPc);
    }
    ProcessMemoryReader memoryReader;
    return BacktraceFromFp(startFp, pcArray, size, memoryReader, adjustPc);
}
void FpBacktraceImpl::BacktraceArkFrame(ArkStepParam &arkParam, MemoryReader& memoryReader,
    uint64_t &staticArkFrameIndex) const
{
    if (*(arkParam.pc) >= staticArkBegin_ && *(arkParam.pc) < staticArkEnd_) {
        staticArkFrameIndex = 0;
        arkParam.frameIndex = staticArkFrameIndex;
        *(arkParam.frameType) = FrameType::STATIC_JS_FRAME;
    }
    DfxArk::Instance().StepArkFrame(&memoryReader, [](void* memoryReader, uintptr_t addr, uintptr_t* val) {
        return reinterpret_cast<MemoryReader*>(memoryReader)->ReadMemory(addr, val, sizeof(uintptr_t));
    }, &arkParam);
    if (*(arkParam.frameType) == FrameType::STATIC_JS_FRAME) {
        staticArkFrameIndex++;
    }
}

uint32_t FpBacktraceImpl::BacktraceFromFp(void* startFp, void** pcArray, uint32_t size,
    MemoryReader& memoryReader, bool adjustPc) const
{
    uint32_t index = 0;
    bool isJsFrame = false;
    FrameType frameType = FrameType::NATIVE_FRAME;
    uint64_t staticArkFrameIndex = 0;
    uintptr_t registerState[] = {reinterpret_cast<uintptr_t>(startFp), 0};
    uintptr_t sp = 0;
    uintptr_t arkStubBegin{0};
    uintptr_t arkStubEnd{0};
    if (!g_updateArkStubFlag.load(std::memory_order_acquire)) {
        maps_->GetArkStackRange(arkStubBegin, arkStubEnd);
    } else {
        arkStubBegin = g_arkStubBegin.load(std::memory_order_relaxed);
        arkStubEnd = g_arkStubEnd.load(std::memory_order_relaxed);
    }
    while (index < size) {
        constexpr auto fpIndex = 0;
        constexpr auto pcIndex = 1;
        uintptr_t preFp = registerState[fpIndex];
        if (isJsFrame || (registerState[pcIndex] < arkStubEnd && registerState[pcIndex] >= arkStubBegin) ||
            (registerState[pcIndex] < staticArkEnd_ && registerState[pcIndex] >= staticArkBegin_)) {
            ArkStepParam arkParam(&registerState[fpIndex], &sp, &registerState[pcIndex], &isJsFrame, &frameType,
                                  staticArkFrameIndex);
            BacktraceArkFrame(arkParam, memoryReader, staticArkFrameIndex);
        } else {
            if (!memoryReader.ReadMemory(registerState[fpIndex], registerState, sizeof(registerState))) {
                break;
            }
        }
        constexpr auto pcBound = 0x1000;
        if (registerState[pcIndex] <= pcBound) {
            if (index != 0) {
                break;
            }
            // when fp back trace first frame failed, use the ark interface try again
            ArkStepParam arkParam(&registerState[fpIndex], &sp, &registerState[pcIndex], &isJsFrame, &frameType,
                                  staticArkFrameIndex);
            BacktraceArkFrame(arkParam, memoryReader, staticArkFrameIndex);
        }
        uintptr_t curPc = registerState[pcIndex];
#if defined(__aarch64__)
        if (adjustPc && !isJsFrame && frameType == FrameType::NATIVE_FRAME && curPc > 0x4) {
            curPc -= 0x4;
        }
#endif
        uintptr_t pc = StripPac(curPc, 0);
        auto realPc = reinterpret_cast<void *>(pc);
        if (realPc != nullptr) {
            pcArray[index++] = realPc;
        }
        if (frameType != FrameType::STATIC_JS_FRAME &&
            (registerState[fpIndex] <= preFp || registerState[fpIndex] == 0)) {
            break;
        }
    }
    return index;
}

bool FpBacktraceImpl::GetCurrentThreadRange(uintptr_t startFp, uintptr_t& threadBegin, uintptr_t& threadEnd)
{
    if (getpid() == gettid() && startFp >= mainStackBegin_ && startFp < mainStackEnd_) {
        threadBegin = mainStackBegin_;
        threadEnd = mainStackEnd_;
        return true;
    }
    if (StackUtils::GetSelfStackRange(threadBegin, threadEnd)) {
        if (startFp >= threadBegin && startFp < threadEnd) {
            return true;
        }
    }
    size_t stackSize = 0;
    if (ffrt_get_current_coroutine_stack &&
        ffrt_get_current_coroutine_stack(reinterpret_cast<void**>(&threadBegin), &stackSize)) {
        if (startFp >= threadBegin && startFp < threadBegin + stackSize) {
            threadEnd = threadBegin + stackSize;
            return true;
        }
    }
    return false;
}

DfxFrame* FpBacktraceImpl::SymbolicAddress(void* pc)
{
    std::unique_lock<std::mutex> lock(mutex_);
    auto cachedFrame = cachedFrames_.emplace(pc, nullptr);
    auto& frame = cachedFrame.first->second;
    if (!cachedFrame.second) {
        return frame.get();
    }
    frame = std::unique_ptr<DfxFrame>(new (std::nothrow) DfxFrame());
    if (!frame) {
        return nullptr;
    }
    unwinder_.GetFrameByPc(reinterpret_cast<uintptr_t>(pc), maps_, *(frame));
    if (frame->map == nullptr) {
        frame = nullptr;
        return nullptr;
    }
    return frame.get();
}
#endif

FpBacktrace* FpBacktrace::CreateInstance()
{
#if is_ohos && !is_mingw && (defined(__aarch64__) || defined(__x86_64__))
    auto fpBacktraceImpl =  new (std::nothrow) FpBacktraceImpl();
    if (fpBacktraceImpl == nullptr) {
        return nullptr;
    }
    if (fpBacktraceImpl->Init()) {
        return fpBacktraceImpl;
    }
    delete fpBacktraceImpl;
#endif
    return nullptr;
}

void FpBacktrace::UpdateArkStackRange(uintptr_t arkStubBegin, uintptr_t arkStubEnd)
{
#if is_ohos && !is_mingw && (defined(__aarch64__) || defined(__x86_64__))
    DFXLOGI("UpdateArkStackRange.");
    g_arkStubBegin.store(arkStubBegin, std::memory_order_relaxed);
    g_arkStubEnd.store(arkStubEnd, std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_release);
    g_updateArkStubFlag.store(true, std::memory_order_relaxed);
#endif
}
}
}