• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #include "dfx_crash_local_handler.h"
16 
17 #include <libunwind.h>
18 #include <libunwind_i-ohos.h>
19 #include <map_info.h>
20 #include <securec.h>
21 #include <signal.h>
22 #include <sys/ucontext.h>
23 #include <unistd.h>
24 #include "dfx_log.h"
25 #include "dfx_signal_handler.h"
26 #include "faultloggerd_client.h"
27 
28 #define MAX_FRAME 64
29 #define BUF_SZ 512
30 
31 #if defined(__arm__)
32 typedef enum ARM_REG {
33     ARM_R0 = 0,
34     ARM_R1,
35     ARM_R2,
36     ARM_R3,
37     ARM_R4,
38     ARM_R5,
39     ARM_R6,
40     ARM_R7,
41     ARM_R8,
42     ARM_R9,
43     ARM_R10,
44     ARM_FP,
45     ARM_IP,
46     ARM_SP,
47     ARM_LR,
48     ARM_PC
49 } ARM_REG;
50 #endif
51 
RequestOutputLogFile(const struct ProcessDumpRequest * request)52 __attribute__((noinline)) int RequestOutputLogFile(const struct ProcessDumpRequest* request)
53 {
54     struct FaultLoggerdRequest faultloggerdRequest;
55     if (memset_s(&faultloggerdRequest, sizeof(faultloggerdRequest), 0, sizeof(struct FaultLoggerdRequest)) != 0) {
56         return -1;
57     }
58 
59     faultloggerdRequest.type = (int32_t)CPP_CRASH;
60     faultloggerdRequest.pid = request->pid;
61     faultloggerdRequest.tid = request->tid;
62     faultloggerdRequest.uid = request->uid;
63     faultloggerdRequest.time = request->timeStamp + 1;
64     if (strncpy_s(faultloggerdRequest.module, sizeof(faultloggerdRequest.module),
65         request->processName, sizeof(faultloggerdRequest.module) - 1) != 0) {
66         return -1;
67     }
68 
69     return RequestFileDescriptorEx(&faultloggerdRequest);
70 }
71 
PrintLog(int fd,const char * format,...)72 __attribute__((noinline)) void PrintLog(int fd, const char *format, ...)
73 {
74     char buf[BUF_SZ] = {0};
75     (void)memset_s(&buf, sizeof(buf), 0, sizeof(buf));
76     va_list args;
77     va_start(args, format);
78     int size = vsnprintf_s(buf, sizeof(buf), sizeof(buf) - 1, format, args);
79     va_end(args);
80     if (size == -1) {
81         if (fd > 0) {
82             const char* error = "PrintLog vsnprintf_s fail\n";
83             (void)write(fd, error, strlen(error));
84         }
85         return;
86     }
87     DfxLogError(buf);
88     if (fd > 0) {
89         (void)write(fd, buf, strlen(buf));
90     }
91 }
92 
CrashLocalUnwind(const int fd,const ucontext_t * uc)93 __attribute__((noinline)) void CrashLocalUnwind(const int fd, const ucontext_t* uc)
94 {
95     unw_cursor_t* cursor = NULL;
96     unw_context_t* context = NULL;
97     GET_MEMORY(cursor, sizeof(unw_cursor_t));
98     GET_MEMORY(context, sizeof(unw_context_t));
99     if (!context || !cursor) {
100         PrintLog(fd, "Fail to mmap, errno(%d).", errno);
101         goto out;
102     }
103 
104 #if defined(__arm__)
105     context->regs[ARM_R0] = uc->uc_mcontext.arm_r0;
106     context->regs[ARM_R1] = uc->uc_mcontext.arm_r1;
107     context->regs[ARM_R2] = uc->uc_mcontext.arm_r2;
108     context->regs[ARM_R3] = uc->uc_mcontext.arm_r3;
109     context->regs[ARM_R4] = uc->uc_mcontext.arm_r4;
110     context->regs[ARM_R5] = uc->uc_mcontext.arm_r5;
111     context->regs[ARM_R6] = uc->uc_mcontext.arm_r6;
112     context->regs[ARM_R7] = uc->uc_mcontext.arm_r7;
113     context->regs[ARM_R8] = uc->uc_mcontext.arm_r8;
114     context->regs[ARM_R9] = uc->uc_mcontext.arm_r9;
115     context->regs[ARM_R10] = uc->uc_mcontext.arm_r10;
116     context->regs[ARM_FP] = uc->uc_mcontext.arm_fp;
117     context->regs[ARM_IP] = uc->uc_mcontext.arm_ip;
118     context->regs[ARM_SP] = uc->uc_mcontext.arm_sp;
119     context->regs[ARM_LR] = uc->uc_mcontext.arm_lr;
120     context->regs[ARM_PC] = uc->uc_mcontext.arm_pc;
121 #else
122     // the ucontext.uc_mcontext.__reserved of libunwind is simplified with the system's own in aarch64
123     if (memcpy_s(context, sizeof(unw_context_t), uc, sizeof(unw_context_t)) != 0) {
124         PrintLog(fd, "memcpy_s context error.");
125         goto out;
126     }
127 #endif
128 
129     if (unw_init_local(cursor, context) != 0) {
130         PrintLog(fd, "Fail to init local unwind context.\n");
131         goto out;
132     }
133 
134     unw_word_t pc;
135     unw_word_t sp;
136     unw_word_t relPc;
137     unw_word_t offset;
138     unw_word_t sz;
139     unw_word_t prevPc;
140     size_t index = 0;
141     while (true) {
142         if (index > MAX_FRAME) {
143             PrintLog(fd, "reach max unwind frame count, stop.\n");
144             break;
145         }
146 
147         if (unw_get_reg(cursor, UNW_REG_IP, (unw_word_t*)(&pc))) {
148             PrintLog(fd, "Failed to get current pc, stop.\n");
149             break;
150         }
151 
152         if (index > 1 && prevPc == pc) {
153             PrintLog(fd, "repeated pc(%p), stop.\n", pc);
154             break;
155         }
156         prevPc = pc;
157 
158         relPc = unw_get_rel_pc(cursor);
159         struct map_info* mapInfo = unw_get_map(cursor);
160         if (mapInfo == NULL && index > 1) {
161             PrintLog(fd, "Invalid frame for pc(%p).\n", relPc);
162         }
163 
164         sz = unw_get_previous_instr_sz(cursor);
165         if (index > 0 && relPc != 0) {
166             relPc -= sz;
167         }
168 
169         char symbol[BUF_SZ] = {0};
170         memset_s(&symbol, sizeof(symbol), 0, sizeof(symbol));
171         if (unw_get_proc_name(cursor, symbol, sizeof(symbol), (unw_word_t*)(&offset)) == 0) {
172             PrintLog(fd, "#%02d %016p %s(%s+%lu)\n", index, relPc,
173                 mapInfo == NULL ? "Unknown" : mapInfo->path,
174                 symbol, offset);
175         } else {
176             PrintLog(fd, "#%02d %016p %s\n", index, relPc,
177                 mapInfo == NULL ? "Unknown" : mapInfo->path);
178         }
179         index++;
180 
181         int ret = unw_step(cursor);
182         if (ret < 0) {
183             PrintLog(fd, "Unwind step stop, reason:%d.\n", ret);
184             break;
185         } else if (ret == 0) {
186             DfxLogInfo("Unwind step finish\n");
187             break;
188         }
189     }
190 out:
191     if (cursor != NULL) {
192         munmap(cursor, sizeof(unw_cursor_t));
193     }
194     if (context != NULL) {
195         munmap(context, sizeof(unw_context_t));
196     }
197     if (fd >= 0) {
198         close(fd);
199     }
200 }
201 
202 // currently, only stacktrace is logged to faultloggerd
CrashLocalHandler(const struct ProcessDumpRequest * request)203 void CrashLocalHandler(const struct ProcessDumpRequest* request)
204 {
205     int fd = RequestOutputLogFile(request);
206     CrashLocalHandlerFd(fd, request);
207 }
208 
CrashLocalHandlerFd(const int fd,const struct ProcessDumpRequest * request)209 void CrashLocalHandlerFd(const int fd, const struct ProcessDumpRequest* request)
210 {
211     PrintLog(fd, "Pid:%d\n", request->pid);
212     PrintLog(fd, "Uid:%d\n", request->uid);
213     PrintLog(fd, "Process name:%s\n", request->processName);
214     PrintLog(fd, "Reason:Signal(%d)\n", request->siginfo.si_signo);
215     PrintLog(fd, "Tid:%d, Name:%s\n", request->tid, request->threadName);
216 
217     CrashLocalUnwind(fd, &(request->context));
218 }