• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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