• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright (c) 2021 Huawei Device Co., Ltd.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <pthread.h>
19 #include <sched.h>
20 #include <signal.h>
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <sys/capability.h>
25 #include <sys/mman.h>
26 #include <sys/prctl.h>
27 #include <sys/syscall.h>
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <sys/uio.h>
31 #include <sys/wait.h>
32 #include <linux/futex.h>
33 
34 #include <libunwind.h>
35 #include <libunwind_i-ohos.h>
36 
37 #include "beget_ext.h"
38 #include "securec.h"
39 #include "init_cmds.h"
40 #include "init_log.h"
41 #include "crash_handler.h"
42 
43 #define BEGET_DFX_CHECK(fd, retCode, exper, fmt, ...) \
44     if (!(retCode)) {                \
45         PrintLog(fd, fmt, ##__VA_ARGS__);     \
46         BEGET_LOGE(fmt, ##__VA_ARGS__);       \
47         exper;                       \
48     }
49 
50 static unw_addr_space_t g_addrSpace = NULL;
51 static void *g_reservedChildStack = NULL;
52 static ProcessDumpRequest g_request;
53 static const SignalInfo g_platformSignals[] = {
54     { SIGABRT, "SIGABRT" },
55     { SIGBUS, "SIGBUS" },
56     { SIGFPE, "SIGFPE" },
57     { SIGILL, "SIGILL" },
58     { SIGSEGV, "SIGSEGV" },
59 #if defined(SIGSTKFLT)
60     { SIGSTKFLT, "SIGSTKFLT" },
61 #endif
62     { SIGSYS, "SIGSYS" },
63     { SIGTRAP, "SIGTRAP" },
64 };
65 
PrintLog(int fd,const char * format,...)66 __attribute__((noinline)) void PrintLog(int fd, const char *format, ...)
67 {
68     char buf[BUF_SZ] = {0};
69     va_list args;
70     va_start(args, format);
71     int size = vsnprintf_s(buf, sizeof(buf), sizeof(buf) - 1, format, args);
72     if (size == -1) {
73         BEGET_LOGE("Failed to sprintf %s", format);
74         va_end(args);
75         return;
76     }
77     va_end(args);
78     if (fd < 0) {
79         return;
80     }
81     (void)write(fd, buf, strlen(buf));
82 }
83 
SetRegister(unw_context_t * context,const ucontext_t * uc)84 static int SetRegister(unw_context_t *context, const ucontext_t *uc)
85 {
86 #if defined(__arm__)
87     (void)memset_s(context, sizeof(*context), 0, sizeof(*context));
88     context->regs[ARM_R0] = uc->uc_mcontext.arm_r0;
89     context->regs[ARM_R1] = uc->uc_mcontext.arm_r1;
90     context->regs[ARM_R2] = uc->uc_mcontext.arm_r2;
91     context->regs[ARM_R3] = uc->uc_mcontext.arm_r3;
92     context->regs[ARM_R4] = uc->uc_mcontext.arm_r4;
93     context->regs[ARM_R5] = uc->uc_mcontext.arm_r5;
94     context->regs[ARM_R6] = uc->uc_mcontext.arm_r6;
95     context->regs[ARM_R7] = uc->uc_mcontext.arm_r7;
96     context->regs[ARM_R8] = uc->uc_mcontext.arm_r8;
97     context->regs[ARM_R9] = uc->uc_mcontext.arm_r9;
98     context->regs[ARM_R10] = uc->uc_mcontext.arm_r10;
99     context->regs[ARM_FP] = uc->uc_mcontext.arm_fp;
100     context->regs[ARM_IP] = uc->uc_mcontext.arm_ip;
101     context->regs[ARM_SP] = uc->uc_mcontext.arm_sp;
102     context->regs[ARM_LR] = uc->uc_mcontext.arm_lr;
103     context->regs[ARM_PC] = uc->uc_mcontext.arm_pc;
104     BEGET_LOGE("fp:%08x ip:%08x sp:%08x lr:%08x pc:%08x\n",
105         uc->uc_mcontext.arm_fp, uc->uc_mcontext.arm_ip, uc->uc_mcontext.arm_sp,
106         uc->uc_mcontext.arm_lr, uc->uc_mcontext.arm_pc);
107 #elif defined(__aarch64__)
108     // the ucontext.uc_mcontext.__reserved of libunwind is simplified with the system's own in aarch64
109     if (memcpy_s(context, sizeof(unw_context_t), uc, sizeof(unw_context_t)) != 0) {
110         return -1;
111     }
112 #endif
113     return 0;
114 }
115 
PrintfRegister(const unw_context_t * context,int fd)116 static void PrintfRegister(const unw_context_t *context, int fd)
117 {
118     PrintLog(fd, "Registers:\n");
119 #if defined(__arm__)
120     PrintLog(fd, "r0:%08x r1:%08x r2:%08x r3:%08x\n",
121         context->regs[ARM_R0], context->regs[ARM_R1], context->regs[ARM_R2], context->regs[ARM_R3]);
122     PrintLog(fd, "r4:%08x r5:%08x r6:%08x r7:%08x\n",
123         context->regs[ARM_R4], context->regs[ARM_R5], context->regs[ARM_R6], context->regs[ARM_R7]);
124     PrintLog(fd, "r8:%08x r9:%08x r10:%08x\n",
125         context->regs[ARM_R8], context->regs[ARM_R9], context->regs[ARM_R10]);
126     PrintLog(fd, "fp:%08x ip:%08x sp:%08x lr:%08x pc:%08x\n",
127         context->regs[ARM_FP], context->regs[ARM_IP], context->regs[ARM_SP],
128         context->regs[ARM_LR], context->regs[ARM_PC]);
129 #elif defined(__aarch64__)
130     PrintLog(fd, "x0:%016lx x1:%016lx x2:%016lx x3:%016lx\n", \
131         context->uc_mcontext.regs[AARCH64_X0], context->uc_mcontext.regs[AARCH64_X1],
132         context->uc_mcontext.regs[AARCH64_X2], context->uc_mcontext.regs[AARCH64_X3]);
133     PrintLog(fd, "x4:%016lx x5:%016lx x6:%016lx x7:%016lx\n", \
134         context->uc_mcontext.regs[AARCH64_X4], context->uc_mcontext.regs[AARCH64_X5],
135         context->uc_mcontext.regs[AARCH64_X6], context->uc_mcontext.regs[AARCH64_X7]);
136     PrintLog(fd, "x8:%016lx x9:%016lx x10:%016lx x11:%016lx\n", \
137         context->uc_mcontext.regs[AARCH64_X8], context->uc_mcontext.regs[AARCH64_X9],
138         context->uc_mcontext.regs[AARCH64_X10], context->uc_mcontext.regs[AARCH64_X11]);
139     PrintLog(fd, "x12:%016lx x13:%016lx x14:%016lx x15:%016lx\n", \
140         context->uc_mcontext.regs[AARCH64_X12], context->uc_mcontext.regs[AARCH64_X13],
141         context->uc_mcontext.regs[AARCH64_X14], context->uc_mcontext.regs[AARCH64_X15]);
142     PrintLog(fd, "x16:%016lx x17:%016lx x18:%016lx x19:%016lx\n", \
143         context->uc_mcontext.regs[AARCH64_X16], context->uc_mcontext.regs[AARCH64_X17],
144         context->uc_mcontext.regs[AARCH64_X18], context->uc_mcontext.regs[AARCH64_X19]);
145     PrintLog(fd, "x20:%016lx x21:%016lx x22:%016lx x23:%016lx\n", \
146         context->uc_mcontext.regs[AARCH64_X20], context->uc_mcontext.regs[AARCH64_X21],
147         context->uc_mcontext.regs[AARCH64_X22], context->uc_mcontext.regs[AARCH64_X23]);
148     PrintLog(fd, "x24:%016lx x25:%016lx x26:%016lx x27:%016lx\n", \
149         context->uc_mcontext.regs[AARCH64_X24], context->uc_mcontext.regs[AARCH64_X25],
150         context->uc_mcontext.regs[AARCH64_X26], context->uc_mcontext.regs[AARCH64_X27]);
151     PrintLog(fd, "x28:%016lx x29:%016lx\n", \
152         context->uc_mcontext.regs[AARCH64_X28], context->uc_mcontext.regs[AARCH64_X29]);
153     PrintLog(fd, "lr:%016lx sp:%016lx pc:%016lx\n", \
154         context->uc_mcontext.regs[AARCH64_X30], context->uc_mcontext.sp, context->uc_mcontext.pc);
155 #endif
156 }
157 
GetTimeMilliseconds(void)158 static uint64_t GetTimeMilliseconds(void)
159 {
160     struct timeval time;
161     gettimeofday(&time, NULL);
162     return ((uint64_t)time.tv_sec * 1000) +    // 1000 : second to millisecond convert ratio
163            (((uint64_t)time.tv_usec) / 1000);  // 1000 : microsecond to millisecond convert ratio
164 }
165 
GetSignalName(const int32_t signal)166 const char *GetSignalName(const int32_t signal)
167 {
168     for (size_t i = 0; i < sizeof(g_platformSignals) / sizeof(g_platformSignals[0]); i++) {
169         if (signal == g_platformSignals[i].sigNo) {
170             return g_platformSignals[i].name;
171         }
172     }
173     return "Uncare Signal";
174 }
175 
ExecLocalDumpUnwinding(int fd,unw_context_t * ctx,size_t skipFrameNum)176 __attribute__((noinline)) void ExecLocalDumpUnwinding(int fd, unw_context_t *ctx, size_t skipFrameNum)
177 {
178     unw_cursor_t cursor;
179     unw_init_local_with_as(g_addrSpace, &cursor, ctx);
180 
181     size_t index = 0;
182     unw_word_t pc = 0;
183     unw_word_t prevPc = 0;
184     unw_word_t offset = 0;
185     char symbol[SYMBOL_BUF_SIZE];
186     do {
187         // skip 0 stack, as this is dump catcher. Caller don't need it.
188         if (index < skipFrameNum) {
189             index++;
190             continue;
191         }
192         int ret = unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *)(&pc));
193         BEGET_DFX_CHECK(fd, ret == 0, break, "Failed to get current pc, stop.\n");
194         size_t curIndex = index - skipFrameNum;
195         BEGET_DFX_CHECK(fd, !(curIndex > 1 && prevPc == pc), break, "Invalid pc %l %l, stop.", prevPc, pc);
196         prevPc = pc;
197 
198         unw_word_t relPc = unw_get_rel_pc(&cursor);
199         unw_word_t sz = unw_get_previous_instr_sz(&cursor);
200         if ((curIndex > 0) && (relPc > sz)) {
201             relPc -= sz;
202             pc -= sz;
203 #if defined(__arm__)
204             unw_set_adjust_pc(&cursor, pc);
205 #endif
206         }
207 
208         struct map_info *map = unw_get_map(&cursor);
209         (void)memset_s(&symbol, sizeof(symbol), 0, sizeof(symbol));
210         if (unw_get_proc_name(&cursor, symbol, sizeof(symbol), (unw_word_t *)(&offset)) == 0) {
211             PrintLog(fd, "#%02d %016p %s(%s+%lu)\n",
212                 curIndex, relPc, map == NULL ? "Unknown" : map->path, symbol, offset);
213         } else {
214             PrintLog(fd, "#%02d %016p %s\n", curIndex, relPc, map == NULL ? "Unknown" : map->path);
215         }
216         index++;
217     } while ((unw_step(&cursor) > 0) && (index < BACK_STACK_MAX_STEPS));
218     return;
219 }
220 
CrashLocalHandler(const ProcessDumpRequest * request)221 static void CrashLocalHandler(const ProcessDumpRequest *request)
222 {
223     int fd = GetKmsgFd();
224     BEGET_ERROR_CHECK(fd >= 0, return, "Invalid fd");
225 
226     PrintLog(fd, "Pid:%d\n", request->pid);
227     PrintLog(fd, "Uid:%d\n", request->uid);
228     PrintLog(fd, "Reason:Signal(%s)\n", GetSignalName(request->siginfo.si_signo));
229 
230     unw_context_t context;
231     SetRegister(&context, &(request->context));
232     ExecLocalDumpUnwinding(fd, &context, 0);
233     PrintfRegister(&context, fd);
234     (void)fsync(fd);
235     (void)close(fd);
236 }
237 
ReserveChildThreadSignalStack(void)238 static void ReserveChildThreadSignalStack(void)
239 {
240     // reserve stack for fork
241     g_reservedChildStack = mmap(NULL, LOCAL_HANDLER_STACK_SIZE, PROT_READ | PROT_WRITE,
242                                 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
243     if (g_reservedChildStack == NULL) {
244         BEGET_LOGE("Failed to alloc memory for child stack.");
245         return;
246     }
247     g_reservedChildStack = (void *)(((uint8_t *)g_reservedChildStack) + LOCAL_HANDLER_STACK_SIZE - 1);
248 }
249 
DoCrashHandler(void * arg)250 static int DoCrashHandler(void *arg)
251 {
252     BEGET_LOGI("DoCrashHandler");
253     (void)arg;
254     CrashLocalHandler(&g_request);
255     ExecReboot("panic");
256     return 0;
257 }
258 
SignalHandler(int sig,siginfo_t * si,void * context)259 static void SignalHandler(int sig, siginfo_t *si, void *context)
260 {
261     (void)memset_s(&g_request, sizeof(g_request), 0, sizeof(g_request));
262     g_request.type = sig;
263     g_request.tid = gettid();
264     g_request.pid = getpid();
265     g_request.timeStamp = GetTimeMilliseconds();
266     BEGET_LOGI("CrashHandler :: sig(%d), pid(%d), tid(%d).", sig, g_request.pid, g_request.tid);
267 
268     int ret = memcpy_s(&(g_request.siginfo), sizeof(siginfo_t), si, sizeof(siginfo_t));
269     if (ret < 0) {
270         BEGET_LOGE("memcpy_s siginfo fail, ret=%d", ret);
271     }
272     ret = memcpy_s(&(g_request.context), sizeof(ucontext_t), context, sizeof(ucontext_t));
273     if (ret < 0) {
274         BEGET_LOGE("memcpy_s context fail, ret=%d", ret);
275     }
276 
277     int pseudothreadTid = -1;
278     pid_t childTid = clone(DoCrashHandler, g_reservedChildStack,
279                            CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID,
280                            &pseudothreadTid, NULL, NULL, &pseudothreadTid);
281     if (childTid == -1) {
282         BEGET_LOGE("Failed to create thread for crash local handler");
283         ExecReboot("panic");
284     } else {
285         sleep(5); // wait 5s
286         ExecReboot("panic");
287     }
288 
289     BEGET_LOGI("child thread(%d) exit.", childTid);
290     unw_destroy_local_address_space(g_addrSpace);
291 }
292 
InstallLocalSignalHandler(void)293 void InstallLocalSignalHandler(void)
294 {
295     ReserveChildThreadSignalStack();
296     unw_init_local_address_space(&g_addrSpace);
297     sigset_t set;
298     sigemptyset(&set);
299     struct sigaction action;
300     memset_s(&action, sizeof(action), 0, sizeof(action));
301     action.sa_sigaction = SignalHandler;
302     action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
303 
304     for (size_t i = 0; i < sizeof(g_platformSignals) / sizeof(g_platformSignals[0]); i++) {
305         int32_t sig = g_platformSignals[i].sigNo;
306         sigemptyset(&action.sa_mask);
307         sigaddset(&action.sa_mask, sig);
308 
309         sigaddset(&set, sig);
310         if (sigaction(sig, &action, NULL) != 0) {
311             BEGET_LOGE("Failed to register signal(%d)", sig);
312         }
313     }
314     sigprocmask(SIG_UNBLOCK, &set, NULL);
315 }