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 }