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_frames.h"
12 : #include "scd_regs.h"
13 : #include "scd_maps.h"
14 : #include "scd_log.h"
15 : #include "scd_dl.h"
16 : #include "scd_frame.h"
17 :
18 : #define SCD_MAX_STACK_LAYER 32U
19 :
20 0 : STATIC TraStatus ScdFramesFpStep(ScdFrame *frame, ScdRegs *regs)
21 : {
22 0 : uintptr_t fp = frame->fp;
23 0 : SCD_CHK_EXPR_ACTION(fp == 0, return TRACE_FAILURE, "invalid fp 0, frame pointer is not supported");
24 0 : uintptr_t lr = fp + 8U; // LR_OFFSET
25 : uintptr_t nextPc;
26 : /* ScdMemoryRead(NULL, ...) uses global handler (ScdMemoryRemoteRead via ptrace).
27 : * Safe here: this function is only called from dumper subprocess context
28 : * (ScdProcessDump -> ScdFramesLoad), where ptrace is available. */
29 0 : size_t size = ScdMemoryRead(NULL, lr, &nextPc, sizeof(uintptr_t));
30 0 : SCD_CHK_EXPR_ACTION(size == 0, return TRACE_FAILURE, "scd read memory from 0x%llx, failed ", lr);
31 0 : ScdRegsSetPc(regs, nextPc);
32 0 : SCD_DLOG_INF("update pc to 0x%llx get from 0x%llx",nextPc, lr);
33 :
34 : uintptr_t nextFp;
35 0 : size = ScdMemoryRead(NULL, fp, &nextFp, sizeof(uintptr_t));
36 0 : SCD_CHK_EXPR_ACTION(size == 0, return TRACE_FAILURE, "scd read memory from 0x%llx, failed ", fp);
37 0 : ScdRegsSetFp(regs, nextFp);
38 0 : SCD_DLOG_INF("update fp to 0x%llx get from 0x%llx", nextFp, fp);
39 0 : return TRACE_SUCCESS;
40 : }
41 :
42 0 : STATIC ScdFrame *ScdFramesCreateFrame(ScdFrames *frames, uintptr_t pc, uintptr_t sp, uintptr_t fp)
43 : {
44 0 : ScdMap *map = ScdMapsGetMapByPc(frames->maps, pc);
45 0 : if (map == NULL) {
46 0 : SCD_DLOG_ERR("can not find map, pc = %p, sp = %p.", pc, sp);
47 0 : return NULL;
48 : }
49 0 : SCD_DLOG_INF("find pc 0x%llx in map %s",pc, map->name);
50 :
51 0 : TraStatus ret = ScdDlLoad(&map->dl, frames->pid, map->name);
52 0 : if (ret != TRACE_SUCCESS) {
53 0 : SCD_DLOG_ERR("load map(%s) failed, pc = %p, sp = %p.", map->name, pc, sp);
54 0 : return NULL;
55 : }
56 0 : uintptr_t relPc = ScdMapGetRelPc(map, pc);
57 0 : ScdFrame *frame = ScdFrameCreate(map, pc, sp, fp);
58 0 : if (frame == NULL) {
59 0 : SCD_DLOG_ERR("create frame failed, map = %s, pc = %p, sp = %p.", map->name, pc, sp);
60 0 : return NULL;
61 : }
62 0 : frame->base = ScdMapGetBase(map);
63 0 : frame->num = frames->framesNum;
64 0 : frame->tid = frames->tid;
65 0 : frame->relPc = relPc;
66 :
67 0 : if (AdiagListInsert(&frames->frameList, frame) != ADIAG_SUCCESS) {
68 0 : SCD_DLOG_ERR("insert frame to list failed, map = %s, pc = %p, sp = %p.", map->name, pc, sp);
69 0 : ScdFrameDestroy(&frame);
70 0 : return NULL;
71 : }
72 0 : frames->framesNum++;
73 0 : ScdElfGetFunctionInfo(&map->dl.elf, relPc, frame->funcName, SCD_FUNC_NAME_LENGTH, &frame->funcOffset);
74 :
75 0 : SCD_DLOG_DBG("map info: name = %s, start = 0x%lx, end = 0x%lx, memory data = 0x%lx, loadBias = 0x%lx.",
76 : map->name, map->start, map->end, map->dl.elf.memory->data, map->dl.elf.loadBias);
77 0 : SCD_DLOG_DBG("create thread(%d) frame[%u] successfully,"
78 : " pc = %p, relPc = %p, base = %p, sp = %p, fp = %p, function(%s: %d).",
79 : frames->tid, frame->num, frame->pc, frame->relPc, frame->base, frame->sp, frame->fp,
80 : strlen(frame->funcName) != 0 ? frame->funcName : "unknown", frame->funcOffset);
81 0 : return frame;
82 : }
83 :
84 0 : TraStatus ScdFramesLoad(ScdFrames *frames, ScdMaps *maps, ScdRegs *regs)
85 : {
86 0 : SCD_CHK_PTR_ACTION(frames, return TRACE_FAILURE);
87 0 : SCD_CHK_PTR_ACTION(maps, return TRACE_FAILURE);
88 0 : SCD_CHK_PTR_ACTION(regs, return TRACE_FAILURE);
89 0 : frames->regs = regs;
90 0 : frames->maps = maps;
91 0 : ScdRegs frameRegs = *(frames->regs);
92 0 : while (frames->framesNum < SCD_MAX_STACK_LAYER) {
93 0 : uintptr_t framePc = ScdRegsGetPc(&frameRegs);
94 0 : uintptr_t frameSp = ScdRegsGetSp(&frameRegs);
95 0 : uintptr_t frameFp = ScdRegsGetFp(&frameRegs);
96 :
97 : // 1. create new frame
98 0 : ScdFrame *frame = ScdFramesCreateFrame(frames, framePc, frameSp, frameFp);
99 0 : if (frame == NULL) {
100 0 : SCD_DLOG_ERR("create frame failed.");
101 0 : return TRACE_FAILURE;
102 : }
103 :
104 : // 2. do step, get next frame regs
105 0 : TraStatus ret = ScdElfStep(&frame->map->dl.elf, frame->relPc, &frameRegs, frames->framesNum == 1);
106 0 : if (ret != TRACE_SUCCESS) {
107 0 : SCD_DLOG_WAR("get from regs, pc = 0x%lx, sp = 0x%lx, fp = 0x%lx.", framePc, frameSp, frameFp);
108 0 : SCD_DLOG_WAR("can not step by elf, pid = %d, tid = %d, num = %u, pc = 0x%lx, sp = 0x%lx, fp = 0x%lx.",
109 : frames->maps->pid, frame->tid, frames->framesNum, frame->pc, frame->sp, frame->fp);
110 0 : ret = ScdFramesFpStep(frame, &frameRegs);
111 0 : if (ret != TRACE_SUCCESS) {
112 0 : SCD_DLOG_ERR("step by fp failed, pid = %d, tid = %d, num = %u, pc = 0x%lx, sp = 0x%lx, fp = 0x%lx.",
113 : frames->maps->pid, frame->tid, frames->framesNum, frame->pc, frame->sp, frame->fp);
114 0 : return TRACE_FAILURE;
115 : }
116 : }
117 0 : if (ScdRegsGetPc(&frameRegs) == 0) {
118 0 : break;
119 : }
120 : // 3. if the pc and sp didn't change, stop.
121 0 : if ((framePc == ScdRegsGetPc(&frameRegs)) && (frameSp == ScdRegsGetSp(&frameRegs))) {
122 0 : break;
123 : }
124 : }
125 0 : return TRACE_SUCCESS;
126 : }
127 :
128 15 : TraStatus ScdFramesInit(ScdFrames *frames, int32_t pid, int32_t tid)
129 : {
130 15 : SCD_CHK_PTR_ACTION(frames, return TRACE_FAILURE);
131 15 : frames->pid = pid;
132 15 : frames->tid = tid;
133 15 : frames->regs = NULL;
134 15 : frames->maps = NULL;
135 15 : frames->framesNum = 0;
136 15 : AdiagStatus adiagRet = AdiagListInit(&frames->frameList);
137 15 : if (adiagRet != ADIAG_SUCCESS) {
138 0 : SCD_DLOG_ERR("frame list of frames init failed, pid = %d, tid = %d.", pid, tid);
139 0 : return TRACE_FAILURE;
140 : }
141 15 : return TRACE_SUCCESS;
142 : }
143 :
144 15 : void ScdFramesUninit(ScdFrames *frames)
145 : {
146 15 : SCD_CHK_PTR_ACTION(frames, return);
147 15 : ScdFrame *node = (ScdFrame *)AdiagListTakeOut(&frames->frameList);
148 30 : while (node != NULL) {
149 15 : ScdFrameDestroy(&node);
150 15 : node = (ScdFrame *)AdiagListTakeOut(&frames->frameList);
151 : }
152 : }
|