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_layout.h"
12 : #include "scd_threads.h"
13 : #include "scd_thread.h"
14 : #include "scd_frame.h"
15 : #include "adiag_utils.h"
16 : #include "trace_system_api.h"
17 : #include "scd_log.h"
18 :
19 870 : STATIC ScdSection *ScdLayoutGetEmptShdr(ScdProcess *pro)
20 : {
21 870 : uint32_t offset = (uint32_t)sizeof(ScdProcess);
22 2685 : for (uint32_t i = 0; i < SCD_MAX_SHDR_NUM; i++) {
23 2685 : if (pro->shdr[i].use) {
24 1815 : offset = pro->shdr[i].offset + pro->shdr[i].totalSize;
25 1815 : continue;
26 : }
27 870 : (void)memset_s(&(pro->shdr[i]), sizeof(ScdSection), 0, sizeof(ScdSection));
28 870 : pro->shdr[i].use = true;
29 870 : pro->shdr[i].offset = offset;
30 870 : return &(pro->shdr[i]);
31 : }
32 0 : return NULL;
33 : }
34 :
35 315 : STATIC TraStatus ScdLayoutSetShdrFrames(ScdProcess *pro)
36 : {
37 315 : ScdSection *tmp = ScdLayoutGetEmptShdr(pro);
38 315 : if (tmp == NULL) {
39 15 : SCD_DLOG_ERR("get empty section for frames failed.");
40 15 : return TRACE_FAILURE;
41 : }
42 300 : errno_t err = memcpy_s(tmp->name, SCD_SECTION_NAME_LEN, SCD_SECTION_STACK, strlen(SCD_SECTION_STACK));
43 300 : if (err != EOK) {
44 15 : SCD_DLOG_ERR("memcpy failed, err=%d, errno=%d.", (int32_t)err, errno);
45 15 : return TRACE_FAILURE;
46 : }
47 :
48 285 : tmp->org = (uintptr_t)&pro->thds.thdList;
49 285 : tmp->type = SCD_SHDR_TYPE_LIST;
50 285 : tmp->entSize = (uint32_t)sizeof(ScdFrame);
51 : // 遍历thds,遍历frames的frame,将frame放进section
52 285 : ScdThreads *thds = &pro->thds;
53 285 : uint32_t frameNum = 0;
54 285 : struct ListHead *pos = NULL;
55 285 : struct AdiagListNode *node = NULL;
56 300 : LIST_FOR_EACH(pos, &thds->thdList.list) {
57 15 : node = LIST_ENTRY(pos, struct AdiagListNode, list);
58 15 : ScdThread *threadInfo = (ScdThread *)node->data;
59 15 : frameNum += threadInfo->frames.frameList.cnt;
60 : }
61 285 : tmp->num = frameNum;
62 285 : tmp->totalSize = tmp->num * tmp->entSize;
63 285 : return TRACE_SUCCESS;
64 : }
65 :
66 660 : STATIC uint32_t ScdLayoutGetFileSize(int32_t pid, const char *fileName)
67 : {
68 660 : int32_t fd = ScdUtilGetProcFd(pid, fileName);
69 660 : if (fd < 0) {
70 60 : return 0;
71 : }
72 :
73 600 : ssize_t fileSize = 0;
74 600 : char data[SCD_UTIL_TMP_BUF_LEN] = { 0 };
75 600 : ssize_t ret = ScdUtilReadLine(fd, data, SCD_UTIL_TMP_BUF_LEN);
76 44235 : while(ret > 0) {
77 43635 : fileSize += ret;
78 43635 : ret = ScdUtilReadLine(fd, data, SCD_UTIL_TMP_BUF_LEN);
79 : }
80 600 : (void)close(fd);
81 600 : return (uint32_t)fileSize;
82 : }
83 :
84 660 : STATIC TraStatus ScdLayoutSetFdType(ScdSection *shdr, int32_t pid, const char *fileName)
85 : {
86 660 : uint32_t fileSize = ScdLayoutGetFileSize(pid, fileName);
87 660 : if (fileSize == 0) {
88 60 : return TRACE_FAILURE;
89 : }
90 :
91 600 : int32_t procFd = ScdUtilGetProcFd(pid, fileName);
92 600 : if (procFd < 0) {
93 0 : return TRACE_FAILURE;
94 : }
95 600 : SCD_DLOG_INF("set proc file[%s] fileSize=%u, fd=%d.", fileName, fileSize, procFd);
96 :
97 600 : shdr->entSize = fileSize;
98 600 : shdr->org = (uintptr_t)procFd;
99 600 : shdr->type = SCD_SHDR_TYPE_FD;
100 600 : shdr->num = 1U;
101 600 : shdr->totalSize = shdr->num * shdr->entSize;
102 600 : return TRACE_SUCCESS;
103 : }
104 :
105 285 : STATIC TraStatus ScdLayoutSetShdrProcMaps(ScdProcess *pro)
106 : {
107 285 : ScdSection *tmp = ScdLayoutGetEmptShdr(pro);
108 285 : if (tmp == NULL) {
109 15 : SCD_DLOG_ERR("get empty section for maps failed.");
110 15 : return TRACE_FAILURE;
111 : }
112 270 : errno_t err = memcpy_s(tmp->name, SCD_SECTION_NAME_LEN, SCD_SECTION_MAPS, strlen(SCD_SECTION_MAPS));
113 270 : if (err != EOK) {
114 15 : SCD_DLOG_ERR("memcpy failed, err=%d, errno=%d.", (int32_t)err, errno);
115 15 : return TRACE_FAILURE;
116 : }
117 :
118 255 : return ScdLayoutSetFdType(tmp, pro->args.pid, "maps");
119 : }
120 :
121 195 : STATIC TraStatus ScdLayoutSetShdrProcMeminfo(ScdProcess *pro)
122 : {
123 195 : ScdSection *tmp = ScdLayoutGetEmptShdr(pro);
124 195 : if (tmp == NULL) {
125 15 : SCD_DLOG_ERR("get empty section for meminfo failed.");
126 15 : return TRACE_FAILURE;
127 : }
128 180 : errno_t err = memcpy_s(tmp->name, SCD_SECTION_NAME_LEN, SCD_SECTION_MEMORY, strlen(SCD_SECTION_MEMORY));
129 180 : if (err != EOK) {
130 15 : SCD_DLOG_ERR("memcpy failed, err=%d, errno=%d.", (int32_t)err, errno);
131 15 : return TRACE_FAILURE;
132 : }
133 165 : return ScdLayoutSetFdType(tmp, -1, "meminfo");
134 : }
135 :
136 165 : STATIC TraStatus ScdLayoutSetShdrProcStatus(ScdProcess *pro)
137 : {
138 165 : ScdSection *tmp = ScdLayoutGetEmptShdr(pro);
139 165 : if (tmp == NULL) {
140 15 : SCD_DLOG_ERR("get empty section for status failed.");
141 15 : return TRACE_FAILURE;
142 : }
143 150 : errno_t err = memcpy_s(tmp->name, SCD_SECTION_NAME_LEN, SCD_SECTION_STATUS, strlen(SCD_SECTION_STATUS));
144 150 : if (err != EOK) {
145 15 : SCD_DLOG_ERR("memcpy failed, err=%d, errno=%d.", (int32_t)err, errno);
146 15 : return TRACE_FAILURE;
147 : }
148 135 : return ScdLayoutSetFdType(tmp, pro->args.pid, "status");
149 : }
150 :
151 135 : STATIC TraStatus ScdLayoutSetShdrProcLimits(ScdProcess *pro)
152 : {
153 135 : ScdSection *tmp = ScdLayoutGetEmptShdr(pro);
154 135 : if (tmp == NULL) {
155 15 : SCD_DLOG_ERR("get empty section for limits failed.");
156 15 : return TRACE_FAILURE;
157 : }
158 120 : errno_t err = memcpy_s(tmp->name, SCD_SECTION_NAME_LEN, SCD_SECTION_LIMITS, strlen(SCD_SECTION_LIMITS));
159 120 : if (err != EOK) {
160 15 : SCD_DLOG_ERR("memcpy failed, err=%d, errno=%d.", (int32_t)err, errno);
161 15 : return TRACE_FAILURE;
162 : }
163 105 : return ScdLayoutSetFdType(tmp, pro->args.pid, "limits");
164 : }
165 :
166 315 : STATIC TraStatus ScdLayoutSetShdr(ScdProcess *pro)
167 : {
168 : // frame section header
169 315 : TraStatus ret = ScdLayoutSetShdrFrames(pro);
170 315 : if (ret != TRACE_SUCCESS) {
171 30 : SCD_DLOG_ERR("set stack section failed.");
172 30 : return TRACE_FAILURE;
173 : }
174 :
175 285 : ret = ScdLayoutSetShdrProcMaps(pro);
176 285 : if (ret != TRACE_SUCCESS) {
177 90 : SCD_DLOG_ERR("set maps section failed.");
178 90 : return TRACE_FAILURE;
179 : }
180 :
181 195 : ret = ScdLayoutSetShdrProcMeminfo(pro);
182 195 : if (ret != TRACE_SUCCESS) {
183 30 : SCD_DLOG_ERR("set memory section failed.");
184 30 : return TRACE_FAILURE;
185 : }
186 :
187 165 : ret = ScdLayoutSetShdrProcStatus(pro);
188 165 : if (ret != TRACE_SUCCESS) {
189 30 : SCD_DLOG_ERR("set status section failed.");
190 30 : return TRACE_FAILURE;
191 : }
192 :
193 135 : ret = ScdLayoutSetShdrProcLimits(pro);
194 135 : if (ret != TRACE_SUCCESS) {
195 30 : SCD_DLOG_ERR("set limits section failed.");
196 30 : return TRACE_FAILURE;
197 : }
198 :
199 105 : pro->shdrUsed = true;
200 105 : return TRACE_SUCCESS;
201 : }
202 :
203 270 : STATIC TraStatus ScdLayoutWriteShdrProc(int32_t fd, ScdSection *shdr)
204 : {
205 270 : if (lseek(fd, shdr->offset, SEEK_SET) < 0) {
206 15 : SCD_DLOG_ERR("lseek failed, offset=%d, fd=%d, errno=%d.", shdr->offset, fd, errno);
207 15 : return TRACE_FAILURE;
208 : }
209 255 : if (shdr->org == SCD_SHDR_INVALID_FD) {
210 15 : SCD_DLOG_ERR("get proc file fd failed.");
211 15 : return TRACE_FAILURE;
212 : }
213 240 : int32_t procFd = (int32_t)shdr->org;
214 240 : size_t fileSize = 0;
215 240 : char data[SCD_UTIL_TMP_BUF_LEN] = { 0 };
216 15660 : while (ScdUtilReadLine(procFd, data, SCD_UTIL_TMP_BUF_LEN) > 0) {
217 15420 : size_t ret = ScdUtilWrite(fd, data, strlen(data));
218 15420 : if (ret != strlen(data)) {
219 0 : SCD_DLOG_ERR("write proc info to file failed.");
220 0 : (void)close(procFd);
221 0 : shdr->org = SCD_SHDR_INVALID_FD;
222 0 : return TRACE_FAILURE;
223 : }
224 15420 : fileSize += ret;
225 : }
226 240 : SCD_DLOG_INF("write section %s info, totalSize=%u, size=%ld, fd=%d.", shdr->name, shdr->totalSize, fileSize, procFd);
227 240 : size_t totalSize = (size_t)shdr->totalSize;
228 300 : while(fileSize < totalSize) {
229 60 : (void)ScdUtilWrite(fd, " ", 1);
230 60 : fileSize++;
231 : }
232 :
233 240 : (void)close(procFd);
234 240 : shdr->org = SCD_SHDR_INVALID_FD;
235 240 : return TRACE_SUCCESS;
236 : }
237 :
238 75 : STATIC TraStatus ScdLayoutWriteShdrFrames(int32_t fd, ScdSection *shdr)
239 : {
240 75 : if (lseek(fd, shdr->offset, SEEK_SET) < 0) {
241 15 : SCD_DLOG_ERR("lseek failed, offset=%d, fd=%d, errno=%d.", shdr->offset, fd, errno);
242 15 : return TRACE_FAILURE;
243 : }
244 60 : struct ListHead *pos = NULL;
245 60 : struct AdiagListNode *node = NULL;
246 60 : struct AdiagList *threadList = (struct AdiagList *)shdr->org;
247 75 : LIST_FOR_EACH(pos, &threadList->list) {
248 15 : node = LIST_ENTRY(pos, struct AdiagListNode, list);
249 15 : ScdThread *threadInfo = (ScdThread *)node->data;
250 :
251 : // record frame info
252 15 : struct ListHead *posFrame = NULL;
253 15 : struct AdiagListNode *nodeFrame = NULL;
254 30 : LIST_FOR_EACH(posFrame, &threadInfo->frames.frameList.list) {
255 15 : nodeFrame = LIST_ENTRY(posFrame, struct AdiagListNode, list);
256 15 : ScdFrame *frame = (ScdFrame *)nodeFrame->data;
257 15 : size_t len = ScdUtilWrite(fd, frame, sizeof(ScdFrame));
258 15 : if (len != sizeof(ScdFrame)) {
259 0 : SCD_DLOG_ERR("write frame section to file failed.");
260 0 : return TRACE_FAILURE;
261 : }
262 : }
263 : }
264 60 : return TRACE_SUCCESS;
265 : }
266 :
267 105 : STATIC TraStatus ScdLayoutWriteShdr(int32_t fd, ScdProcess *pro)
268 : {
269 405 : for (uint32_t i = 0; i < SCD_MAX_SHDR_NUM; i++) {
270 405 : if (!pro->shdr[i].use) {
271 60 : break;
272 : }
273 345 : ScdShdrType type = pro->shdr[i].type;
274 345 : if (type == SCD_SHDR_TYPE_FD) {
275 : // read fd , then write
276 270 : if (ScdLayoutWriteShdrProc(fd, &pro->shdr[i]) != TRACE_SUCCESS) {
277 30 : SCD_DLOG_ERR("write frame section failed.");
278 30 : return TRACE_FAILURE;
279 : }
280 75 : } else if (type == SCD_SHDR_TYPE_LIST) {
281 : // 遍历list,获取node,按node大小写入
282 75 : if (ScdLayoutWriteShdrFrames(fd, &pro->shdr[i]) != TRACE_SUCCESS) {
283 15 : SCD_DLOG_ERR("write frame section failed.");
284 15 : return TRACE_FAILURE;
285 : }
286 : } else {
287 : ;
288 : }
289 : }
290 60 : return TRACE_SUCCESS;
291 : }
292 :
293 105 : STATIC TraStatus ScdLayoutWritePhdr(int32_t fd, ScdProcess *pro)
294 : {
295 105 : size_t len = ScdUtilWrite(fd, pro, sizeof(ScdProcess));
296 105 : if (len != sizeof(ScdProcess)) {
297 0 : SCD_DLOG_ERR("write phdr failed.");
298 0 : return TRACE_FAILURE;
299 : }
300 105 : return TRACE_SUCCESS;
301 : }
302 :
303 15 : STATIC TraStatus ScdSectionProcRecord(int32_t fd, const ScdSection *shdr, const ScdProcess *pro)
304 : {
305 15 : uintptr_t pos = (uintptr_t)pro + shdr->offset;
306 15 : size_t len = ScdUtilWrite(fd, (const void *)pos, shdr->totalSize);
307 15 : if (len != shdr->totalSize) {
308 0 : SCD_DLOG_ERR("write proc section \"%s\" failed.", shdr->name);
309 0 : return TRACE_FAILURE;
310 : }
311 15 : return TRACE_SUCCESS;
312 : }
313 :
314 195 : STATIC TraStatus ScdSectionStackRecord(int32_t fd, const ScdSection *shdr, const ScdProcess *pro)
315 : {
316 195 : uint32_t frameNum = shdr->num;
317 195 : int32_t threadIdx = 0;
318 195 : int32_t tid = -1;
319 195 : int32_t err = 0;
320 195 : char tmpBuf[SCD_FRAME_LENGTH] = {0};
321 195 : uintptr_t pos = (uintptr_t)pro + shdr->offset;
322 285 : for (uint32_t i = 0; i < frameNum; i++) {
323 180 : uintptr_t framePos = pos + i * (uintptr_t)shdr->entSize;
324 180 : ScdFrame *frame = (ScdFrame *)framePos;
325 180 : if (frame->tid != tid) {
326 180 : if (threadIdx != 0) {
327 0 : ScdUtilWriteNewLine(fd);
328 : }
329 180 : tid = frame->tid;
330 180 : threadIdx++;
331 180 : err = snprintf_s(tmpBuf, SCD_FRAME_LENGTH, SCD_FRAME_LENGTH - 1U, "Thread %d (%d)\n", threadIdx, tid);
332 180 : if (err == -1) {
333 15 : SCD_DLOG_ERR("snprintf_s thread header failed, tid=%d.", tid);
334 15 : return TRACE_FAILURE;
335 : }
336 165 : if (ScdUtilWrite(fd, tmpBuf, strlen(tmpBuf)) != strlen(tmpBuf)) {
337 45 : SCD_DLOG_ERR("write thread header failed, tid=%d.", tid);
338 45 : return TRACE_FAILURE;
339 : }
340 : }
341 120 : if (strlen(frame->funcName) == 0) {
342 120 : err = snprintf_s(tmpBuf, SCD_FRAME_LENGTH, SCD_FRAME_LENGTH - 1U,
343 120 : "#%02u 0x%016lx 0x%016lx %s\n", frame->num, frame->pc, frame->base, frame->soName);
344 : } else {
345 0 : err = snprintf_s(tmpBuf, SCD_FRAME_LENGTH, SCD_FRAME_LENGTH - 1U,
346 0 : "#%02u 0x%016lx 0x%016lx %s (%s)\n", frame->num, frame->pc, frame->base, frame->soName, frame->funcName);
347 : }
348 120 : if (err == -1) {
349 15 : SCD_DLOG_ERR("snprintf_s frame failed, tid=%d, frame index=%u.", frame->tid, frame->num);
350 15 : return TRACE_FAILURE;
351 : }
352 105 : if (ScdUtilWrite(fd, tmpBuf, strlen(tmpBuf)) != strlen(tmpBuf)) {
353 15 : SCD_DLOG_ERR("write frame failed, tid=%d, frame index=%u.", frame->tid, frame->num);
354 15 : return TRACE_FAILURE;
355 : }
356 : }
357 105 : return TRACE_SUCCESS;
358 : }
359 :
360 240 : STATIC TraStatus ScdSectionRecordByName(int32_t fd, const ScdSection *shdr, const ScdProcess *pro)
361 : {
362 240 : size_t len = ScdUtilWrite(fd, shdr->name, strlen(shdr->name));
363 240 : if (len != strlen(shdr->name)) {
364 30 : SCD_DLOG_ERR("write \"%s\" section failed.", shdr->name);
365 30 : return TRACE_FAILURE;
366 : }
367 210 : ScdUtilWriteNewLine(fd);
368 210 : TraStatus ret = TRACE_SUCCESS;
369 210 : if (strncmp(shdr->name, SCD_SECTION_STACK, SCD_SECTION_NAME_LEN) == 0) {
370 195 : ret = ScdSectionStackRecord(fd, shdr, pro);
371 : } else {
372 15 : ret = ScdSectionProcRecord(fd, shdr, pro);
373 : }
374 210 : ScdUtilWriteNewLine(fd);
375 210 : return ret;
376 : }
377 :
378 315 : TraStatus ScdSectionRecord(int32_t fd, const ScdProcess *pro, const char *name)
379 : {
380 2265 : for (uint32_t i = 0; i < SCD_MAX_SHDR_NUM; i++) {
381 2070 : const ScdSection *shdr = &pro->shdr[i];
382 2070 : if (!shdr->use) {
383 1440 : continue;
384 : }
385 630 : if (strncmp(shdr->name, name, SCD_SECTION_NAME_LEN) != 0) {
386 390 : continue;
387 : }
388 240 : if (ScdSectionRecordByName(fd, shdr, pro) != TRACE_SUCCESS) {
389 120 : SCD_DLOG_ERR("write \"%s\" section failed.", name);
390 120 : return TRACE_FAILURE;
391 : }
392 : }
393 195 : return TRACE_SUCCESS;
394 : }
395 :
396 315 : TraStatus ScdLayoutWrite(int32_t fd, ScdProcess *pro)
397 : {
398 : // calculate core layout
399 315 : TraStatus ret = ScdLayoutSetShdr(pro);
400 315 : if (ret != TRACE_SUCCESS) {
401 210 : SCD_DLOG_ERR("set section layout failed.");
402 210 : return TRACE_FAILURE;
403 : }
404 :
405 : // write process struct to core
406 105 : ret = ScdLayoutWritePhdr(fd, pro);
407 105 : if (ret != TRACE_SUCCESS) {
408 0 : SCD_DLOG_ERR("write process struct failed.");
409 0 : return TRACE_FAILURE;
410 : }
411 :
412 : // write section([maps]、[meminfo]、[status]、[limits]...) to core
413 105 : ret = ScdLayoutWriteShdr(fd, pro);
414 105 : if (ret != TRACE_SUCCESS) {
415 45 : SCD_DLOG_ERR("write section layout failed.");
416 45 : return TRACE_FAILURE;
417 : }
418 60 : return TRACE_SUCCESS;
419 : }
420 :
421 120 : TraStatus ScdLayoutRead(ScdProcess **pro, const char *filePath)
422 : {
423 : // open bin
424 120 : int32_t fd = ScdUtilOpen(filePath);
425 120 : if (fd < 0) {
426 15 : SCD_DLOG_ERR("open bin file failed.");
427 15 : return TRACE_FAILURE;
428 : }
429 :
430 105 : off_t ret = lseek(fd, 0, SEEK_END);
431 105 : if (ret < 0) {
432 15 : SCD_DLOG_ERR("lseek failed, errno=%d.", errno);
433 15 : (void)close(fd);
434 15 : return TRACE_FAILURE;
435 : }
436 90 : size_t fileSize = (size_t)ret;
437 90 : void *buffer = AdiagMalloc(fileSize);
438 90 : if (buffer == NULL) {
439 15 : SCD_DLOG_ERR("malloc failed.");
440 15 : (void)close(fd);
441 15 : return TRACE_FAILURE;
442 : }
443 : // 从fd里读取,然后写入pro中
444 75 : (void)lseek(fd, 0, SEEK_SET);
445 75 : ssize_t readBytes = read(fd, buffer, fileSize);
446 75 : if ((size_t)readBytes != fileSize) {
447 15 : (void)close(fd);
448 15 : ADIAG_SAFE_FREE(buffer);
449 15 : SCD_DLOG_ERR("can not read data from file [%s], errno=%d.", filePath, errno);
450 15 : return TRACE_FAILURE;
451 : }
452 :
453 60 : (void)close(fd);
454 60 : *pro = (ScdProcess *)buffer;
455 60 : return TRACE_SUCCESS;
456 : }
|