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 "scd_util.h"
12 : #include <stdio.h>
13 : #include <fcntl.h>
14 : #include <errno.h>
15 : #include <stdio.h>
16 : #include <ctype.h>
17 : #include <sys/ptrace.h>
18 : #include "securec.h"
19 : #include "adiag_utils.h"
20 : #include "trace_system_api.h"
21 : #include "atrace_types.h"
22 : #include "scd_log.h"
23 :
24 : #define MIN(a, b) ((a) > (b) ? (b) : (a))
25 :
26 8573 : TraStatus ScdUtilTrim(char *start, uint32_t len, const char **pos)
27 : {
28 8573 : if ((start == NULL) || (len == 0)) {
29 14 : return TRACE_FAILURE;
30 : }
31 :
32 8559 : char *end = start + strlen(start);
33 8559 : if (start == end) {
34 14 : *pos = start;
35 14 : return TRACE_SUCCESS;
36 : }
37 :
38 134509 : while ((start < end) && (isspace((int)(*start)) != 0)) {
39 125964 : start++;
40 : }
41 8545 : if (start == end) {
42 2094 : *pos = start;
43 2094 : return TRACE_SUCCESS;
44 : }
45 :
46 12797 : while ((start < end) && (isspace((int)(*(end - 1))) != 0)) {
47 6346 : end--;
48 : }
49 :
50 6451 : *end = '\0';
51 6451 : *pos = start;
52 6451 : return TRACE_SUCCESS;
53 : }
54 :
55 42 : TraStatus ScdUtilReadStdin(void *buf, size_t len)
56 : {
57 42 : SCD_CHK_PTR_ACTION(buf, return TRACE_FAILURE);
58 28 : size_t readLen = 0;
59 :
60 42 : while(len > readLen) {
61 28 : ssize_t readSize = SCD_UTIL_RETRY(read(STDIN_FILENO, (void *)((uint8_t *)buf + readLen), len - readLen));
62 28 : if (readSize <= 0) {
63 14 : SCD_DLOG_ERR("read from stdin failed, ret=%ld, errno=%d.", readSize, errno);
64 14 : return TRACE_FAILURE;
65 : }
66 14 : readLen += (size_t)readSize;
67 : }
68 14 : return TRACE_SUCCESS;
69 : }
70 :
71 67942 : ssize_t ScdUtilReadLine(int32_t fd, char *buf, size_t len)
72 : {
73 67942 : if (fd < 0 || buf == NULL || len == 0) {
74 14 : return -1;
75 : }
76 :
77 67928 : ssize_t n = 1;
78 67928 : char c = (char)EOF;
79 67928 : char *ptr = buf;
80 5164435 : while (n < (ssize_t)len) {
81 5164210 : ssize_t rc = read(fd, &c, 1);
82 5164210 : if (rc == 1) {
83 5163061 : *ptr = c;
84 5163061 : ptr++;
85 5163061 : if (c == '\n') {
86 66568 : break;
87 : }
88 1149 : } else if (rc == 0) {
89 1121 : *ptr = '\0';
90 1121 : return (n - 1);
91 : } else {
92 28 : if (errno == EINTR) {
93 14 : continue;
94 : }
95 14 : return -1;
96 : }
97 5096493 : n++;
98 : }
99 66793 : *ptr = '\0';
100 66793 : return n;
101 : }
102 :
103 218 : STATIC TraStatus ScdUtilGetTaskName(const char *path, char *buf, size_t len)
104 : {
105 218 : int32_t fd = open(path, O_RDONLY | O_CLOEXEC);
106 218 : if (fd < 0) {
107 29 : SCD_DLOG_WAR("can not open file[%s], errno=%d.", path, errno);
108 29 : return TRACE_FAILURE;
109 : }
110 : // read a line
111 189 : char tmp[SCD_UTIL_TMP_BUF_LEN] = {0};
112 189 : ssize_t ret = ScdUtilReadLine(fd, tmp, SCD_UTIL_TMP_BUF_LEN);
113 189 : (void)close(fd);
114 189 : if (ret <= 0) {
115 28 : SCD_DLOG_WAR("can not read line from file[%s], errno=%d.", path, errno);
116 28 : return TRACE_FAILURE;
117 : }
118 :
119 : // trim
120 161 : const char *data = NULL;
121 161 : if ((ScdUtilTrim(tmp, SCD_UTIL_TMP_BUF_LEN, &data) != TRACE_SUCCESS) || (strlen(data) == 0)) {
122 14 : SCD_DLOG_WAR("file line is empty.");
123 14 : return TRACE_FAILURE;
124 : }
125 147 : size_t dataLen = strlen(data);
126 147 : size_t copyLen = SCD_MIN(len - 1U, dataLen);
127 147 : errno_t err = strncpy_s(buf, len, data, copyLen);
128 147 : if (err != EOK) {
129 14 : SCD_DLOG_WAR("can not strncpy_s, ret=%d, errno=%d", (int32_t)err, errno);
130 14 : return TRACE_FAILURE;
131 : }
132 :
133 133 : buf[copyLen] = '\0';
134 133 : return TRACE_SUCCESS;
135 : }
136 :
137 142 : STATIC void ScdUtilSetUnknown(char *buf, size_t len)
138 : {
139 142 : errno_t ret = strncpy_s(buf, len, "unknown", strlen("unknown"));
140 142 : if (ret != 0) {
141 28 : SCD_DLOG_ERR("strncpy_s failed. (ret=%d)\n", (int32_t)ret);
142 : }
143 142 : }
144 :
145 233 : void ScdUtilGetProcessName(int32_t pid, char *buf, size_t len)
146 : {
147 233 : char path[SCD_UTIL_TMP_BUF_LEN] = {0};
148 :
149 233 : int32_t ret = snprintf_s(path, SCD_UTIL_TMP_BUF_LEN, SCD_UTIL_TMP_BUF_LEN - 1U, "/proc/%d/cmdline", pid);
150 233 : if (ret == -1) {
151 43 : SCD_DLOG_WAR("can not snprintf_s, set process name to unknown.");
152 43 : ScdUtilSetUnknown(buf, len);
153 43 : return;
154 : }
155 :
156 190 : if (ScdUtilGetTaskName(path, buf, len) != TRACE_SUCCESS) {
157 71 : SCD_DLOG_WAR("can not get process name by file[%s], set process name to unknown.", path);
158 71 : ScdUtilSetUnknown(buf, len);
159 : }
160 : }
161 :
162 42 : void ScdUtilGetThreadName(int32_t pid, int32_t tid, char *buf, size_t len)
163 : {
164 42 : char path[SCD_UTIL_TMP_BUF_LEN] = {0};
165 42 : int32_t ret = snprintf_s(path, sizeof(path), sizeof(path) - 1U, "/proc/%d/task/%d/comm", pid, tid);
166 42 : if (ret == -1) {
167 14 : SCD_DLOG_WAR("can not snprintf_s, set thread name to unknown.");
168 14 : ScdUtilSetUnknown(buf, len);
169 14 : return;
170 : }
171 :
172 28 : if (ScdUtilGetTaskName(path, buf, len) != TRACE_SUCCESS) {
173 14 : SCD_DLOG_WAR("can not get thread name by file[%s], set thread name to unknown.", path);
174 14 : ScdUtilSetUnknown(buf, len);
175 : }
176 : }
177 :
178 29 : STATIC TraStatus ScdUtilPtraceReadLong(int32_t pid, uintptr_t addr, long *value)
179 : {
180 29 : errno = 0;
181 29 : long ret = ptrace(PTRACE_PEEKTEXT, pid, addr, NULL);
182 29 : if (ret == -1 && errno != 0) {
183 7 : SCD_DLOG_ERR("ptrace peektext failed, ret %ld, error : %s", ret, strerror(errno));
184 7 : return TRACE_FAILURE;
185 : }
186 22 : *value = ret;
187 22 : return TRACE_SUCCESS;
188 : }
189 :
190 20 : size_t ScdUtilsPtraceRead(int32_t pid, uintptr_t src, void *dst, size_t dstLen)
191 : {
192 20 : size_t readSize = dstLen;
193 20 : void *dstPos = dst;
194 20 : uintptr_t srcAddr = src;
195 20 : long data = 0;
196 20 : size_t alignBytes = srcAddr & (sizeof(long) - 1U);
197 20 : if (alignBytes != 0) {
198 14 : TraStatus ret = ScdUtilPtraceReadLong(pid, srcAddr & ~(sizeof(long) - 1U), &data);
199 14 : if (ret != TRACE_SUCCESS) {
200 7 : return 0;
201 : }
202 7 : size_t readLen = MIN(readSize, sizeof(long) - alignBytes);
203 7 : errno_t err = memcpy_s(dstPos, readSize, (const void *)((uintptr_t)(&data) + alignBytes), readLen);
204 7 : if (err != EOK) {
205 2 : SCD_DLOG_ERR("memcpy_s failed, err = %d, errno = %d.", (int32_t)err, errno);
206 2 : return 0;
207 : }
208 5 : srcAddr += readLen;
209 5 : dstPos = (void *)((uintptr_t)dstPos + readLen);
210 5 : readSize -= readLen;
211 : }
212 :
213 18 : for (size_t i = readSize / sizeof(long); i > 0; i--) {
214 8 : TraStatus ret = ScdUtilPtraceReadLong(pid, srcAddr, &data);
215 8 : if (ret != TRACE_SUCCESS) {
216 0 : return 0;
217 : }
218 8 : errno_t err = memcpy_s(dstPos, readSize, &data, sizeof(long));
219 8 : if (err != EOK) {
220 1 : SCD_DLOG_ERR("memcpy_s failed, err = %d, errno = %d.", (int32_t)err, errno);
221 1 : return 0;
222 : }
223 7 : srcAddr += sizeof(long);
224 7 : dstPos = (void *)((uintptr_t)dstPos + sizeof(long));
225 7 : readSize -= sizeof(long);
226 : }
227 10 : if (readSize != 0) {
228 7 : TraStatus ret = ScdUtilPtraceReadLong(pid, srcAddr, &data);
229 7 : if (ret != TRACE_SUCCESS) {
230 0 : return 0;
231 : }
232 7 : errno_t err = memcpy_s(dstPos, readSize, &data, readSize);
233 7 : if (err != EOK) {
234 1 : SCD_DLOG_ERR("memcpy_s failed, err = %d, errno = %d.", (int32_t)err, errno);
235 1 : return 0;
236 : }
237 : }
238 9 : return dstLen;
239 : }
240 :
241 1603 : int32_t ScdUtilOpen(const char *path)
242 : {
243 1603 : char realPath[TRACE_MAX_PATH] = {0};
244 1603 : if ((TraceRealPath(path, realPath, TRACE_MAX_PATH) != EN_OK) && (AdiagGetErrorCode() != ENOENT)) {
245 29 : SCD_DLOG_ERR("can not get realpath, path=%s, strerr=%s.", path, strerror(AdiagGetErrorCode()));
246 29 : return -1;
247 : }
248 :
249 1574 : int32_t fd = open(path, O_RDONLY | O_CLOEXEC);
250 1574 : if (fd < 0) {
251 89 : SCD_DLOG_ERR("open %s failed, stderr=%s.", path, strerror(AdiagGetErrorCode()));
252 89 : return -1;
253 : }
254 1485 : return fd;
255 : }
256 :
257 29325 : size_t ScdUtilWrite(int32_t fd, const void *data, size_t len)
258 : {
259 29325 : if ((fd < 0) || (data == NULL) || (len == 0)) {
260 359 : SCD_DLOG_ERR("invalid input, fd=%d, data=%p, len=%zu.", fd, data, len);
261 359 : return 0;
262 : }
263 :
264 28966 : size_t reserved = len;
265 : do {
266 28966 : ssize_t wrLen = write(fd, (const void *)((uintptr_t)data + (len - reserved)), reserved);
267 28966 : if ((wrLen < 0) || (errno == EINTR)) {
268 14 : SCD_DLOG_ERR("write failed, ret=%ld, errno=%d.", wrLen, errno);
269 14 : return len - reserved;
270 : }
271 28952 : reserved -= (size_t)wrLen;
272 28952 : } while (reserved != 0);
273 28952 : return len;
274 : }
275 :
276 851 : void ScdUtilWriteTitle(int32_t fd, const char *title)
277 : {
278 851 : (void)ScdUtilWrite(fd, title, strlen(title));
279 851 : ScdUtilWriteNewLine(fd);
280 851 : }
281 :
282 1822 : void ScdUtilWriteNewLine(int32_t fd)
283 : {
284 1822 : (void)ScdUtilWrite(fd, "\n", 1);
285 1822 : }
286 :
287 1422 : int32_t ScdUtilGetProcFd(int32_t pid, const char* fileName)
288 : {
289 1422 : char path[SCD_UTIL_TMP_BUF_LEN] = {0};
290 : int32_t err;
291 1422 : if (pid == -1) {
292 360 : err = snprintf_s(path, SCD_UTIL_TMP_BUF_LEN, SCD_UTIL_TMP_BUF_LEN - 1U, "/proc/%s", fileName);
293 : } else {
294 1062 : err = snprintf_s(path, SCD_UTIL_TMP_BUF_LEN, SCD_UTIL_TMP_BUF_LEN - 1U, "/proc/%d/%s", pid, fileName);
295 : }
296 1422 : if (err == -1) {
297 29 : SCD_DLOG_ERR("snprintf_s proc file name failed, pid=%d, file name[%s].", pid, fileName);
298 29 : return -1;
299 : }
300 :
301 1393 : return ScdUtilOpen(path);
302 : }
303 :
304 162 : TraStatus ScdUtilWriteProcInfo(int32_t fd, int32_t pid, const char* fileName)
305 : {
306 162 : int32_t procFd = ScdUtilGetProcFd(pid, fileName);
307 162 : if (procFd < 0) {
308 28 : return TRACE_FAILURE;
309 : }
310 :
311 134 : char info[SCD_UTIL_TMP_BUF_LEN] = { 0 };
312 7844 : while (ScdUtilReadLine(procFd, info, SCD_UTIL_TMP_BUF_LEN) > 0) {
313 7724 : size_t ret = ScdUtilWrite(fd, info, strlen(info));
314 7724 : if (ret != strlen(info)) {
315 14 : SCD_DLOG_ERR("write proc info to file failed, ret=%d, errno=%d", ret, errno);
316 14 : (void)close(procFd);
317 14 : return TRACE_FAILURE;
318 : }
319 : }
320 :
321 120 : SCD_DLOG_INF("write proc file[%s] info to file successfully.", fileName);
322 120 : (void)close(procFd);
323 120 : return TRACE_SUCCESS;
324 : }
|