* Copyright (c) 2021 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 HIPERF_CALLSTACK_H
#define HIPERF_CALLSTACK_H
#include <map>
#include <optional>
#include <string>
#include <vector>
#if !is_mingw
#include <sys/mman.h>
#endif
#include "hashlist.h"
#include "register.h"
#include "utilities.h"
#include "unwinder.h"
#include "virtual_thread.h"
using ADDR_TYPE = uintptr_t;
namespace OHOS {
namespace Developtools {
namespace HiPerf {
using namespace OHOS::HiviewDFX;
const int MAX_CALL_FRAME_EXPAND_CYCLE = 10;
const size_t MAX_CALL_FRAME_EXPAND_CACHE_SIZE = 10;
const size_t MAX_CALL_FRAME_UNWIND_SIZE = 256;
struct UnwindInfo;
class CallStack {
public:
CallStack();
~CallStack() = default;
void ClearCache();
bool UnwindCallStack(const VirtualThread &thread, const bool abi32, u64 *regs, const u64 regsNum,
const u8 *stack, u64 stackSize, std::vector<DfxFrame> &,
const size_t maxStackLevel = MAX_CALL_FRAME_UNWIND_SIZE);
size_t ExpandCallStack(const pid_t tid, std::vector<DfxFrame> &callFrames, const size_t expandLimit = 1u);
private:
pid_t lastPid_ = -1;
ADDR_TYPE lastAddr_ = 0;
ADDR_TYPE lastData_ = 0;
uint64_t stackPoint_ = 0;
uint64_t stackEnd_ = 0;
u64 *regs_ = nullptr;
u64 regsNum_ = 0;
const u8 *stack_ = nullptr;
u64 stackSize_ = 0;
void LogFrame(const std::string msg, const std::vector<DfxFrame> &frames);
size_t DoExpandCallStack(std::vector<DfxFrame> &newCallFrames,
const std::vector<DfxFrame> &cachedCallFrames, const size_t expandLimit);
std::map<pid_t, HashList<uint64_t, std::vector<DfxFrame>>> cachedCallFramesMap_;
bool GetIpSP(uint64_t &ip, uint64_t &sp, const u64 *regs, const size_t regNum) const;
ArchType arch_ = ArchType::ARCH_UNKNOWN;
static bool ReadVirtualThreadMemory(UnwindInfo &unwindInfoPtr, const ADDR_TYPE addr, ADDR_TYPE *data);
#if defined(HAVE_LIBUNWINDER) && HAVE_LIBUNWINDER
bool DoUnwind2(const VirtualThread &thread, std::vector<DfxFrame> &callStack, const size_t maxStackLevel);
static void DumpTableInfo(UnwindTableInfo &outTableInfo);
static int FillUnwindTable(SymbolsFile *symbolsFile, std::shared_ptr<DfxMap> map, UnwindInfo *unwindInfoPtr,
const uintptr_t pc, UnwindTableInfo& outTableInfo);
static int FindUnwindTable(const uintptr_t pc, UnwindTableInfo& outTableInfo, void *arg);
static int AccessMem2(const uintptr_t addr, uintptr_t *val, void *arg);
static int GetMapByPc(const uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg);
std::unordered_map<pid_t, std::shared_ptr<Unwinder>> pidUnwinder_;
using DsoUnwindTableInfoMap = std::unordered_map<std::string, UnwindTableInfo>;
std::unordered_map<pid_t, DsoUnwindTableInfoMap> unwindTableInfoMap_;
std::shared_ptr<UnwindAccessors> accessor_ = nullptr;
#endif
};
struct UnwindInfo {
const VirtualThread &thread;
const u64 *regs;
size_t regNumber = 0;
ArchType arch;
CallStack &callStack;
};
}
}
}
#endif