1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
16 #include <dlfcn.h>
17 #include <sstream>
18 #include "unwinder.h"
19 #include "backtrace_local.h"
20 #endif
21 #include <securec.h>
22 #include "dfx/bbox/bbox.h"
23 #include "internal_inc/osal.h"
24 #include "dfx/log/ffrt_log_api.h"
25 #include "dfx/trace_record/ffrt_trace_record.h"
26 #include "dump.h"
27
28 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
29 using namespace OHOS::HiviewDFX;
30 #endif
31
32 namespace ffrt {
33 constexpr uint32_t DEFAULT_TIMEOUT_MS = 30000;
34 struct TimeoutCfg {
Instanceffrt::TimeoutCfg35 static inline TimeoutCfg* Instance()
36 {
37 static TimeoutCfg inst;
38 return &inst;
39 }
40
41 uint32_t timeout = DEFAULT_TIMEOUT_MS;
42 ffrt_task_timeout_cb callback = nullptr;
43 };
44
45 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
DumpTask(CPUEUTask * task,std::string & stackInfo,uint8_t flag)46 void DumpTask(CPUEUTask* task, std::string& stackInfo, uint8_t flag)
47 {
48 ucontext_t ctx;
49
50 if (ExecuteCtx::Cur()->task == task || task == nullptr) {
51 if (flag == 0) {
52 OHOS::HiviewDFX::PrintTrace(-1);
53 } else {
54 OHOS::HiviewDFX::GetBacktrace(stackInfo, false);
55 }
56 return;
57 } else {
58 memset_s(&ctx, sizeof(ctx), 0, sizeof(ctx));
59 #if defined(__aarch64__)
60 ctx.uc_mcontext.regs[REG_AARCH64_X29] = task->coRoutine->ctx.regs[10];
61 ctx.uc_mcontext.sp = task->coRoutine->ctx.regs[13];
62 ctx.uc_mcontext.pc = task->coRoutine->ctx.regs[11];
63 #elif defined(__x86_64__)
64 ctx.uc_mcontext.gregs[REG_RBX] = task->coRoutine->ctx.regs[0];
65 ctx.uc_mcontext.gregs[REG_RBP] = task->coRoutine->ctx.regs[1];
66 ctx.uc_mcontext.gregs[REG_RSP] = task->coRoutine->ctx.regs[6];
67 ctx.uc_mcontext.gregs[REG_RIP] = *(reinterpret_cast<greg_t *>(ctx.uc_mcontext.gregs[REG_RSP] - 8));
68 #elif defined(__arm__)
69 ctx.uc_mcontext.arm_sp = task->coRoutine->ctx.regs[0]; /* sp */
70 ctx.uc_mcontext.arm_pc = task->coRoutine->ctx.regs[1]; /* pc */
71 ctx.uc_mcontext.arm_lr = task->coRoutine->ctx.regs[1]; /* lr */
72 ctx.uc_mcontext.arm_fp = task->coRoutine->ctx.regs[10]; /* fp */
73 #endif
74 }
75
76 auto co = task->coRoutine;
77 uintptr_t stackBottom = reinterpret_cast<uintptr_t>(reinterpret_cast<char*>(co) + sizeof(CoRoutine) - 8);
78 uintptr_t stackTop = static_cast<uintptr_t>(stackBottom + co->stkMem.size);
79 auto unwinder = std::make_shared<Unwinder>();
80 auto regs = DfxRegs::CreateFromUcontext(ctx);
81 unwinder->SetRegs(regs);
82 UnwindContext context;
83 context.pid = UNWIND_TYPE_LOCAL;
84 context.regs = regs;
85 context.maps = unwinder->GetMaps();
86 context.stackCheck = false;
87 context.stackBottom = stackBottom;
88 context.stackTop = stackTop;
89 bool resFlag = unwinder->Unwind(&context);
90 if (!resFlag) {
91 FFRT_LOGE("Call Unwind failed");
92 return;
93 }
94 std::ostringstream ss;
95 auto frames = unwinder->GetFrames();
96 if (flag != 0) {
97 ss << Unwinder::GetFramesStr(frames);
98 ss << std::endl;
99 stackInfo = ss.str();
100 return;
101 }
102 FFRT_LOGE("%s", Unwinder::GetFramesStr(frames).c_str());
103 }
104 #endif
105 }
106
107 #ifdef __cplusplus
108 extern "C" {
109 #endif //__cplusplus
110
111 API_ATTRIBUTE((visibility("default")))
dump_info_all(char * buf,uint32_t len)112 int dump_info_all(char *buf, uint32_t len)
113 {
114 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
115 if (FFRTIsWork()) {
116 std::string dumpInfo;
117 dumpInfo += GetDumpPreface();
118 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2)
119 dumpInfo += SaveTaskCounterInfo();
120 #endif
121 dumpInfo += SaveKeyInfo();
122 dumpInfo += SaveWorkerStatusInfo();
123 dumpInfo += SaveNormalTaskStatusInfo();
124 dumpInfo += SaveQueueTaskStatusInfo();
125 if (dumpInfo.length() > (len - 1)) {
126 FFRT_LOGW("dumpInfo exceeds the buffer length, info length:%d, input len:%u", dumpInfo.length(), len);
127 }
128 return snprintf_s(buf, len, len - 1, "%s", dumpInfo.c_str());
129 } else {
130 return snprintf_s(buf, len, len - 1, "|-> FFRT has done all tasks, pid: %u \n", GetPid());
131 }
132 #else
133 return -1;
134 #endif
135 }
136
137 API_ATTRIBUTE((visibility("default")))
ffrt_dump(ffrt_dump_cmd_t cmd,char * buf,uint32_t len)138 int ffrt_dump(ffrt_dump_cmd_t cmd, char *buf, uint32_t len)
139 {
140 FFRT_COND_RETURN_ERROR(buf == nullptr || len < 1, -1, "buf is nullptr or len is less than 1, len %u", len);
141 switch (cmd) {
142 case DUMP_INFO_ALL: {
143 return dump_info_all(buf, len);
144 }
145 case DUMP_TASK_STATISTIC_INFO: {
146 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2)
147 return ffrt::FFRTTraceRecord::StatisticInfoDump(buf, len);
148 #else
149 return -1;
150 #endif
151 }
152 case DUMP_START_STAT: {
153 return ffrt::FFRTTraceRecord::StatEnable(buf, len);
154 }
155 case DUMP_STOP_STAT: {
156 return ffrt::FFRTTraceRecord::StatsDisable(buf);
157 }
158 default: {
159 FFRT_LOGE("ffrt_dump unsupport cmd[%d]", cmd);
160 }
161 }
162 return -1;
163 }
164
165 API_ATTRIBUTE((visibility("default")))
ffrt_task_timeout_get_cb(void)166 ffrt_task_timeout_cb ffrt_task_timeout_get_cb(void)
167 {
168 return ffrt::TimeoutCfg::Instance()->callback;
169 }
170
171 API_ATTRIBUTE((visibility("default")))
ffrt_task_timeout_set_cb(ffrt_task_timeout_cb cb)172 void ffrt_task_timeout_set_cb(ffrt_task_timeout_cb cb)
173 {
174 FFRT_COND_DO_ERR((cb == nullptr), return, "input invalid, cb is nullptr");
175 ffrt::TimeoutCfg::Instance()->callback = cb;
176 }
177
178 API_ATTRIBUTE((visibility("default")))
ffrt_task_timeout_get_threshold(void)179 uint32_t ffrt_task_timeout_get_threshold(void)
180 {
181 return ffrt::TimeoutCfg::Instance()->timeout;
182 }
183
184 API_ATTRIBUTE((visibility("default")))
ffrt_task_timeout_set_threshold(uint32_t threshold_ms)185 void ffrt_task_timeout_set_threshold(uint32_t threshold_ms)
186 {
187 ffrt::TimeoutCfg::Instance()->timeout = threshold_ms;
188 }
189 #ifdef __cplusplus
190 }
191 #endif
192