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 276 : STATIC TraStatus TraceGetSelfMap(uintptr_t pc, char* data, uint32_t len)
37 : {
38 276 : if (data == NULL || len == 0) {
39 0 : return TRACE_FAILURE;
40 : }
41 :
42 276 : int32_t fd = open(SELF_MAP_PATH, O_RDONLY);
43 276 : if (fd < 0) {
44 0 : LOGW("self map fopen null");
45 0 : return TRACE_FAILURE;
46 : }
47 :
48 276 : char* vmPath = NULL;
49 276 : uintptr_t vmStart = 0;
50 276 : uintptr_t vmEnd = 0;
51 276 : char currentPath[CORE_BUFFER_LEN] = {0};
52 276 : uintptr_t baseAddr = 0; // the minimum addr of load segment
53 12574 : while (TraceSafeReadLine(fd, data, len) > 0) {
54 12517 : vmPath = strchr(data, OS_SPLIT);
55 12517 : if (vmPath == NULL) {
56 3446 : continue;
57 : }
58 9071 : if (sscanf_s(data, "%lx-%lx", &vmStart, &vmEnd) <= 0) {
59 0 : continue;
60 : }
61 :
62 9071 : if (strcmp(currentPath, vmPath) != 0) {
63 1177 : errno_t err = strncpy_s(currentPath, CORE_BUFFER_LEN, vmPath, CORE_BUFFER_LEN - 1U);
64 1177 : if (err != 0) {
65 0 : LOGE("copy vmPath to currentPath failed.");
66 0 : break;
67 : }
68 1177 : baseAddr = vmStart; // update baseAddr when path change
69 : }
70 : // pcAddr is in code-segment(r-xp)
71 9071 : if ((pc < vmStart) || (pc > vmEnd) || (strstr(data, EXEC_MAP_ATTR) == NULL)) {
72 8852 : continue;
73 : }
74 :
75 219 : int32_t ret = snprintf_s(data, len, (size_t)len - 1U, "0x%016lx %s", baseAddr, currentPath);
76 219 : if (ret == -1) {
77 0 : LOGE("snprintf_s map info failed");
78 0 : break;
79 : }
80 219 : TraceClose(&fd);
81 219 : return TRACE_SUCCESS;
82 : }
83 57 : TraceClose(&fd);
84 57 : 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 364 : STATIC uintptr_t TraceStackFrame(int32_t layer, uintptr_t fp, char* data, size_t len)
96 : {
97 364 : uintptr_t nfp = 0;
98 364 : uintptr_t pc = 0;
99 364 : char info[CORE_BUFFER_LEN] = {0};
100 364 : if (fp == 0 || layer >= MAX_STACK_LAYER || data == NULL || len == 0) {
101 88 : return 0;
102 : }
103 :
104 276 : if (layer == 0) { // current pc frame
105 83 : pc = fp;
106 83 : nfp = pc;
107 : } else { // fp inference pc frame
108 193 : uintptr_t lr = fp + LR_OFFSET;
109 193 : if (lr < fp) {
110 0 : return 0;
111 : }
112 193 : pc = *(uintptr_t*)lr;
113 193 : nfp = *(uintptr_t*)fp;
114 : }
115 : int32_t ret;
116 276 : if (TraceGetSelfMap(pc, info, (uint32_t)sizeof(info)) != TRACE_SUCCESS) {
117 57 : ret = snprintf_s(data, len, len - 1U, "invalid pc address 0x%016lx, can not reason stack.\n", pc);
118 57 : if (ret == -1) {
119 0 : LOGE("snprintf_s core info failed");
120 : }
121 57 : return 0;
122 : }
123 219 : ret = snprintf_s(data, len, len - 1U, "#%02d 0x%016lx %s", layer, pc, info);
124 219 : if (ret == -1) {
125 0 : LOGE("snprintf_s core info failed");
126 0 : return 0;
127 : }
128 219 : 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 171 : STATIC void TraceStackPcFrame(int32_t layer, uintptr_t pc, char* data, size_t len)
139 : {
140 171 : if (layer >= MAX_STACK_LAYER || data == NULL || len == 0) {
141 0 : return;
142 : }
143 :
144 171 : if (pc == 0) { // current pc frame
145 : int32_t ret =
146 88 : snprintf_s(data, len, len - 1U, "#%d 0x%016lx 0x%016lx %s\n", layer, pc, pc, program_invocation_name);
147 88 : if (ret == -1) {
148 0 : LOGE("snprintf_s core info failed");
149 : }
150 : }
151 171 : (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 193 : STATIC bool TraceCheckRegister(uintptr_t rbp, uintptr_t rsp, uintptr_t stackBaseAddr)
161 : {
162 193 : if ((rbp >= rsp) && (rbp < stackBaseAddr)) {
163 171 : return true;
164 : }
165 :
166 22 : 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 281 : TraStatus TraceStackFp(const ThreadArgument* arg, uintptr_t* regs, uint32_t regNum, TraceStackInfo* stackInfo)
178 : {
179 281 : if (regs == NULL || arg == NULL || stackInfo == NULL || regNum < MAX_USE_REG_NUM) {
180 66 : return TRACE_INVALID_PARAM;
181 : }
182 :
183 215 : uintptr_t fp = GET_FPREG(regs);
184 215 : uintptr_t sp = GET_SPREG(regs);
185 215 : uintptr_t pc = GET_PCREG(regs);
186 :
187 215 : int32_t layer = 0;
188 215 : stackInfo->layer = -1;
189 215 : char info[CORE_BUFFER_LEN] = {0};
190 215 : if (!TraceCheckRegister(fp, sp, arg->stackBaseAddr)) {
191 44 : int32_t ret = snprintf_s(
192 : info, CORE_BUFFER_LEN, CORE_BUFFER_LEN - 1U,
193 44 : "invalid register value, stack_start_addr=0x%016lx rbp=0x%016lx rsp=0x%016lx \n\n", arg->stackBaseAddr, fp,
194 : sp);
195 44 : if (ret != -1) {
196 44 : (void)memcpy_s(&stackInfo->errLog, CORE_BUFFER_LEN, info, strlen(info));
197 : }
198 44 : return TRACE_FAILURE;
199 : }
200 :
201 : // save pc frame info
202 171 : TraceStackPcFrame(layer, pc, info, sizeof(info));
203 171 : errno_t err = memcpy_s(&stackInfo->frame[0].info, CORE_BUFFER_LEN, info, strlen(info));
204 171 : if (err != EOK) {
205 22 : LOGE("memcpy pc frame failed, ret=%d", err);
206 22 : return TRACE_FAILURE;
207 : }
208 149 : stackInfo->layer = 0;
209 :
210 : // save stack frame info
211 149 : uintptr_t nfp = fp;
212 342 : while ((fp != 0) && (fp >= nfp) && (layer < MAX_STACK_LAYER - 1)) {
213 193 : layer++;
214 193 : fp = TraceStackFrame(layer, fp, info, sizeof(info));
215 193 : err = memcpy_s(&stackInfo->frame[layer].info, CORE_BUFFER_LEN, info, strlen(info));
216 193 : if (err != EOK) {
217 0 : LOGE("memcpy stack frame failed, ret=%d", err);
218 0 : stackInfo->layer = layer - 1;
219 0 : return TRACE_FAILURE;
220 : }
221 : }
222 :
223 149 : stackInfo->layer = layer;
224 149 : return TRACE_SUCCESS;
225 : }
226 :
227 : /**
228 : * @brief write "process" info
229 : * @param [in] fd: handle of stack_core file
230 : * @param [in] arg: argument
231 : * @return TraStatus
232 : */
233 171 : STATIC TraStatus TraceWriteProcessInfo(int32_t fd, const ThreadArgument* arg)
234 : {
235 171 : uintptr_t sp = 0;
236 171 : const mcontext_t* mcontext = &(arg->ucontext.uc_mcontext);
237 171 : if (mcontext != NULL) {
238 171 : sp = GET_SPREG_FROM_CONTEXT(mcontext);
239 : }
240 :
241 171 : TraceStackProcessInfo info = {arg->signo, arg->pid, arg->tid, arg->crashTime, arg->stackBaseAddr, sp};
242 171 : return TraceSafeWriteProcessInfo(fd, &info);
243 : }
244 :
245 : /**
246 : * @brief process the exception signal, write info to stack_core file
247 : * @param [in] arg: argument
248 : * @return TraStatus
249 : */
250 215 : TraStatus TraceStackSigHandler(const ThreadArgument* arg)
251 : {
252 215 : if (arg == NULL) {
253 0 : return TRACE_FAILURE;
254 : }
255 :
256 215 : LOGI("get signal number:%d, start to analysis stack info.", arg->signo);
257 215 : TraceStackInfo* stackInfo = TraceSafeGetStackBuffer();
258 215 : stackInfo->threadIdx = 0;
259 215 : stackInfo->threadTid = arg->tid;
260 215 : const ucontext_t* utext = &arg->ucontext;
261 215 : const mcontext_t* mcontext = (const mcontext_t*)&(utext->uc_mcontext);
262 215 : uintptr_t regs[TRACE_CORE_REG_NUM] = {0};
263 215 : GET_REGISTER_FROM_CONTEXT(regs, mcontext);
264 215 : TraStatus ret = TraceStackFp(arg, regs, TRACE_CORE_REG_NUM, stackInfo);
265 215 : if (ret != TRACE_SUCCESS) {
266 66 : LOGW("can not derivation stack by fp, ret=%d.", ret);
267 : }
268 :
269 215 : int32_t fd = -1;
270 215 : TraceStackRecorderInfo info = {arg->crashTime, arg->signo, arg->pid, arg->tid};
271 215 : ret = TraceSafeGetFd(&info, TRACE_FILE_TXT_SUFFIX, &fd);
272 215 : if (ret != TRACE_SUCCESS) {
273 44 : LOGE("get fd failed.");
274 44 : return TRACE_FAILURE;
275 : }
276 :
277 171 : ret = TraceWriteProcessInfo(fd, arg);
278 171 : if (ret != TRACE_SUCCESS) {
279 0 : LOGE("write process info to file failed, ret=%d.", ret);
280 : }
281 :
282 171 : ret = TraceSafeWriteStackInfo(fd, stackInfo);
283 171 : if (ret != TRACE_SUCCESS) {
284 44 : LOGE("write stack info to file failed, ret=%d.", ret);
285 : }
286 :
287 171 : ret = TraceSafeWriteSystemInfo(fd, arg->pid);
288 171 : if (ret != TRACE_SUCCESS) {
289 0 : LOGE("write process info to file failed, ret=%d.", ret);
290 : }
291 :
292 171 : TraceClose(&fd);
293 171 : LOGI("write stackcore file end.");
294 171 : return TRACE_SUCCESS;
295 : }
|