mirror of
https://gitee.com/openharmony/developtools_hiperf
synced 2024-11-23 15:39:47 +00:00
7b263b2c6e
Signed-off-by:wenlong12 <wenlong12@huawei.com> Signed-off-by: wenlong12 <wenlong12@huawei.com>
161 lines
6.4 KiB
C++
161 lines
6.4 KiB
C++
/*
|
|
* 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
|
|
|
|
#if HAVE_LIBUNWIND
|
|
// for libunwind.h empty struct has size 0 in c, size 1 in c++
|
|
#include <libunwind.h>
|
|
#endif
|
|
|
|
#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"
|
|
|
|
#if HAVE_LIBUNWIND
|
|
using ADDR_TYPE = unw_word_t;
|
|
#else
|
|
using ADDR_TYPE = uintptr_t;
|
|
#endif
|
|
|
|
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();
|
|
bool UnwindCallStack(const VirtualThread &thread, bool abi32, u64 *regs, u64 regsNum,
|
|
const u8 *stack, u64 stackSize, std::vector<DfxFrame> &,
|
|
size_t maxStackLevel = MAX_CALL_FRAME_UNWIND_SIZE);
|
|
size_t ExpandCallStack(pid_t tid, std::vector<DfxFrame> &callFrames, 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; // not const , be cause we will fix it for arm64 cpu in UpdateRegForABI
|
|
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, size_t expandLimit);
|
|
|
|
// we have a cache for all thread
|
|
std::map<pid_t, HashList<uint64_t, std::vector<DfxFrame>>> cachedCallFramesMap_;
|
|
bool GetIpSP(uint64_t &ip, uint64_t &sp, const u64 *regs, size_t regNum) const;
|
|
ArchType arch_ = ArchType::ARCH_UNKNOWN;
|
|
|
|
static bool ReadVirtualThreadMemory(UnwindInfo &unwindInfoPtr, ADDR_TYPE addr, ADDR_TYPE *data);
|
|
#if HAVE_LIBUNWIND
|
|
static const std::string GetUnwErrorName(int error);
|
|
static void dumpUDI(unw_dyn_info_t &di);
|
|
static bool fillUDI(unw_dyn_info_t &di, SymbolsFile &symbolsFile, std::shared_ptr<DfxMap> map,
|
|
const VirtualThread &thread);
|
|
static int FindProcInfo(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
|
|
int need_unwind_info, void *arg);
|
|
static int AccessMem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valuePoint,
|
|
int writeOperation, void *arg);
|
|
static int AccessReg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valuePoint,
|
|
int writeOperation, void *arg);
|
|
static void PutUnwindInfo(unw_addr_space_t as, unw_proc_info_t *pi, void *arg);
|
|
static int AccessFpreg(unw_addr_space_t as, unw_regnum_t num, unw_fpreg_t *val,
|
|
int writeOperation, void *arg);
|
|
static int GetDynInfoListAaddr(unw_addr_space_t as, unw_word_t *dil_vaddr, void *arg);
|
|
static int Resume(unw_addr_space_t as, unw_cursor_t *cu, void *arg);
|
|
static int getProcName(unw_addr_space_t as, unw_word_t addr, char *bufp, size_t buf_len,
|
|
unw_word_t *offp, void *arg);
|
|
static int FindUnwindTable(SymbolsFile *symbolsFile, std::shared_ptr<DfxMap> map,
|
|
UnwindInfo *unwindInfoPtr, unw_addr_space_t as, unw_word_t ip,
|
|
unw_proc_info_t *pi, int need_unwind_info, void *arg);
|
|
void UnwindStep(unw_cursor_t &c, std::vector<DfxFrame> &callFrames, size_t maxStackLevel);
|
|
std::unordered_map<pid_t, unw_addr_space_t> unwindAddrSpaceMap_;
|
|
|
|
using dsoUnwDynInfoMap = std::unordered_map<std::string, std::optional<unw_dyn_info_t>>;
|
|
std::unordered_map<pid_t, dsoUnwDynInfoMap> unwindTableInfoMap_;
|
|
|
|
using unwMemoryCache = std::unordered_map<unw_word_t, unw_word_t>;
|
|
std::unordered_map<pid_t, unwMemoryCache> porcessMemoryMap_;
|
|
|
|
unw_accessors_t accessors_ = {
|
|
.find_proc_info = FindProcInfo,
|
|
.put_unwind_info = PutUnwindInfo,
|
|
.get_dyn_info_list_addr = GetDynInfoListAaddr,
|
|
.access_mem = AccessMem,
|
|
.access_reg = AccessReg,
|
|
.access_fpreg = AccessFpreg,
|
|
.resume = Resume,
|
|
.get_proc_name = getProcName,
|
|
};
|
|
bool DoUnwind(const VirtualThread &thread, std::vector<DfxFrame> &callStack,
|
|
size_t maxStackLevel);
|
|
#endif
|
|
#if defined(HAVE_LIBUNWINDER) && HAVE_LIBUNWINDER
|
|
bool DoUnwind2(const VirtualThread &thread, std::vector<DfxFrame> &callStack, size_t maxStackLevel);
|
|
static void DumpTableInfo(UnwindTableInfo &outTableInfo);
|
|
static int FillUnwindTable(SymbolsFile *symbolsFile, std::shared_ptr<DfxMap> map, UnwindInfo *unwindInfoPtr,
|
|
uintptr_t pc, UnwindTableInfo& outTableInfo);
|
|
static int FindUnwindTable(uintptr_t pc, UnwindTableInfo& outTableInfo, void *arg);
|
|
static int AccessMem2(uintptr_t addr, uintptr_t *val, void *arg);
|
|
static int GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg);
|
|
|
|
// pid->unwinder(acc/regs/maps) cache
|
|
std::unordered_map<pid_t, std::shared_ptr<Unwinder>> pidUnwinder_;
|
|
// pid->elf->unwindtable cache
|
|
using DsoUnwindTableInfoMap = std::unordered_map<std::string, UnwindTableInfo>;
|
|
std::unordered_map<pid_t, DsoUnwindTableInfoMap> unwindTableInfoMap_;
|
|
|
|
std::shared_ptr<UnwindAccessors> accessor_;
|
|
#endif
|
|
|
|
FRIEND_TEST(CallStackTest, ExpendCallStackFullCache);
|
|
FRIEND_TEST(CallStackTest, LibUnwindEmptyFunc);
|
|
FRIEND_TEST(CallStackTest, GetUnwErrorName);
|
|
};
|
|
|
|
struct UnwindInfo {
|
|
const VirtualThread &thread;
|
|
const u64 *regs;
|
|
size_t regNumber;
|
|
ArchType arch;
|
|
CallStack &callStack;
|
|
};
|
|
} // namespace HiPerf
|
|
} // namespace Developtools
|
|
} // namespace OHOS
|
|
#endif // HIPERF_CALLSTACK_H
|