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 26 : STATIC ScdFrame* ScdFramesCreateFrame(ScdFrames* frames, uintptr_t pc, uintptr_t sp, uintptr_t fp)
43 : {
44 26 : ScdMap* map = ScdMapsGetMapByPc(frames->maps, pc);
45 26 : if (map == NULL) {
46 6 : SCD_DLOG_ERR("can not find map, pc = %p, sp = %p.", pc, sp);
47 6 : return NULL;
48 : }
49 20 : SCD_DLOG_INF("find pc 0x%llx in map %s", pc, map->name);
50 :
51 20 : TraStatus ret = ScdDlLoad(&map->dl, frames->pid, map->name);
52 20 : if (ret != TRACE_SUCCESS) {
53 4 : SCD_DLOG_ERR("load map(%s) failed, pc = %p, sp = %p.", map->name, pc, sp);
54 4 : return NULL;
55 : }
56 16 : uintptr_t relPc = ScdMapGetRelPc(map, pc);
57 16 : ScdFrame* frame = ScdFrameCreate(map, pc, sp, fp);
58 16 : if (frame == NULL) {
59 4 : SCD_DLOG_ERR("create frame failed, map = %s, pc = %p, sp = %p.", map->name, pc, sp);
60 4 : return NULL;
61 : }
62 12 : frame->base = ScdMapGetBase(map);
63 12 : frame->num = frames->framesNum;
64 12 : frame->tid = frames->tid;
65 12 : frame->relPc = relPc;
66 :
67 12 : if (AdiagListInsert(&frames->frameList, frame) != ADIAG_SUCCESS) {
68 2 : SCD_DLOG_ERR("insert frame to list failed, map = %s, pc = %p, sp = %p.", map->name, pc, sp);
69 2 : ScdFrameDestroy(&frame);
70 2 : return NULL;
71 : }
72 10 : frames->framesNum++;
73 10 : ScdElfGetFunctionInfo(&map->dl.elf, relPc, frame->funcName, SCD_FUNC_NAME_LENGTH, &frame->funcOffset);
74 :
75 10 : SCD_DLOG_DBG(
76 : "map info: name = %s, start = 0x%lx, end = 0x%lx, memory data = 0x%lx, loadBias = 0x%lx.", map->name,
77 : map->start, map->end, map->dl.elf.memory->data, map->dl.elf.loadBias);
78 10 : SCD_DLOG_DBG(
79 : "create thread(%d) frame[%u] successfully,"
80 : " pc = %p, relPc = %p, base = %p, sp = %p, fp = %p, function(%s: %d).",
81 : frames->tid, frame->num, frame->pc, frame->relPc, frame->base, frame->sp, frame->fp,
82 : strlen(frame->funcName) != 0 ? frame->funcName : "unknown", frame->funcOffset);
83 10 : return frame;
84 : }
85 :
86 30 : TraStatus ScdFramesLoad(ScdFrames* frames, ScdMaps* maps, ScdRegs* regs)
87 : {
88 30 : SCD_CHK_PTR_ACTION(frames, return TRACE_FAILURE);
89 30 : SCD_CHK_PTR_ACTION(maps, return TRACE_FAILURE);
90 30 : SCD_CHK_PTR_ACTION(regs, return TRACE_FAILURE);
91 30 : frames->regs = regs;
92 30 : frames->maps = maps;
93 30 : ScdRegs frameRegs = *(frames->regs);
94 60 : while (frames->framesNum < SCD_MAX_STACK_LAYER) {
95 26 : uintptr_t framePc = ScdRegsGetPc(&frameRegs);
96 26 : uintptr_t frameSp = ScdRegsGetSp(&frameRegs);
97 26 : uintptr_t frameFp = ScdRegsGetFp(&frameRegs);
98 :
99 : // 1. create new frame
100 26 : ScdFrame* frame = ScdFramesCreateFrame(frames, framePc, frameSp, frameFp);
101 26 : if (frame == NULL) {
102 16 : SCD_DLOG_ERR("create frame failed.");
103 16 : return TRACE_FAILURE;
104 : }
105 :
106 : // 2. do step, get next frame regs
107 10 : TraStatus ret = ScdElfStep(&frame->map->dl.elf, frame->relPc, &frameRegs, frames->framesNum == 1);
108 10 : if (ret != TRACE_SUCCESS) {
109 8 : SCD_DLOG_WAR("get from regs, pc = 0x%lx, sp = 0x%lx, fp = 0x%lx.", framePc, frameSp, frameFp);
110 8 : SCD_DLOG_WAR(
111 : "can not step by elf, pid = %d, tid = %d, num = %u, pc = 0x%lx, sp = 0x%lx, fp = 0x%lx.",
112 : frames->maps->pid, frame->tid, frames->framesNum, frame->pc, frame->sp, frame->fp);
113 8 : ret = ScdFramesFpStep(frame, &frameRegs);
114 8 : if (ret != TRACE_SUCCESS) {
115 2 : SCD_DLOG_ERR(
116 : "step by fp failed, pid = %d, tid = %d, num = %u, pc = 0x%lx, sp = 0x%lx, fp = 0x%lx.",
117 : frames->maps->pid, frame->tid, frames->framesNum, frame->pc, frame->sp, frame->fp);
118 2 : return TRACE_FAILURE;
119 : }
120 : }
121 8 : if (ScdRegsGetPc(&frameRegs) == 0) {
122 0 : break;
123 : }
124 : // 3. if the pc and sp didn't change, stop.
125 8 : if ((framePc == ScdRegsGetPc(&frameRegs)) && (frameSp == ScdRegsGetSp(&frameRegs))) {
126 8 : break;
127 : }
128 : }
129 12 : return TRACE_SUCCESS;
130 : }
131 :
132 40 : TraStatus ScdFramesInit(ScdFrames* frames, int32_t pid, int32_t tid)
133 : {
134 40 : SCD_CHK_PTR_ACTION(frames, return TRACE_FAILURE);
135 40 : frames->pid = pid;
136 40 : frames->tid = tid;
137 40 : frames->regs = NULL;
138 40 : frames->maps = NULL;
139 40 : frames->framesNum = 0;
140 40 : AdiagStatus adiagRet = AdiagListInit(&frames->frameList);
141 40 : if (adiagRet != ADIAG_SUCCESS) {
142 2 : SCD_DLOG_ERR("frame list of frames init failed, pid = %d, tid = %d.", pid, tid);
143 2 : return TRACE_FAILURE;
144 : }
145 38 : return TRACE_SUCCESS;
146 : }
147 :
148 40 : void ScdFramesUninit(ScdFrames* frames)
149 : {
150 40 : SCD_CHK_PTR_ACTION(frames, return);
151 40 : ScdFrame* node = (ScdFrame*)AdiagListTakeOut(&frames->frameList);
152 69 : while (node != NULL) {
153 29 : ScdFrameDestroy(&node);
154 29 : node = (ScdFrame*)AdiagListTakeOut(&frames->frameList);
155 : }
156 : }
|