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_elf.h"
12 : #include <elf.h>
13 : #include <link.h>
14 : #include <sys/types.h>
15 : #include "adiag_utils.h"
16 : #include "scd_log.h"
17 : #include "scd_dwarf.h"
18 :
19 : #define SCD_ELF_FDE_ENTRY_SIZE 8U
20 : #define SCD_ELF_SH_NAME_LENGTH 128U
21 : #define SCD_UINTPTR_MAX ((uintptr_t)(-1))
22 : #define SCD_PF_X ((uint32_t)(PF_X))
23 :
24 16 : uintptr_t ScdElfGetLoadBias(const ScdElf *elf)
25 : {
26 16 : return elf->loadBias;
27 : }
28 :
29 0 : size_t ScdElfGetFdeNum(const ScdElf *elf)
30 : {
31 0 : return elf->ehFrameHdrSize / SCD_ELF_FDE_ENTRY_SIZE;
32 : }
33 :
34 : /**
35 : * @brief get function info based on pc
36 : * @param [in] elf: elf info
37 : * @param [in] pc: program counter
38 : * @param [out] funcName: function name
39 : * @param [in] len: function name buffer length
40 : * @param [out] funcOffset: function offset in file
41 : * @return NA
42 : */
43 0 : void ScdElfGetFunctionInfo(ScdElf *elf, uintptr_t pc, char *funcName, size_t len, size_t *funcOffset)
44 : {
45 0 : SCD_CHK_PTR_ACTION(elf, return);
46 0 : SCD_CHK_PTR_ACTION(funcName, return);
47 0 : SCD_CHK_PTR_ACTION(funcOffset, return);
48 0 : struct ListHead *pos = NULL;
49 0 : struct AdiagListNode *node = NULL;
50 0 : ScdDlSymbol *symbols = NULL;
51 0 : char buf[SCD_FUNC_NAME_LENGTH] = {0};
52 : // traverse all symbol section to find function symbol
53 0 : LIST_FOR_EACH(pos, &elf->symbolList.list) {
54 0 : node = LIST_ENTRY(pos, struct AdiagListNode, list);
55 0 : if (node == NULL) {
56 0 : return;
57 : }
58 0 : symbols = (ScdDlSymbol *)node->data;
59 0 : for (size_t offset = symbols->symOffset; offset < symbols->symEnd; offset += symbols->symEntrySize) {
60 0 : ElfW(Sym) *sym = (ElfW(Sym) *)ScdMemoryGetAddr(elf->memory, offset, sizeof(ElfW(Sym)));
61 0 : if (sym == NULL) {
62 0 : break;
63 : }
64 : // filter function symbol
65 0 : if ((sym->st_shndx == SHN_UNDEF) || (ELF64_ST_TYPE(sym->st_info) != STT_FUNC)) {
66 0 : continue;
67 : }
68 :
69 0 : size_t startOffset = sym->st_value + elf->memory->data + elf->loadBias;
70 0 : size_t endOffset = startOffset + sym->st_size;
71 0 : if ((pc < startOffset) || (pc >= endOffset)) {
72 0 : continue;
73 : }
74 : // st_name is the offset of symbol name in string table
75 0 : size_t strOffset = symbols->strOffset + sym->st_name;
76 0 : if (strOffset >= symbols->strEnd) {
77 0 : continue;
78 : }
79 :
80 0 : if (ScdMemoryReadString(elf->memory, strOffset, buf,
81 0 : SCD_MIN(SCD_FUNC_NAME_LENGTH, symbols->strEnd - strOffset)) == 0) {
82 0 : continue;
83 : }
84 :
85 0 : errno_t err = memcpy_s(funcName, len, buf, SCD_MIN(strlen(buf) + 1U, len));
86 0 : if (err != EOK) {
87 0 : SCD_DLOG_ERR("memcpy_s failed, err=%d.", (int32_t)err);
88 0 : return;
89 : }
90 0 : *funcOffset = pc - startOffset;
91 0 : return;
92 : }
93 : }
94 : }
95 :
96 0 : TraStatus ScdElfStep(ScdElf *elf, uintptr_t pc, ScdRegs *regs, bool isFirstStack)
97 : {
98 0 : if (elf->ehFrameHdrOffset == 0) {
99 0 : STACKTRACE_LOG_RUN("elf of pc(0x%llx) does not have eh_frame_hdr section.", pc);
100 0 : return TRACE_FAILURE;
101 : }
102 0 : ScdDwarf dwarf = {0};
103 0 : const ScdDwarfStepArgs args = {ScdRegsGetSp(regs), SCD_UINTPTR_MAX, isFirstStack};
104 0 : dwarf.memory = elf->memory;
105 0 : dwarf.ehFrameHdrOffset = elf->ehFrameHdrOffset;
106 0 : dwarf.loadBias = elf->loadBias;
107 0 : SCD_DLOG_DBG("dwarf.ehFrameHdrOffset = 0x%llx, dwarf.loadBias = 0x%llx.", dwarf.ehFrameHdrOffset, dwarf.loadBias);
108 0 : dwarf.fdeCount = ScdElfGetFdeNum(elf);
109 : uintptr_t nextPc;
110 : // when the address read from the elf file is compared with the address in the memory, bias offset is required
111 : // pc is the address in the memory, so it needs to be subtracted by the bias offset
112 0 : TraStatus ret = ScdDwarfStep(&dwarf, regs, &args, pc - dwarf.loadBias, &nextPc);
113 0 : ScdRegsSetPc(regs, nextPc);
114 0 : return ret;
115 : }
116 :
117 16 : STATIC TraStatus ScdElfParseProgramHeaders(ScdElf *elf, ElfW(Ehdr) *ehdr)
118 : {
119 16 : size_t phSize = (size_t)ehdr->e_phnum * (size_t)ehdr->e_phentsize;
120 16 : for (size_t i = 0; i < phSize; i += ehdr->e_phentsize) {
121 16 : ElfW(Phdr) *phdr = (ElfW(Phdr) *)ScdMemoryGetAddr(elf->memory, ehdr->e_phoff + i, sizeof(ElfW(Phdr)));
122 16 : SCD_CHK_PTR_ACTION(phdr, return TRACE_FAILURE);
123 :
124 0 : switch(phdr->p_type) {
125 0 : case PT_LOAD:
126 0 : if ((phdr->p_flags & SCD_PF_X) == 0) {
127 0 : continue;
128 : }
129 0 : if (elf->loadBiasSave == false) {
130 0 : elf->loadBias = phdr->p_vaddr - phdr->p_offset;
131 0 : elf->loadBiasSave = true;
132 : }
133 0 : break;
134 0 : case PT_GNU_EH_FRAME:
135 0 : elf->ehFrameHdrOffset = phdr->p_offset;
136 0 : elf->ehFrameHdrSize = phdr->p_memsz;
137 0 : elf->ehFrameHdrLoadBias = phdr->p_vaddr - phdr->p_offset;
138 0 : break;
139 0 : case PT_DYNAMIC:
140 0 : elf->dynamicOffset = phdr->p_offset;
141 0 : elf->dynamicSize = phdr->p_memsz;
142 0 : break;
143 0 : default:
144 0 : break;
145 : }
146 : }
147 0 : return TRACE_SUCCESS;
148 : }
149 :
150 0 : STATIC TraStatus ScdElfGetStringSectionHeader(ScdElf *elf, ElfW(Ehdr) *ehdr, size_t *secOffset, size_t *secSize)
151 : {
152 0 : ElfW(Shdr) *shdr = ScdMemoryGetAddr(elf->memory,
153 0 : ehdr->e_shoff + (uintptr_t)ehdr->e_shstrndx * (uintptr_t)ehdr->e_shentsize, sizeof(ElfW(Shdr)));
154 0 : if (shdr == NULL) {
155 0 : SCD_DLOG_ERR("read memory failed, get string table section header failed.");
156 0 : return TRACE_FAILURE;
157 : }
158 0 : *secOffset = shdr->sh_offset;
159 0 : *secSize = shdr->sh_size;
160 0 : return TRACE_SUCCESS;
161 : }
162 :
163 0 : STATIC void ScdElfHandleNote(ScdElf *elf, ElfW(Shdr) *shdr, size_t secOffset, size_t secSize)
164 : {
165 0 : if (shdr->sh_name >= secSize) {
166 0 : return;
167 : }
168 0 : char name[SCD_ELF_SH_NAME_LENGTH] = { 0 };
169 0 : if (ScdMemoryReadString(elf->memory, secOffset + shdr->sh_name, name, sizeof(name)) == 0) {
170 0 : return;
171 : }
172 0 : if (strcmp(name, ".note.gnu.build-id") == 0) {
173 0 : elf->buildIdOffset = shdr->sh_offset;
174 0 : elf->buildIdSize = shdr->sh_size;
175 : }
176 0 : return;
177 : }
178 :
179 0 : STATIC TraStatus ScdElfHandleDynsym(ScdElf *elf, ElfW(Ehdr) *ehdr, ElfW(Shdr) *shdr)
180 : {
181 0 : if (shdr->sh_link >= ehdr->e_shnum) {
182 0 : return TRACE_SUCCESS;
183 : }
184 0 : ElfW(Shdr) *strShdr = (ElfW(Shdr) *)ScdMemoryGetAddr(elf->memory,
185 0 : ehdr->e_shoff + (uintptr_t)shdr->sh_link * (uintptr_t)ehdr->e_shentsize, sizeof(ElfW(Shdr)));
186 0 : SCD_CHK_PTR_ACTION(strShdr, return TRACE_FAILURE);
187 :
188 0 : if (strShdr->sh_type != SHT_STRTAB) {
189 0 : return TRACE_SUCCESS;
190 : }
191 0 : ScdDlSymbol *symbol = (ScdDlSymbol *)AdiagMalloc(sizeof(ScdDlSymbol));
192 0 : SCD_CHK_PTR_ACTION(symbol, return TRACE_FAILURE);
193 :
194 0 : symbol->symOffset = shdr->sh_offset;
195 0 : symbol->symEnd = shdr->sh_offset + shdr->sh_size;
196 0 : symbol->symEntrySize = shdr->sh_entsize;
197 0 : symbol->strOffset = strShdr->sh_offset;
198 0 : symbol->strEnd = strShdr->sh_offset + strShdr->sh_size;
199 :
200 0 : AdiagStatus adiagRet = AdiagListInsert(&elf->symbolList, symbol);
201 0 : if (adiagRet != ADIAG_SUCCESS) {
202 0 : SCD_DLOG_ERR("add symbol to list failed.");
203 0 : ADIAG_SAFE_FREE(symbol);
204 0 : return TRACE_FAILURE;
205 : }
206 0 : return TRACE_SUCCESS;
207 : }
208 :
209 0 : STATIC TraStatus ScdElfHandleProgbits(ScdElf *elf, ElfW(Shdr) *shdr, size_t secOffset, size_t secSize)
210 : {
211 0 : if (shdr->sh_name >= secSize) {
212 0 : return TRACE_SUCCESS;
213 : }
214 0 : char name[SCD_ELF_SH_NAME_LENGTH] = { 0 };
215 0 : if (ScdMemoryReadString(elf->memory, secOffset + shdr->sh_name, name, sizeof(name)) == 0) {
216 0 : SCD_DLOG_ERR("read memory failed, get SHT_PROGBITS section failed.");
217 0 : return TRACE_FAILURE;
218 : }
219 0 : if (strcmp(name, ".eh_frame") == 0) {
220 0 : elf->ehFrameOffset = shdr->sh_offset;
221 0 : elf->ehFrameSize = shdr->sh_size;
222 0 : elf->ehFrameLoadBias = shdr->sh_addr - shdr->sh_offset;
223 0 : } else if(strcmp(name, ".eh_frame_hdr") == 0 && elf->ehFrameHdrOffset == 0) {
224 0 : elf->ehFrameHdrOffset = shdr->sh_offset;
225 0 : elf->ehFrameHdrSize = shdr->sh_size;
226 0 : elf->ehFrameHdrLoadBias = shdr->sh_addr - shdr->sh_offset;
227 : } else {
228 : ;
229 : }
230 0 : return TRACE_SUCCESS;
231 : }
232 :
233 0 : STATIC TraStatus ScdElfParseSectionHeaders(ScdElf *elf, ElfW(Ehdr) *ehdr)
234 : {
235 0 : size_t secOffset = 0;
236 0 : size_t secSize = 0;
237 : // get section header entry that contains the section names
238 0 : if (ehdr->e_shstrndx < ehdr->e_shnum) {
239 0 : if (ScdElfGetStringSectionHeader(elf, ehdr, &secOffset, &secSize) != TRACE_SUCCESS) {
240 0 : return TRACE_FAILURE;
241 : }
242 : }
243 0 : size_t ehSize = (size_t)ehdr->e_shnum * (size_t)ehdr->e_shentsize;
244 0 : for (size_t i = ehdr->e_shentsize; i < ehSize; i += ehdr->e_shentsize) {
245 0 : ElfW(Shdr) *shdr = (ElfW(Shdr) *)ScdMemoryGetAddr(elf->memory, ehdr->e_shoff + i, sizeof(ElfW(Shdr)));
246 0 : if (shdr == NULL) {
247 0 : SCD_DLOG_ERR("read memory failed, get section[%zu] failed.", i);
248 0 : return TRACE_FAILURE;
249 : }
250 0 : switch(shdr->sh_type) {
251 0 : case SHT_NOTE: {
252 0 : ScdElfHandleNote(elf, shdr, secOffset, secSize);
253 0 : break;
254 : }
255 0 : case SHT_SYMTAB:
256 : case SHT_DYNSYM: {
257 0 : if (ScdElfHandleDynsym(elf, ehdr, shdr) != TRACE_SUCCESS) {
258 0 : return TRACE_FAILURE;
259 : }
260 0 : break;
261 : }
262 0 : case SHT_PROGBITS: {
263 0 : if (ScdElfHandleProgbits(elf, shdr, secOffset, secSize) != TRACE_SUCCESS) {
264 0 : return TRACE_FAILURE;
265 : }
266 0 : break;
267 : }
268 0 : default:
269 0 : break;
270 : }
271 : }
272 0 : return TRACE_SUCCESS;
273 : }
274 :
275 32 : STATIC TraStatus ScdElfCheckValid(ElfW(Ehdr) *ehdr)
276 : {
277 : // check magic
278 32 : if (strncmp((const char *)ehdr->e_ident, (const char *)ELFMAG, SELFMAG) != 0) {
279 16 : SCD_DLOG_ERR("elf valid check failed, ehdr->e_ident = %s.", ehdr->e_ident);
280 16 : return TRACE_FAILURE;
281 : }
282 :
283 16 : return TRACE_SUCCESS;
284 : }
285 :
286 48 : STATIC TraStatus ScdElfParse(ScdElf *elf)
287 : {
288 : // get ELF header
289 48 : ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)ScdMemoryGetAddr(elf->memory, 0, sizeof(ElfW(Ehdr)));
290 48 : SCD_CHK_PTR_ACTION(ehdr, return TRACE_FAILURE);
291 :
292 32 : TraStatus ret = ScdElfCheckValid(ehdr);
293 32 : if (ret != TRACE_SUCCESS) {
294 16 : return TRACE_FAILURE;
295 : }
296 :
297 16 : ret = ScdElfParseProgramHeaders(elf, ehdr);
298 16 : if (ret != TRACE_SUCCESS) {
299 16 : return TRACE_FAILURE;
300 : }
301 :
302 0 : ret = ScdElfParseSectionHeaders(elf, ehdr);
303 0 : if (ret != TRACE_SUCCESS) {
304 0 : return TRACE_FAILURE;
305 : }
306 :
307 0 : return TRACE_SUCCESS;
308 : }
309 :
310 : /**
311 : * @brief load elf info from memory
312 : * @param [in] elf: elf info
313 : * @param [in] pid: process id
314 : * @param [in] memory: dynamic library memory
315 : * @return TraStatus
316 : */
317 48 : TraStatus ScdElfLoad(ScdElf *elf, int32_t pid, ScdMemory *memory)
318 : {
319 48 : SCD_CHK_PTR_ACTION(elf, return TRACE_FAILURE);
320 48 : elf->pid = pid;
321 48 : elf->memory = memory;
322 :
323 48 : TraStatus ret = ScdElfParse(elf);
324 48 : if (ret != TRACE_SUCCESS) {
325 48 : return TRACE_FAILURE;
326 : }
327 :
328 0 : return TRACE_SUCCESS;
329 : }
330 :
331 : /**
332 : * @brief init elf info
333 : * @param [in] elf: elf info
334 : * @return TraStatus
335 : */
336 1023 : TraStatus ScdElfInit(ScdElf *elf)
337 : {
338 1023 : (void)memset_s(elf, sizeof(ScdElf), 0, sizeof(ScdElf));
339 1023 : elf->loadBiasSave = false;
340 1023 : return AdiagListInit(&elf->symbolList);
341 : }
342 :
343 : /**
344 : * @brief uinit elf info
345 : * @param [in] elf: elf info
346 : * @return NA
347 : */
348 16 : void ScdElfUninit(ScdElf *elf)
349 : {
350 16 : ScdDlSymbol *node = (ScdDlSymbol *)AdiagListTakeOut(&elf->symbolList);
351 16 : while (node != NULL) {
352 0 : ADIAG_SAFE_FREE(node);
353 0 : node = (ScdDlSymbol *)AdiagListTakeOut(&elf->symbolList);
354 : }
355 16 : }
|