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