Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "stacktrace_fp.h"
12 : #include <errno.h>
13 : #include <string.h>
14 : #include <ucontext.h>
15 : #include <fcntl.h>
16 : #include <pthread.h>
17 : #include "securec.h"
18 : #include "stacktrace_unwind_reg.h"
19 : #include "adiag_print.h"
20 : #include "adiag_utils.h"
21 : #include "trace_types.h"
22 : #include "trace_system_api.h"
23 :
24 : #define EXEC_READ_MAP "r"
25 : #define EXEC_MAP_ATTR "r-xp"
26 : #define OS_SPLIT '/'
27 : #define LR_OFFSET 8U
28 :
29 : /**
30 : * @brief get current pc self map
31 : * @param [in] pc: exception PC register
32 : * @param [out] data: exception map info
33 : * @param [in] len: data buffer length
34 : * @return TRACE_SUCCESS success; TRACE_FAILURE failure
35 : */
36 250 : STATIC TraStatus TraceGetSelfMap(uintptr_t pc, char *data, uint32_t len)
37 : {
38 250 : if (data == NULL || len == 0) {
39 0 : return TRACE_FAILURE;
40 : }
41 :
42 250 : int32_t fd = open(SELF_MAP_PATH, O_RDONLY);
43 250 : if (fd < 0) {
44 0 : LOGW("self map fopen null");
45 0 : return TRACE_FAILURE;
46 : }
47 :
48 250 : char *vmPath = NULL;
49 250 : uintptr_t vmStart = 0;
50 250 : uintptr_t vmEnd = 0;
51 250 : char currentPath[CORE_BUFFER_LEN] = { 0 };
52 250 : uintptr_t baseAddr = 0; // the minimum addr of load segment
53 12337 : while (TraceSafeReadLine(fd, data, len) > 0) {
54 12286 : vmPath = strchr(data, OS_SPLIT);
55 12286 : if (vmPath == NULL) {
56 3098 : continue;
57 : }
58 9188 : if (sscanf_s(data, "%lx-%lx", &vmStart, &vmEnd) <= 0) {
59 0 : continue;
60 : }
61 :
62 9188 : if (strcmp(currentPath, vmPath) != 0) {
63 1255 : errno_t err = strncpy_s(currentPath, CORE_BUFFER_LEN, vmPath, CORE_BUFFER_LEN - 1U);
64 1255 : if (err != 0) {
65 0 : LOGE("copy vmPath to currentPath failed.");
66 0 : break;
67 : }
68 1255 : baseAddr = vmStart; // update baseAddr when path change
69 : }
70 : // pcAddr is in code-segment(r-xp)
71 9188 : if ((pc < vmStart) || (pc > vmEnd) || (strstr(data, EXEC_MAP_ATTR) == NULL)) {
72 8989 : continue;
73 : }
74 :
75 199 : int32_t ret = snprintf_s(data, len, (size_t)len - 1U, "0x%016lx %s", baseAddr, currentPath);
76 199 : if (ret == -1) {
77 0 : LOGE("snprintf_s map info failed");
78 0 : break;
79 : }
80 199 : TraceClose(&fd);
81 199 : return TRACE_SUCCESS;
82 : }
83 51 : TraceClose(&fd);
84 51 : return TRACE_FAILURE;
85 : }
86 :
87 : /**
88 : * @brief reason the stack frame by FP
89 : * @param [in] layer: exception layer
90 : * @param [in] fp: exception FP register
91 : * @param [out] data: exception info
92 : * @param [in] len: data buffer length
93 : * @return 0 reason end; other continue to reason
94 : */
95 330 : STATIC uintptr_t TraceStackFrame(int32_t layer, uintptr_t fp, char *data, size_t len)
96 : {
97 330 : uintptr_t nfp = 0;
98 330 : uintptr_t pc = 0;
99 330 : char info[CORE_BUFFER_LEN] = { 0 };
100 330 : if (fp == 0 || layer >= MAX_STACK_LAYER || data == NULL || len == 0) {
101 80 : return 0;
102 : }
103 :
104 250 : if (layer == 0) { // current pc frame
105 75 : pc = fp;
106 75 : nfp = pc;
107 : } else { // fp inference pc frame
108 175 : uintptr_t lr = fp + LR_OFFSET;
109 175 : if (lr < fp) {
110 0 : return 0;
111 : }
112 175 : pc = *(uintptr_t *)lr;
113 175 : nfp = *(uintptr_t *)fp;
114 : }
115 : int32_t ret;
116 250 : if (TraceGetSelfMap(pc, info, (uint32_t)sizeof(info)) != TRACE_SUCCESS) {
117 51 : ret = snprintf_s(data, len, len - 1U, "invalid pc address 0x%016lx, can not reason stack.\n", pc);
118 51 : if (ret == -1) {
119 0 : LOGE("snprintf_s core info failed");
120 : }
121 51 : return 0;
122 : }
123 199 : ret = snprintf_s(data, len, len - 1U, "#%02d 0x%016lx %s", layer, pc, info);
124 199 : if (ret == -1) {
125 0 : LOGE("snprintf_s core info failed");
126 0 : return 0;
127 : }
128 199 : return nfp;
129 : }
130 :
131 : /**
132 : * @brief reason the stack frame by PC
133 : * @param [in] layer: exception layer
134 : * @param [in] pc: current pc
135 : * @param [out] data: exception info
136 : * @param [in] len: data buffer length
137 : */
138 155 : STATIC void TraceStackPcFrame(int32_t layer, uintptr_t pc, char *data, size_t len)
139 : {
140 155 : if (layer >= MAX_STACK_LAYER || data == NULL || len == 0) {
141 0 : return;
142 : }
143 :
144 155 : if (pc == 0) { // current pc frame
145 80 : int32_t ret = snprintf_s(data, len, len - 1U, "#%d 0x%016lx 0x%016lx %s\n",
146 : layer, pc, pc, program_invocation_name);
147 80 : if (ret == -1) {
148 0 : LOGE("snprintf_s core info failed");
149 : }
150 : }
151 155 : (void)TraceStackFrame(layer, pc, data, len);
152 : }
153 :
154 : /**
155 : * @brief check rbp register value is valid or not
156 : * @param [in] rbp: exception BP register
157 : * @param [in] rsp: exception SP register
158 : * @return true valid; false invalid
159 : */
160 175 : STATIC bool TraceCheckRegister(uintptr_t rbp, uintptr_t rsp, uintptr_t stackBaseAddr)
161 : {
162 175 : if ((rbp >= rsp) && (rbp < stackBaseAddr)) {
163 155 : return true;
164 : }
165 :
166 20 : return false;
167 : }
168 :
169 : /**
170 : * @brief derivation stack by fp
171 : * @param [in] arg: argument
172 : * @param [in] regs: register info
173 : * @param [in] regNum: number of register
174 : * @param [out] stackInfo: buffer to save stack info
175 : * @return TraStatus
176 : */
177 255 : TraStatus TraceStackFp(const ThreadArgument *arg, uintptr_t *regs, uint32_t regNum, TraceStackInfo *stackInfo)
178 : {
179 255 : if (regs == NULL || arg == NULL || stackInfo == NULL || regNum < MAX_USE_REG_NUM) {
180 60 : return TRACE_INVALID_PARAM;
181 : }
182 :
183 195 : uintptr_t fp = GET_FPREG(regs);
184 195 : uintptr_t sp = GET_SPREG(regs);
185 195 : uintptr_t pc = GET_PCREG(regs);
186 :
187 195 : int32_t layer = 0;
188 195 : stackInfo->layer = -1;
189 195 : char info[CORE_BUFFER_LEN] = { 0 };
190 195 : if (!TraceCheckRegister(fp, sp, arg->stackBaseAddr)) {
191 40 : int32_t ret = snprintf_s(info, CORE_BUFFER_LEN, CORE_BUFFER_LEN - 1U,
192 40 : "invalid register value, stack_start_addr=0x%016lx rbp=0x%016lx rsp=0x%016lx \n\n", arg->stackBaseAddr, fp, sp);
193 40 : if (ret != -1) {
194 40 : (void)memcpy_s(&stackInfo->errLog, CORE_BUFFER_LEN, info, strlen(info));
195 : }
196 40 : return TRACE_FAILURE;
197 : }
198 :
199 : // save pc frame info
200 155 : TraceStackPcFrame(layer, pc, info, sizeof(info));
201 155 : errno_t err = memcpy_s(&stackInfo->frame[0].info, CORE_BUFFER_LEN, info, strlen(info));
202 155 : if (err != EOK) {
203 20 : LOGE("memcpy pc frame failed, ret=%d", err);
204 20 : return TRACE_FAILURE;
205 : }
206 135 : stackInfo->layer = 0;
207 :
208 : // save stack frame info
209 135 : uintptr_t nfp = fp;
210 310 : while ((fp != 0) && (fp >= nfp) && (layer < MAX_STACK_LAYER - 1)) {
211 175 : layer++;
212 175 : fp = TraceStackFrame(layer, fp, info, sizeof(info));
213 175 : err = memcpy_s(&stackInfo->frame[layer].info, CORE_BUFFER_LEN, info, strlen(info));
214 175 : if (err != EOK) {
215 0 : LOGE("memcpy stack frame failed, ret=%d", err);
216 0 : stackInfo->layer = layer - 1;
217 0 : return TRACE_FAILURE;
218 : }
219 : }
220 :
221 135 : stackInfo->layer = layer;
222 135 : return TRACE_SUCCESS;
223 : }
224 :
225 : /**
226 : * @brief write "process" info
227 : * @param [in] fd: handle of stack_core file
228 : * @param [in] arg: argument
229 : * @return TraStatus
230 : */
231 155 : STATIC TraStatus TraceWriteProcessInfo(int32_t fd, const ThreadArgument *arg)
232 : {
233 155 : uintptr_t sp = 0;
234 155 : const mcontext_t *mcontext = &(arg->ucontext.uc_mcontext);
235 155 : if (mcontext != NULL) {
236 155 : sp = GET_SPREG_FROM_CONTEXT(mcontext);
237 : }
238 :
239 155 : TraceStackProcessInfo info = { arg->signo, arg->pid, arg->tid, arg->crashTime, arg->stackBaseAddr, sp };
240 155 : return TraceSafeWriteProcessInfo(fd, &info);
241 : }
242 :
243 : /**
244 : * @brief process the exception signal, write info to stack_core file
245 : * @param [in] arg: argument
246 : * @return TraStatus
247 : */
248 195 : TraStatus TraceStackSigHandler(const ThreadArgument *arg)
249 : {
250 195 : if (arg == NULL) {
251 0 : return TRACE_FAILURE;
252 : }
253 :
254 195 : LOGI("get signal number:%d, start to analysis stack info.", arg->signo);
255 195 : TraceStackInfo *stackInfo = TraceSafeGetStackBuffer();
256 195 : stackInfo->threadIdx = 0;
257 195 : stackInfo->threadTid = arg->tid;
258 195 : const ucontext_t *utext = &arg->ucontext;
259 195 : const mcontext_t *mcontext = (const mcontext_t *)&(utext->uc_mcontext);
260 195 : uintptr_t regs[TRACE_CORE_REG_NUM] = { 0 };
261 195 : GET_REGISTER_FROM_CONTEXT(regs, mcontext);
262 195 : TraStatus ret = TraceStackFp(arg, regs, TRACE_CORE_REG_NUM, stackInfo);
263 195 : if (ret != TRACE_SUCCESS) {
264 60 : LOGW("can not derivation stack by fp, ret=%d.", ret);
265 : }
266 :
267 195 : int32_t fd = -1;
268 195 : TraceStackRecorderInfo info = {arg->crashTime, arg->signo, arg->pid, arg->tid};
269 195 : ret = TraceSafeGetFd(&info, TRACE_FILE_TXT_SUFFIX, &fd);
270 195 : if (ret != TRACE_SUCCESS) {
271 40 : LOGE("get fd failed.");
272 40 : return TRACE_FAILURE;
273 : }
274 :
275 155 : ret = TraceWriteProcessInfo(fd, arg);
276 155 : if (ret != TRACE_SUCCESS) {
277 0 : LOGE("write process info to file failed, ret=%d.", ret);
278 : }
279 :
280 155 : ret = TraceSafeWriteStackInfo(fd, stackInfo);
281 155 : if (ret != TRACE_SUCCESS) {
282 40 : LOGE("write stack info to file failed, ret=%d.", ret);
283 : }
284 :
285 155 : ret = TraceSafeWriteSystemInfo(fd, arg->pid);
286 155 : if (ret != TRACE_SUCCESS) {
287 0 : LOGE("write process info to file failed, ret=%d.", ret);
288 : }
289 :
290 155 : TraceClose(&fd);
291 155 : LOGI("write stackcore file end.");
292 155 : return TRACE_SUCCESS;
293 : }
|