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 "c/ffrt_dump.h"
23 #include "dfx/bbox/bbox.h"
24 #include "internal_inc/osal.h"
25 #include "dfx/log/ffrt_log_api.h"
26 #include "dfx/trace_record/ffrt_trace_record.h"
27 #include "dump.h"
28
29 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
30 using namespace OHOS::HiviewDFX;
31 #endif
32
33 namespace ffrt {
34 constexpr uint32_t DEFAULT_TIMEOUT_MS = 30000;
35 struct TimeoutCfg {
Instanceffrt::TimeoutCfg36 static inline TimeoutCfg* Instance()
37 {
38 static TimeoutCfg inst;
39 return &inst;
40 }
41
42 uint32_t timeout = DEFAULT_TIMEOUT_MS;
43 ffrt_task_timeout_cb callback = nullptr;
44 };
45
46 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
DumpTask(CPUEUTask * task,std::string & stackInfo,uint8_t flag)47 void DumpTask(CPUEUTask* task, std::string& stackInfo, uint8_t flag)
48 {
49 ucontext_t ctx;
50
51 if (ExecuteCtx::Cur()->task == task || task == nullptr) {
52 if (flag == 0) {
53 OHOS::HiviewDFX::PrintTrace(-1);
54 } else {
55 OHOS::HiviewDFX::GetBacktrace(stackInfo, false);
56 }
57 return;
58 } else {
59 memset_s(&ctx, sizeof(ctx), 0, sizeof(ctx));
60 #if defined(__aarch64__)
61 ctx.uc_mcontext.regs[REG_AARCH64_X29] = task->coRoutine->ctx.regs[10];
62 ctx.uc_mcontext.sp = task->coRoutine->ctx.regs[13];
63 ctx.uc_mcontext.pc = task->coRoutine->ctx.regs[11];
64 #elif defined(__x86_64__)
65 ctx.uc_mcontext.gregs[REG_RBX] = task->coRoutine->ctx.regs[0];
66 ctx.uc_mcontext.gregs[REG_RBP] = task->coRoutine->ctx.regs[1];
67 ctx.uc_mcontext.gregs[REG_RSP] = task->coRoutine->ctx.regs[6];
68 ctx.uc_mcontext.gregs[REG_RIP] = *(reinterpret_cast<greg_t *>(ctx.uc_mcontext.gregs[REG_RSP] - 8));
69 #elif defined(__arm__)
70 ctx.uc_mcontext.arm_sp = task->coRoutine->ctx.regs[0]; /* sp */
71 ctx.uc_mcontext.arm_pc = task->coRoutine->ctx.regs[1]; /* pc */
72 ctx.uc_mcontext.arm_lr = task->coRoutine->ctx.regs[1]; /* lr */
73 ctx.uc_mcontext.arm_fp = task->coRoutine->ctx.regs[10]; /* fp */
74 #endif
75 }
76
77 auto co = task->coRoutine;
78 uintptr_t stackBottom = reinterpret_cast<uintptr_t>(reinterpret_cast<char*>(co) + sizeof(CoRoutine) - 8);
79 uintptr_t stackTop = static_cast<uintptr_t>(stackBottom + co->stkMem.size);
80 auto unwinder = std::make_shared<Unwinder>();
81 auto regs = DfxRegs::CreateFromUcontext(ctx);
82 unwinder->SetRegs(regs);
83 UnwindContext context;
84 context.pid = UNWIND_TYPE_LOCAL;
85 context.regs = regs;
86 context.maps = unwinder->GetMaps();
87 context.stackCheck = false;
88 context.stackBottom = stackBottom;
89 context.stackTop = stackTop;
90 bool resFlag = unwinder->Unwind(&context);
91 if (!resFlag) {
92 FFRT_LOGE("Call Unwind failed");
93 return;
94 }
95 std::ostringstream ss;
96 auto frames = unwinder->GetFrames();
97 if (flag != 0) {
98 ss << Unwinder::GetFramesStr(frames);
99 ss << std::endl;
100 stackInfo = ss.str();
101 return;
102 }
103 FFRT_LOGE("%s", Unwinder::GetFramesStr(frames).c_str());
104 }
105 #endif
106 }
107
108 #ifdef __cplusplus
109 extern "C" {
110 #endif //__cplusplus
111
112 API_ATTRIBUTE((visibility("default")))
dump_info_all(char * buf,uint32_t len)113 int dump_info_all(char *buf, uint32_t len)
114 {
115 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
116 if (FFRTIsWork()) {
117 std::string dumpInfo;
118 dumpInfo += "|-> Launcher proc ffrt, pid:" + std::to_string(GetPid()) + "\n";
119 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2)
120 dumpInfo += SaveTaskCounterInfo();
121 #endif
122 dumpInfo += SaveKeyInfo();
123 dumpInfo += SaveWorkerStatusInfo();
124 dumpInfo += SaveReadyQueueStatusInfo();
125 dumpInfo += SaveNormalTaskStatusInfo();
126 dumpInfo += SaveQueueTaskStatusInfo();
127 if (dumpInfo.length() > (len - 1)) {
128 FFRT_LOGW("dumpInfo exceeds the buffer length, length:%d", dumpInfo.length());
129 }
130 return snprintf_s(buf, len, len - 1, "%s", dumpInfo.c_str());
131 } else {
132 return snprintf_s(buf, len, len - 1, "|-> FFRT has done all tasks, pid: %u \n", GetPid());
133 }
134 #else
135 return -1;
136 #endif
137 }
138
139 API_ATTRIBUTE((visibility("default")))
ffrt_dump(ffrt_dump_cmd_t cmd,char * buf,uint32_t len)140 int ffrt_dump(ffrt_dump_cmd_t cmd, char *buf, uint32_t len)
141 {
142 FFRT_COND_RETURN_ERROR(buf == nullptr || len < 1, -1, "buf is nullptr or len is less than 1, len %u", len);
143 switch (cmd) {
144 case DUMP_INFO_ALL: {
145 return dump_info_all(buf, len);
146 }
147 case DUMP_TASK_STATISTIC_INFO: {
148 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2)
149 return ffrt::FFRTTraceRecord::StatisticInfoDump(buf, len);
150 #else
151 return -1;
152 #endif
153 }
154 default: {
155 FFRT_LOGE("ffrt_dump unsupport cmd[%d]", cmd);
156 }
157 }
158 return -1;
159 }
160
161 API_ATTRIBUTE((visibility("default")))
ffrt_task_timeout_get_cb(void)162 ffrt_task_timeout_cb ffrt_task_timeout_get_cb(void)
163 {
164 return ffrt::TimeoutCfg::Instance()->callback;
165 }
166
167 API_ATTRIBUTE((visibility("default")))
ffrt_task_timeout_set_cb(ffrt_task_timeout_cb cb)168 void ffrt_task_timeout_set_cb(ffrt_task_timeout_cb cb)
169 {
170 ffrt::TimeoutCfg::Instance()->callback = cb;
171 }
172
173 API_ATTRIBUTE((visibility("default")))
ffrt_task_timeout_get_threshold(void)174 uint32_t ffrt_task_timeout_get_threshold(void)
175 {
176 return ffrt::TimeoutCfg::Instance()->timeout;
177 }
178
179 API_ATTRIBUTE((visibility("default")))
ffrt_task_timeout_set_threshold(uint32_t threshold_ms)180 void ffrt_task_timeout_set_threshold(uint32_t threshold_ms)
181 {
182 ffrt::TimeoutCfg::Instance()->timeout = threshold_ms;
183 }
184 #ifdef __cplusplus
185 }
186 #endif
187