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 10306 : TraStatus ScdUtilTrim(char* start, uint32_t len, const char** pos)
27 : {
28 10306 : if ((start == NULL) || (len == 0)) {
29 17 : return TRACE_FAILURE;
30 : }
31 :
32 10289 : char* end = start + strlen(start);
33 10289 : if (start == end) {
34 17 : *pos = start;
35 17 : return TRACE_SUCCESS;
36 : }
37 :
38 159352 : while ((start < end) && (isspace((int)(*start)) != 0)) {
39 149080 : start++;
40 : }
41 10272 : if (start == end) {
42 2609 : *pos = start;
43 2609 : return TRACE_SUCCESS;
44 : }
45 :
46 15190 : while ((start < end) && (isspace((int)(*(end - 1))) != 0)) {
47 7527 : end--;
48 : }
49 :
50 7663 : *end = '\0';
51 7663 : *pos = start;
52 7663 : return TRACE_SUCCESS;
53 : }
54 :
55 51 : TraStatus ScdUtilReadStdin(void* buf, size_t len)
56 : {
57 51 : SCD_CHK_PTR_ACTION(buf, return TRACE_FAILURE);
58 34 : size_t readLen = 0;
59 :
60 51 : while (len > readLen) {
61 34 : ssize_t readSize = SCD_UTIL_RETRY(read(STDIN_FILENO, (void*)((uint8_t*)buf + readLen), len - readLen));
62 34 : if (readSize <= 0) {
63 17 : SCD_DLOG_ERR("read from stdin failed, ret=%ld, errno=%d.", readSize, errno);
64 17 : return TRACE_FAILURE;
65 : }
66 17 : readLen += (size_t)readSize;
67 : }
68 17 : return TRACE_SUCCESS;
69 : }
70 :
71 79753 : ssize_t ScdUtilReadLine(int32_t fd, char* buf, size_t len)
72 : {
73 79753 : if (fd < 0 || buf == NULL || len == 0) {
74 17 : return -1;
75 : }
76 :
77 79736 : ssize_t n = 1;
78 79736 : char c = (char)EOF;
79 79736 : char* ptr = buf;
80 6001810 : while (n < (ssize_t)len) {
81 6001538 : ssize_t rc = read(fd, &c, 1);
82 6001538 : if (rc == 1) {
83 6000144 : *ptr = c;
84 6000144 : ptr++;
85 6000144 : if (c == '\n') {
86 78087 : break;
87 : }
88 1394 : } else if (rc == 0) {
89 1360 : *ptr = '\0';
90 1360 : return (n - 1);
91 : } else {
92 34 : if (errno == EINTR) {
93 17 : continue;
94 : }
95 17 : return -1;
96 : }
97 5922057 : n++;
98 : }
99 78359 : *ptr = '\0';
100 78359 : return n;
101 : }
102 :
103 286 : STATIC TraStatus ScdUtilGetTaskName(const char* path, char* buf, size_t len)
104 : {
105 286 : int32_t fd = open(path, O_RDONLY | O_CLOEXEC);
106 286 : if (fd < 0) {
107 42 : SCD_DLOG_WAR("can not open file[%s], errno=%d.", path, errno);
108 42 : return TRACE_FAILURE;
109 : }
110 : // read a line
111 244 : char tmp[SCD_UTIL_TMP_BUF_LEN] = {0};
112 244 : ssize_t ret = ScdUtilReadLine(fd, tmp, SCD_UTIL_TMP_BUF_LEN);
113 244 : (void)close(fd);
114 244 : if (ret <= 0) {
115 34 : SCD_DLOG_WAR("can not read line from file[%s], errno=%d.", path, errno);
116 34 : return TRACE_FAILURE;
117 : }
118 :
119 : // trim
120 210 : const char* data = NULL;
121 210 : if ((ScdUtilTrim(tmp, SCD_UTIL_TMP_BUF_LEN, &data) != TRACE_SUCCESS) || (strlen(data) == 0)) {
122 17 : SCD_DLOG_WAR("file line is empty.");
123 17 : return TRACE_FAILURE;
124 : }
125 193 : size_t dataLen = strlen(data);
126 193 : size_t copyLen = SCD_MIN(len - 1U, dataLen);
127 193 : errno_t err = strncpy_s(buf, len, data, copyLen);
128 193 : if (err != EOK) {
129 17 : SCD_DLOG_WAR("can not strncpy_s, ret=%d, errno=%d", (int32_t)err, errno);
130 17 : return TRACE_FAILURE;
131 : }
132 :
133 176 : buf[copyLen] = '\0';
134 176 : return TRACE_SUCCESS;
135 : }
136 :
137 178 : STATIC void ScdUtilSetUnknown(char* buf, size_t len)
138 : {
139 178 : errno_t ret = strncpy_s(buf, len, "unknown", strlen("unknown"));
140 178 : if (ret != 0) {
141 34 : SCD_DLOG_ERR("strncpy_s failed. (ret=%d)\n", (int32_t)ret);
142 : }
143 178 : }
144 :
145 289 : void ScdUtilGetProcessName(int32_t pid, char* buf, size_t len)
146 : {
147 289 : char path[SCD_UTIL_TMP_BUF_LEN] = {0};
148 :
149 289 : int32_t ret = snprintf_s(path, SCD_UTIL_TMP_BUF_LEN, SCD_UTIL_TMP_BUF_LEN - 1U, "/proc/%d/cmdline", pid);
150 289 : if (ret == -1) {
151 51 : SCD_DLOG_WAR("can not snprintf_s, set process name to unknown.");
152 51 : ScdUtilSetUnknown(buf, len);
153 51 : return;
154 : }
155 :
156 238 : if (ScdUtilGetTaskName(path, buf, len) != TRACE_SUCCESS) {
157 85 : SCD_DLOG_WAR("can not get process name by file[%s], set process name to unknown.", path);
158 85 : ScdUtilSetUnknown(buf, len);
159 : }
160 : }
161 :
162 65 : void ScdUtilGetThreadName(int32_t pid, int32_t tid, char* buf, size_t len)
163 : {
164 65 : char path[SCD_UTIL_TMP_BUF_LEN] = {0};
165 65 : int32_t ret = snprintf_s(path, sizeof(path), sizeof(path) - 1U, "/proc/%d/task/%d/comm", pid, tid);
166 65 : if (ret == -1) {
167 17 : SCD_DLOG_WAR("can not snprintf_s, set thread name to unknown.");
168 17 : ScdUtilSetUnknown(buf, len);
169 17 : return;
170 : }
171 :
172 48 : if (ScdUtilGetTaskName(path, buf, len) != TRACE_SUCCESS) {
173 25 : SCD_DLOG_WAR("can not get thread name by file[%s], set thread name to unknown.", path);
174 25 : ScdUtilSetUnknown(buf, len);
175 : }
176 : }
177 :
178 32 : STATIC TraStatus ScdUtilPtraceReadLong(int32_t pid, uintptr_t addr, long* value)
179 : {
180 32 : errno = 0;
181 32 : long ret = ptrace(PTRACE_PEEKTEXT, pid, addr, NULL);
182 32 : if (ret == -1 && errno != 0) {
183 10 : SCD_DLOG_ERR("ptrace peektext failed, ret %ld, error : %s", ret, strerror(errno));
184 10 : return TRACE_FAILURE;
185 : }
186 22 : *value = ret;
187 22 : return TRACE_SUCCESS;
188 : }
189 :
190 23 : size_t ScdUtilsPtraceRead(int32_t pid, uintptr_t src, void* dst, size_t dstLen)
191 : {
192 23 : size_t readSize = dstLen;
193 23 : void* dstPos = dst;
194 23 : uintptr_t srcAddr = src;
195 23 : long data = 0;
196 23 : size_t alignBytes = srcAddr & (sizeof(long) - 1U);
197 23 : if (alignBytes != 0) {
198 17 : TraStatus ret = ScdUtilPtraceReadLong(pid, srcAddr & ~(sizeof(long) - 1U), &data);
199 17 : if (ret != TRACE_SUCCESS) {
200 10 : 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 1900 : int32_t ScdUtilOpen(const char* path)
242 : {
243 1900 : char realPath[TRACE_MAX_PATH] = {0};
244 1900 : if ((TraceRealPath(path, realPath, TRACE_MAX_PATH) != EN_OK) && (AdiagGetErrorCode() != ENOENT)) {
245 34 : SCD_DLOG_ERR("can not get realpath, path=%s, strerr=%s.", path, strerror(AdiagGetErrorCode()));
246 34 : return -1;
247 : }
248 :
249 1866 : int32_t fd = open(path, O_RDONLY | O_CLOEXEC);
250 1866 : if (fd < 0) {
251 105 : SCD_DLOG_ERR("open %s failed, stderr=%s.", path, strerror(AdiagGetErrorCode()));
252 105 : return -1;
253 : }
254 1761 : return fd;
255 : }
256 :
257 37283 : size_t ScdUtilWrite(int32_t fd, const void* data, size_t len)
258 : {
259 37283 : if ((fd < 0) || (data == NULL) || (len == 0)) {
260 408 : SCD_DLOG_ERR("invalid input, fd=%d, data=%p, len=%zu.", fd, data, len);
261 408 : return 0;
262 : }
263 :
264 36875 : size_t reserved = len;
265 : do {
266 36875 : ssize_t wrLen = write(fd, (const void*)((uintptr_t)data + (len - reserved)), reserved);
267 36875 : if ((wrLen < 0) || (errno == EINTR)) {
268 17 : SCD_DLOG_ERR("write failed, ret=%ld, errno=%d.", wrLen, errno);
269 17 : return len - reserved;
270 : }
271 36858 : reserved -= (size_t)wrLen;
272 36858 : } while (reserved != 0);
273 36858 : return len;
274 : }
275 :
276 1061 : void ScdUtilWriteTitle(int32_t fd, const char* title)
277 : {
278 1061 : (void)ScdUtilWrite(fd, title, strlen(title));
279 1061 : ScdUtilWriteNewLine(fd);
280 1061 : }
281 :
282 2245 : void ScdUtilWriteNewLine(int32_t fd) { (void)ScdUtilWrite(fd, "\n", 1); }
283 :
284 1683 : int32_t ScdUtilGetProcFd(int32_t pid, const char* fileName)
285 : {
286 1683 : char path[SCD_UTIL_TMP_BUF_LEN] = {0};
287 : int32_t err;
288 1683 : if (pid == -1) {
289 425 : err = snprintf_s(path, SCD_UTIL_TMP_BUF_LEN, SCD_UTIL_TMP_BUF_LEN - 1U, "/proc/%s", fileName);
290 : } else {
291 1258 : err = snprintf_s(path, SCD_UTIL_TMP_BUF_LEN, SCD_UTIL_TMP_BUF_LEN - 1U, "/proc/%d/%s", pid, fileName);
292 : }
293 1683 : if (err == -1) {
294 34 : SCD_DLOG_ERR("snprintf_s proc file name failed, pid=%d, file name[%s].", pid, fileName);
295 34 : return -1;
296 : }
297 :
298 1649 : return ScdUtilOpen(path);
299 : }
300 :
301 255 : TraStatus ScdUtilWriteProcInfo(int32_t fd, int32_t pid, const char* fileName)
302 : {
303 255 : int32_t procFd = ScdUtilGetProcFd(pid, fileName);
304 255 : if (procFd < 0) {
305 34 : return TRACE_FAILURE;
306 : }
307 :
308 221 : char info[SCD_UTIL_TMP_BUF_LEN] = {0};
309 13022 : while (ScdUtilReadLine(procFd, info, SCD_UTIL_TMP_BUF_LEN) > 0) {
310 12818 : size_t ret = ScdUtilWrite(fd, info, strlen(info));
311 12818 : if (ret != strlen(info)) {
312 17 : SCD_DLOG_ERR("write proc info to file failed, ret=%d, errno=%d", ret, errno);
313 17 : (void)close(procFd);
314 17 : return TRACE_FAILURE;
315 : }
316 : }
317 :
318 204 : SCD_DLOG_INF("write proc file[%s] info to file successfully.", fileName);
319 204 : (void)close(procFd);
320 204 : return TRACE_SUCCESS;
321 : }
|