diff options
author | Karol Lewandowski <k.lewandowsk@samsung.com> | 2020-07-28 12:48:27 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@review> | 2020-07-28 12:48:27 +0000 |
commit | 79a74be4c7fb07d8b5efd08869385173462e599e (patch) | |
tree | f3ba13de43a906f9ad131b00c043d0a18d2f08a3 | |
parent | 49d99694bc9376642e726f14b201d14b7d484e0e (diff) | |
parent | 033bc9902ae6cc069acc2cfc8f813313a818bf4f (diff) | |
download | crash-worker-accepted/tizen_4.0_unified.tar.gz crash-worker-accepted/tizen_4.0_unified.tar.bz2 crash-worker-accepted/tizen_4.0_unified.zip |
Merge changes I9d94aed9,Ia1b3e5de,Ic5af3e23 into tizen_4.0submit/tizen_4.0/20200728.132733submit/tizen_4.0/20200728.125504accepted/tizen/4.0/unified/20200730.072834tizen_4.0accepted/tizen_4.0_unified
* changes:
Release 4.0.5
Change the way ELF file are parsed
Add an ELF file parser
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/crash-stack/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/crash-stack/crash-stack-arm.c | 12 | ||||
-rw-r--r-- | src/crash-stack/crash-stack.c | 59 | ||||
-rw-r--r-- | src/shared/telf.c | 375 | ||||
-rw-r--r-- | src/shared/telf.h | 88 |
6 files changed, 505 insertions, 33 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d55fc2b..6817fd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ PROJECT(crash-worker C) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64) + # Sub modules ADD_SUBDIRECTORY(src/crash-manager) diff --git a/src/crash-stack/CMakeLists.txt b/src/crash-stack/CMakeLists.txt index 0c1a8a4..ff8bfbf 100644 --- a/src/crash-stack/CMakeLists.txt +++ b/src/crash-stack/CMakeLists.txt @@ -4,7 +4,7 @@ set(CRASH_STACK_BIN "crash-stack") # Common source code files INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src) -set(CRASH_STACK_SRCS crash-stack.c crash-stack-libunw.c ${CMAKE_SOURCE_DIR}/src/shared/util.c) +set(CRASH_STACK_SRCS crash-stack.c crash-stack-libunw.c ${CMAKE_SOURCE_DIR}/src/shared/util.c ${CMAKE_SOURCE_DIR}/src/shared/telf.c) # Add architecture dependent source files if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") diff --git a/src/crash-stack/crash-stack-arm.c b/src/crash-stack/crash-stack-arm.c index 5f9033f..948d893 100644 --- a/src/crash-stack/crash-stack-arm.c +++ b/src/crash-stack/crash-stack-arm.c @@ -24,6 +24,8 @@ */ #include "crash-stack.h" +#include <elf.h> +#include <stdio.h> #include <string.h> #include <sys/ptrace.h> #include <sys/user.h> @@ -41,11 +43,11 @@ * @brief Important registers for unwinding stack on ARM */ struct Regs { - Dwarf_Addr regs[REGS_REGULAR_NUM]; ///< regular registers - Dwarf_Addr sp; ///< register: stack pointer - Dwarf_Addr lr; ///< register: link register - Dwarf_Addr pc; ///< register: program counter - Dwarf_Addr spsr; ///< register: status register + Elf64_Addr regs[REGS_REGULAR_NUM]; ///< regular registers + Elf64_Addr sp; ///< register: stack pointer + Elf64_Addr lr; ///< register: link register + Elf64_Addr pc; ///< register: program counter + Elf64_Addr spsr; ///< register: status register }; typedef struct Regs Regs; ///< convenience type definition diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 653a064..8dd2b64 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -18,6 +18,7 @@ * RafaĆ Pietruch <r.pietruch@samsung.com> */ #define _GNU_SOURCE 1 +#define _LARGEFILE64_SOURCE /** * @file crash-stack.c @@ -51,6 +52,7 @@ #include <elfutils/version.h> #include <elfutils/libdwfl.h> #include "shared/util.h" +#include "shared/telf.h" #define BUF_SIZE (BUFSIZ) #define HEXA 16 @@ -134,48 +136,50 @@ static int __module_callback(Dwfl_Module *module, void **userdata, return DWARF_CB_OK; } -static void __find_symbol_in_elf(ProcInfo *proc_info, Dwarf_Addr mapping_start) +static void __find_symbol_in_elf(ProcInfo *proc_info, Elf64_Addr mapping_start) { - Elf *elf; + TElf *elf = malloc(sizeof(TElf)); int fd; const char *elf_name = proc_info->module_name; - Dwarf_Addr address = proc_info->addr; + Elf64_Addr address = proc_info->addr; fd = open(elf_name, O_RDONLY); - if (-1 == fd) + if (-1 == fd) { + free(elf); return; + } - elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); - - if (NULL == elf) { + if (!teu_begin(fd, elf)) { close(fd); + free(elf); + teu_close(elf); return; } - Elf_Scn *scn = NULL; int found = 0; - while ((scn = elf_nextscn(elf, scn)) != NULL && !found) { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem); - if (shdr != NULL && (shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM)) { - Elf_Data *sdata = elf_getdata(scn, NULL); - unsigned int nsyms = sdata->d_size / (gelf_getclass(elf) == ELFCLASS32 ? - sizeof(Elf32_Sym) : - sizeof(Elf64_Sym)); - unsigned int cnt; + for (size_t i = 0; i < elf->ehdr.e_shnum && !found; i++) { + Elf64_Shdr shdr; + + if (!teu_getshdr(elf, i, &shdr)) + break; + + if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { + void *data = teu_getsdata(elf, &shdr); + + unsigned int nsyms = shdr.sh_size / shdr.sh_entsize; uintptr_t address_offset = address; - if (shdr->sh_type == SHT_DYNSYM) + + if (shdr.sh_type == SHT_DYNSYM) address_offset -= mapping_start; - for (cnt = 0; cnt < nsyms; ++cnt) { - GElf_Sym sym_mem; - Elf32_Word xndx; - GElf_Sym *sym = gelf_getsymshndx(sdata, NULL, cnt, &sym_mem, &xndx); - if (sym != NULL && sym->st_shndx != SHN_UNDEF) { - if (sym->st_value <= address_offset && address_offset < sym->st_value + sym->st_size) { + + for (unsigned int cnt = 0; cnt < nsyms; ++cnt) { + Elf64_Sym sym; + if (teu_getsym(elf, &shdr, cnt, data, &sym) && sym.st_shndx != SHN_UNDEF) { + if (sym.st_value <= address_offset && address_offset < sym.st_value + sym.st_size) { free(proc_info->name); - proc_info->name = strdup(elf_strptr(elf, shdr->sh_link, sym->st_name)); - proc_info->offset = address_offset - sym->st_value; + proc_info->name = strdup(teu_strptr(elf, shdr.sh_link, sym.st_name)); + proc_info->offset = address_offset - sym.st_value; found = 1; break; } @@ -184,7 +188,8 @@ static void __find_symbol_in_elf(ProcInfo *proc_info, Dwarf_Addr mapping_start) } } - elf_end(elf); + teu_close(elf); + free(elf); close(fd); } diff --git a/src/shared/telf.c b/src/shared/telf.c new file mode 100644 index 0000000..ed4ae04 --- /dev/null +++ b/src/shared/telf.c @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2020 Samsung Electronics Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <elf.h> +#include <stdbool.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdarg.h> +#include <sys/mman.h> + +#include "telf.h" + +static void set_error(TElf *elf, const char *fmt, ...) +{ + assert(elf); + + va_list args; + va_start(args, fmt); + vsnprintf(elf->last_error, sizeof(elf->last_error), fmt, args); + va_end(args); +} + +static bool set_offset(TElf *elf, off64_t offset) +{ + assert(elf); + + if (lseek64(elf->fd, offset, SEEK_SET) == (off64_t)-1) { + set_error(elf, "set file offset error: %m"); + return false; + } + return true; +} + +static bool readehdr(TElf *elf, Elf64_Ehdr *ehdr) +{ + assert(elf); + assert(ehdr); + + if (teu_class(elf) == ELFCLASS32) { + Elf32_Ehdr *ehdr32 = elf->data; + + memcpy(ehdr->e_ident, ehdr32->e_ident, sizeof(ehdr->e_ident)); + ehdr->e_type = ehdr32->e_type; + ehdr->e_machine = ehdr32->e_machine; + ehdr->e_version = ehdr32->e_version; + ehdr->e_entry = (Elf64_Addr)ehdr32->e_entry; + ehdr->e_phoff = (Elf64_Off)ehdr32->e_phoff; + ehdr->e_shoff = (Elf64_Off)ehdr32->e_shoff; + ehdr->e_flags = ehdr32->e_flags; + ehdr->e_ehsize = ehdr32->e_ehsize; + ehdr->e_phentsize = ehdr32->e_phentsize; + ehdr->e_phnum = ehdr32->e_phnum; + ehdr->e_shentsize = ehdr32->e_shentsize; + ehdr->e_shnum = ehdr32->e_shnum; + ehdr->e_shstrndx = ehdr32->e_shstrndx; + + } else if (teu_class(elf) == ELFCLASS64) { + memcpy(ehdr, elf->data, sizeof(*ehdr)); + } else { + set_error(elf, "Unknown ELF class"); + return false; + } + + return true; +} + +char *teu_errmsg(TElf *elf) +{ + assert(elf); + return elf->last_error; +} + +bool teu_iself(TElf *elf) +{ + assert(elf); + + return elf->ident[EI_MAG0] == ELFMAG0 && + elf->ident[EI_MAG1] == ELFMAG1 && + elf->ident[EI_MAG2] == ELFMAG2 && + elf->ident[EI_MAG3] == ELFMAG3; +} + +uint8_t teu_class(TElf *elf) +{ + assert(elf); + + return (uint8_t)elf->ident[EI_CLASS]; +} + +off64_t get_file_size(TElf *elf, int fd) +{ + off64_t end = lseek64(fd, 0, SEEK_END); + + if (end == (off64_t)-1) { + set_error(elf, "set file offset error: %m"); + return (off64_t)-1; + } + + if (lseek64(fd, 0, SEEK_SET) == (off64_t)-1) { + set_error(elf, "set file offset error: %m"); + return (off64_t)-1; + } + + return end; +} + +static bool teu_init(TElf *elf) +{ + elf->ident = elf->data; + + if (!readehdr(elf, &elf->ehdr)) + return false; + + return true; +} + +bool teu_begin(int fd, TElf *elf) +{ + assert(elf); + assert(fd >= 0); + + elf->fd = fd; + + if (!set_offset(elf, 0)) + return false; + + elf->data_size = get_file_size(elf, fd); + if (elf->data_size == (off64_t)-1) + return false; + + elf->data = mmap(NULL, (elf->data_size + (1024-1)) & ~(1024-1), + PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0); + if (elf->data == NULL) { + set_error(elf, "Can not allocate memory for file: %m"); + return false; + } + + elf->status = TEU_FILE; + + if (!teu_init(elf)) + return false; + + return true; +} + +bool teu_begin_memory(void *memory, TElf *elf) +{ + assert(memory); + assert(elf); + + elf->status = TEU_MEMORY; + + if (!teu_init(elf)) + return false; + + return true; +} + +bool teu_getehdr(TElf *elf, Elf64_Ehdr *ehdr) +{ + assert(elf); + assert(ehdr); + + memcpy(ehdr, &elf->ehdr, sizeof(*ehdr)); + return true; +} + +bool teu_getphdr(TElf *elf, uint64_t index, Elf64_Phdr *phdr) +{ + assert(elf); + assert(phdr); + + if (index >= elf->ehdr.e_phnum) { + set_error(elf, "index is out of range of program headers"); + return false; + } + + void *phdr_data = elf->data + elf->ehdr.e_phoff + index*elf->ehdr.e_phentsize; + + if (teu_class(elf) == ELFCLASS32) { + Elf32_Phdr *phdr32 = phdr_data; + + phdr->p_type = phdr32->p_type; + phdr->p_flags = phdr32->p_flags; + phdr->p_offset = (Elf64_Off)phdr32->p_offset; + phdr->p_vaddr = (Elf64_Addr)phdr32->p_vaddr; + phdr->p_paddr = (Elf64_Addr)phdr32->p_paddr; + phdr->p_filesz = (uint64_t)phdr32->p_filesz; + phdr->p_memsz = (uint64_t)phdr32->p_memsz; + phdr->p_align = (uint64_t)phdr32->p_align; + } else if (teu_class(elf) == ELFCLASS64) { + memcpy(phdr, phdr_data, elf->ehdr.e_phentsize); + } else { + set_error(elf, "Unknown ELF class"); + return false; + } + + return true; +} + +bool teu_getshdr(TElf *elf, uint64_t index, Elf64_Shdr *shdr) +{ + assert(elf); + assert(shdr); + + if (index >= elf->ehdr.e_shnum) { + set_error(elf, "index is out of range of section headers"); + return false; + } + + void *shdr_data = elf->data + elf->ehdr.e_shoff + index*elf->ehdr.e_shentsize; + + if (teu_class(elf) == ELFCLASS32) { + Elf32_Shdr *shdr32 = shdr_data; + + shdr->sh_name = shdr32->sh_name; + shdr->sh_type = shdr32->sh_type; + shdr->sh_flags = (uint64_t)shdr32->sh_flags; + shdr->sh_addr = (Elf64_Addr)shdr32->sh_addr; + shdr->sh_offset = (Elf64_Off)shdr32->sh_offset; + shdr->sh_size = (uint64_t)shdr32->sh_size; + shdr->sh_link = shdr32->sh_link; + shdr->sh_info = shdr32->sh_info; + shdr->sh_addralign = (uint64_t)shdr32->sh_addralign; + shdr->sh_entsize = (uint64_t)shdr32->sh_entsize; + } else if (teu_class(elf) == ELFCLASS64) { + memcpy(shdr, shdr_data, elf->ehdr.e_shentsize); + } else { + set_error(elf, "Unknown ELF class"); + return false; + } + + return true; +} + +char *teu_secname(TElf *elf, Elf64_Shdr *shdr) +{ + assert(elf); + assert(shdr); + + Elf64_Shdr strsection; + if (!teu_getshdr(elf, elf->ehdr.e_shstrndx, &strsection)) { + set_error(elf, "getshdr error"); + return false; + } + + return (char*)(elf->data + strsection.sh_offset + shdr->sh_name); +} + +void *teu_getsdata(TElf *elf, Elf64_Shdr *shdr) +{ + assert(elf); + assert(shdr); + + return elf->data + shdr->sh_offset; +} + +bool teu_getsym(TElf *elf, Elf64_Shdr *shdr, int index, void *data, Elf64_Sym *sym) +{ + assert(elf); + assert(shdr); + assert(data); + assert(sym); + + if (index*shdr->sh_entsize >= shdr->sh_size) { + set_error(elf, "index is out of range"); + return false; + } + + if (teu_class(elf) == ELFCLASS32) { + Elf32_Sym sym32; + memcpy(&sym32, data + index*(shdr->sh_entsize), shdr->sh_entsize); + sym->st_name = sym32.st_name; + sym->st_info = sym32.st_info; + sym->st_other = sym32.st_other; + sym->st_shndx = sym32.st_shndx; + sym->st_value = (Elf64_Addr)sym32.st_value; + sym->st_size = (uint64_t)sym32.st_size; + } else if (teu_class(elf) == ELFCLASS64) { + memcpy(sym, data + index*(shdr->sh_entsize), shdr->sh_entsize); + } else { + set_error(elf, "Unknown ELF class"); + return false; + } + + return true; +} + +char *teu_strptr(TElf *elf, int sindex, off64_t offset) +{ + assert(elf); + + Elf64_Shdr strsection; + if (!teu_getshdr(elf, sindex, &strsection)) { + set_error(elf, "getshdr error"); + return false; + } + + return (char*)(elf->data + strsection.sh_offset + offset); +} + +bool teu_close(TElf *elf) +{ + assert(elf); + + if (elf->status == TEU_MEMORY) + munmap(elf->data, elf->data_size); + + return true; +} + +bool teu_getdata(TElf *elf, off64_t offset, uint64_t size, void *data) +{ + assert(elf); + assert(data); + + memcpy(data, elf->data + offset, size); + + return true; +} + +off64_t teu_getnote(TElf *elf, void *data, off64_t offset, + Elf64_Nhdr *nhdr, off64_t *name_offset, off64_t *desc_offset) +{ + assert(elf); + assert(data); + assert(nhdr); + assert(name_offset); + assert(desc_offset); + + if (teu_class(elf) == ELFCLASS32) { + Elf32_Nhdr *nhdr32 = data + offset; + nhdr->n_descsz = (Elf64_Word)nhdr32->n_descsz; + nhdr->n_namesz = (Elf64_Word)nhdr32->n_namesz; + nhdr->n_type = (Elf64_Word)nhdr32->n_type; + *name_offset = offset + sizeof(nhdr32); + } else if (teu_class(elf) == ELFCLASS64) { + memcpy(nhdr, data + offset, sizeof(*nhdr)); + *name_offset = offset + sizeof(*nhdr); + } else { + set_error(elf, "Uknown ELF class"); + return (off64_t)-1; + } + + *desc_offset = *name_offset + ((nhdr->n_namesz + 3) & ~3); + return *desc_offset + ((nhdr->n_descsz + 3) & ~3); +} diff --git a/src/shared/telf.h b/src/shared/telf.h new file mode 100644 index 0000000..905a185 --- /dev/null +++ b/src/shared/telf.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2020 Samsung Electronics Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __TELF_H +#define __TELF_H +#include <elf.h> +#include <stdbool.h> +#include <sys/types.h> + +#define ERR_MSG_LEN 1024 + +enum TEU_STATUS {TEU_NOINIT = 0, + TEU_FILE, + TEU_MEMORY}; + +struct teu_elf { + enum TEU_STATUS status; + int fd; + char *ident; + off64_t saved_offset; + Elf64_Ehdr ehdr; + char last_error[ERR_MSG_LEN]; + void *data; + off64_t data_size; +}; + +typedef struct teu_elf TElf; + +#ifdef __cplusplus +extern "C" { +#endif + +char *teu_errmsg(TElf *elf); + +bool teu_iself(TElf *elf); + +uint8_t teu_class(TElf *elf); + +bool teu_internal_getehdr(TElf *elf, Elf64_Ehdr *ehdr); + +bool teu_begin(int fd, TElf *elf); + +bool teu_begin_memory(void *memory, TElf *elf); + +bool teu_getehdr(TElf *elf, Elf64_Ehdr *ehdr); + +bool teu_getphdr(TElf *elf, uint64_t index, Elf64_Phdr *phdr); + +bool teu_getshdr(TElf *elf, uint64_t index, Elf64_Shdr *shdr); + +char *teu_secname(TElf *elf, Elf64_Shdr *shdr); + +void *teu_getsdata(TElf *elf, Elf64_Shdr *shdr); + +bool teu_getsym(TElf *elf, Elf64_Shdr *shdr, int index, void *data, Elf64_Sym *sym); + +char *teu_strptr(TElf *elf, int sindex, off64_t offset); + +bool teu_close(TElf *elf); + +bool teu_getdata(TElf *elf, off64_t offset, uint64_t size, void *data); + +off64_t teu_getnote(TElf *elf, void *data, off64_t offset, Elf64_Nhdr *nhdr, off64_t *name_offset, off64_t *desc_offset); + +#ifdef __cplusplus +} +#endif + +#endif // __TELF_H |