LCOV - code coverage report
Current view: top level - atrace/utrace/stacktrace/stacktrace_dumper - scd_frames.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 83.9 % 87 73
Test Date: 2026-08-31 10:07:06 Functions: 80.0 % 5 4

            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              : }
        

Generated by: LCOV version 2.0-1