1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License.
5800b99b8Sopenharmony_ci * You may obtain a copy of the License at
6800b99b8Sopenharmony_ci *
7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8800b99b8Sopenharmony_ci *
9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and
13800b99b8Sopenharmony_ci * limitations under the License.
14800b99b8Sopenharmony_ci */
15800b99b8Sopenharmony_ci
16800b99b8Sopenharmony_ci#include "backtrace_local.h"
17800b99b8Sopenharmony_ci
18800b99b8Sopenharmony_ci#include <cstring>
19800b99b8Sopenharmony_ci#include <dirent.h>
20800b99b8Sopenharmony_ci#include <mutex>
21800b99b8Sopenharmony_ci#include <unistd.h>
22800b99b8Sopenharmony_ci#include <vector>
23800b99b8Sopenharmony_ci
24800b99b8Sopenharmony_ci#include "backtrace_local_thread.h"
25800b99b8Sopenharmony_ci#include "elapsed_time.h"
26800b99b8Sopenharmony_ci#include "dfx_frame_formatter.h"
27800b99b8Sopenharmony_ci#include "dfx_kernel_stack.h"
28800b99b8Sopenharmony_ci#include "dfx_log.h"
29800b99b8Sopenharmony_ci#include "dfx_util.h"
30800b99b8Sopenharmony_ci#include "directory_ex.h"
31800b99b8Sopenharmony_ci#include "procinfo.h"
32800b99b8Sopenharmony_ci#include "unwinder.h"
33800b99b8Sopenharmony_ci
34800b99b8Sopenharmony_cinamespace OHOS {
35800b99b8Sopenharmony_cinamespace HiviewDFX {
36800b99b8Sopenharmony_cinamespace {
37800b99b8Sopenharmony_ci#undef LOG_DOMAIN
38800b99b8Sopenharmony_ci#undef LOG_TAG
39800b99b8Sopenharmony_ci#define LOG_TAG "DfxBacktrace"
40800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11
41800b99b8Sopenharmony_ci
42800b99b8Sopenharmony_cistd::string GetThreadHead(int32_t tid)
43800b99b8Sopenharmony_ci{
44800b99b8Sopenharmony_ci    std::string threadName;
45800b99b8Sopenharmony_ci    if (tid == BACKTRACE_CURRENT_THREAD) {
46800b99b8Sopenharmony_ci        tid = gettid();
47800b99b8Sopenharmony_ci    }
48800b99b8Sopenharmony_ci    ReadThreadName(tid, threadName);
49800b99b8Sopenharmony_ci    std::string threadHead = "Tid:" + std::to_string(tid) + ", Name:" + threadName + "\n";
50800b99b8Sopenharmony_ci    return threadHead;
51800b99b8Sopenharmony_ci}
52800b99b8Sopenharmony_ci}
53800b99b8Sopenharmony_ci
54800b99b8Sopenharmony_cibool GetBacktraceFramesByTid(std::vector<DfxFrame>& frames, int32_t tid, size_t skipFrameNum, bool fast,
55800b99b8Sopenharmony_ci                             size_t maxFrameNums)
56800b99b8Sopenharmony_ci{
57800b99b8Sopenharmony_ci    std::shared_ptr<Unwinder> unwinder = nullptr;
58800b99b8Sopenharmony_ci#ifdef __aarch64__
59800b99b8Sopenharmony_ci    if (fast || (tid != BACKTRACE_CURRENT_THREAD)) {
60800b99b8Sopenharmony_ci        unwinder = std::make_shared<Unwinder>(false);
61800b99b8Sopenharmony_ci    }
62800b99b8Sopenharmony_ci#endif
63800b99b8Sopenharmony_ci    if (unwinder == nullptr) {
64800b99b8Sopenharmony_ci        unwinder = std::make_shared<Unwinder>();
65800b99b8Sopenharmony_ci    }
66800b99b8Sopenharmony_ci    BacktraceLocalThread thread(tid, unwinder);
67800b99b8Sopenharmony_ci    bool ret = thread.Unwind(fast, maxFrameNums, skipFrameNum + 1);
68800b99b8Sopenharmony_ci    frames = thread.GetFrames();
69800b99b8Sopenharmony_ci    return ret;
70800b99b8Sopenharmony_ci}
71800b99b8Sopenharmony_ci
72800b99b8Sopenharmony_cibool GetBacktraceStringByTid(std::string& out, int32_t tid, size_t skipFrameNum, bool fast,
73800b99b8Sopenharmony_ci                             size_t maxFrameNums, bool enableKernelStack)
74800b99b8Sopenharmony_ci{
75800b99b8Sopenharmony_ci    std::vector<DfxFrame> frames;
76800b99b8Sopenharmony_ci    bool ret = GetBacktraceFramesByTid(frames, tid, skipFrameNum + 1, fast, maxFrameNums);
77800b99b8Sopenharmony_ci    if (!ret && enableKernelStack) {
78800b99b8Sopenharmony_ci        std::string msg = "";
79800b99b8Sopenharmony_ci        DfxThreadStack threadStack;
80800b99b8Sopenharmony_ci        if (DfxGetKernelStack(tid, msg) == 0 && FormatThreadKernelStack(msg, threadStack)) {
81800b99b8Sopenharmony_ci            frames = threadStack.frames;
82800b99b8Sopenharmony_ci            ret = true;
83800b99b8Sopenharmony_ci            DFXLOGI("Failed to get tid(%{public}d) user stack, try kernel", tid);
84800b99b8Sopenharmony_ci        }
85800b99b8Sopenharmony_ci    }
86800b99b8Sopenharmony_ci    if (ret) {
87800b99b8Sopenharmony_ci        out.clear();
88800b99b8Sopenharmony_ci        std::string threadHead = GetThreadHead(tid);
89800b99b8Sopenharmony_ci        out = threadHead + Unwinder::GetFramesStr(frames);
90800b99b8Sopenharmony_ci    }
91800b99b8Sopenharmony_ci    return ret;
92800b99b8Sopenharmony_ci}
93800b99b8Sopenharmony_ci
94800b99b8Sopenharmony_cibool PrintBacktrace(int32_t fd, bool fast, size_t maxFrameNums)
95800b99b8Sopenharmony_ci{
96800b99b8Sopenharmony_ci    DFXLOGI("Receive PrintBacktrace request.");
97800b99b8Sopenharmony_ci    std::vector<DfxFrame> frames;
98800b99b8Sopenharmony_ci    bool ret = GetBacktraceFramesByTid(frames,
99800b99b8Sopenharmony_ci        BACKTRACE_CURRENT_THREAD, 1, fast, maxFrameNums); // 1: skip current frame
100800b99b8Sopenharmony_ci    if (!ret) {
101800b99b8Sopenharmony_ci        return false;
102800b99b8Sopenharmony_ci    }
103800b99b8Sopenharmony_ci
104800b99b8Sopenharmony_ci    for (auto const& frame : frames) {
105800b99b8Sopenharmony_ci        auto line = DfxFrameFormatter::GetFrameStr(frame);
106800b99b8Sopenharmony_ci        if (fd >= 0) {
107800b99b8Sopenharmony_ci            dprintf(fd, "    %s", line.c_str());
108800b99b8Sopenharmony_ci        }
109800b99b8Sopenharmony_ci        DFXLOGI(" %{public}s", line.c_str());
110800b99b8Sopenharmony_ci    }
111800b99b8Sopenharmony_ci    return ret;
112800b99b8Sopenharmony_ci}
113800b99b8Sopenharmony_ci
114800b99b8Sopenharmony_cibool GetBacktrace(std::string& out, bool fast, size_t maxFrameNums)
115800b99b8Sopenharmony_ci{
116800b99b8Sopenharmony_ci    ElapsedTime et;
117800b99b8Sopenharmony_ci    bool ret = GetBacktraceStringByTid(out, BACKTRACE_CURRENT_THREAD, 1,
118800b99b8Sopenharmony_ci                                       fast, maxFrameNums, false); // 1: skip current frame
119800b99b8Sopenharmony_ci    DFXLOGI("GetBacktrace elapsed time: %{public}" PRId64 " ms", et.Elapsed<std::chrono::milliseconds>());
120800b99b8Sopenharmony_ci    return ret;
121800b99b8Sopenharmony_ci}
122800b99b8Sopenharmony_ci
123800b99b8Sopenharmony_cibool GetBacktrace(std::string& out, size_t skipFrameNum, bool fast, size_t maxFrameNums)
124800b99b8Sopenharmony_ci{
125800b99b8Sopenharmony_ci    ElapsedTime et;
126800b99b8Sopenharmony_ci    bool ret = GetBacktraceStringByTid(out, BACKTRACE_CURRENT_THREAD, skipFrameNum + 1, fast, maxFrameNums, false);
127800b99b8Sopenharmony_ci    DFXLOGI("GetBacktrace with skip, elapsed time: %{public}" PRId64 " ms", et.Elapsed<std::chrono::milliseconds>());
128800b99b8Sopenharmony_ci    return ret;
129800b99b8Sopenharmony_ci}
130800b99b8Sopenharmony_ci
131800b99b8Sopenharmony_cibool PrintTrace(int32_t fd, size_t maxFrameNums)
132800b99b8Sopenharmony_ci{
133800b99b8Sopenharmony_ci    return PrintBacktrace(fd, false, maxFrameNums);
134800b99b8Sopenharmony_ci}
135800b99b8Sopenharmony_ci
136800b99b8Sopenharmony_ciconst char* GetTrace(size_t skipFrameNum, size_t maxFrameNums)
137800b99b8Sopenharmony_ci{
138800b99b8Sopenharmony_ci    static std::string trace;
139800b99b8Sopenharmony_ci    trace.clear();
140800b99b8Sopenharmony_ci    if (!GetBacktrace(trace, skipFrameNum, false, maxFrameNums)) {
141800b99b8Sopenharmony_ci        DFXLOGE("Failed to get trace string");
142800b99b8Sopenharmony_ci    }
143800b99b8Sopenharmony_ci    return trace.c_str();
144800b99b8Sopenharmony_ci}
145800b99b8Sopenharmony_ci
146800b99b8Sopenharmony_cistd::string GetProcessStacktrace(size_t maxFrameNums, bool enableKernelStack)
147800b99b8Sopenharmony_ci{
148800b99b8Sopenharmony_ci    auto unwinder = std::make_shared<Unwinder>();
149800b99b8Sopenharmony_ci    std::string ss = "\n" + GetStacktraceHeader();
150800b99b8Sopenharmony_ci    std::function<bool(int)> func = [&](int tid) {
151800b99b8Sopenharmony_ci        if (tid <= 0 || tid == gettid()) {
152800b99b8Sopenharmony_ci            return false;
153800b99b8Sopenharmony_ci        }
154800b99b8Sopenharmony_ci        BacktraceLocalThread thread(tid, unwinder);
155800b99b8Sopenharmony_ci        if (thread.Unwind(false, maxFrameNums, 0)) {
156800b99b8Sopenharmony_ci            ss += thread.GetFormattedStr(true) + "\n";
157800b99b8Sopenharmony_ci        } else if (enableKernelStack) {
158800b99b8Sopenharmony_ci            std::string msg = "";
159800b99b8Sopenharmony_ci            DfxThreadStack threadStack;
160800b99b8Sopenharmony_ci            if (DfxGetKernelStack(tid, msg) == 0 && FormatThreadKernelStack(msg, threadStack)) {
161800b99b8Sopenharmony_ci                thread.SetFrames(threadStack.frames);
162800b99b8Sopenharmony_ci                ss += thread.GetFormattedStr(true) + "\n";
163800b99b8Sopenharmony_ci                DFXLOGI("Failed to get tid(%{public}d) user stack, try kernel", tid);
164800b99b8Sopenharmony_ci            }
165800b99b8Sopenharmony_ci        }
166800b99b8Sopenharmony_ci        return true;
167800b99b8Sopenharmony_ci    };
168800b99b8Sopenharmony_ci
169800b99b8Sopenharmony_ci    std::vector<int> tids;
170800b99b8Sopenharmony_ci    GetTidsByPidWithFunc(getpid(), tids, func);
171800b99b8Sopenharmony_ci
172800b99b8Sopenharmony_ci    return ss;
173800b99b8Sopenharmony_ci}
174800b99b8Sopenharmony_ci} // namespace HiviewDFX
175800b99b8Sopenharmony_ci} // namespace OHOS
176