summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarol Lewandowski <k.lewandowsk@samsung.com>2020-07-28 12:48:27 +0000
committerGerrit Code Review <gerrit@review>2020-07-28 12:48:27 +0000
commit79a74be4c7fb07d8b5efd08869385173462e599e (patch)
treef3ba13de43a906f9ad131b00c043d0a18d2f08a3
parent49d99694bc9376642e726f14b201d14b7d484e0e (diff)
parent033bc9902ae6cc069acc2cfc8f813313a818bf4f (diff)
downloadcrash-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
* changes: Release 4.0.5 Change the way ELF file are parsed Add an ELF file parser
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/crash-stack/CMakeLists.txt2
-rw-r--r--src/crash-stack/crash-stack-arm.c12
-rw-r--r--src/crash-stack/crash-stack.c59
-rw-r--r--src/shared/telf.c375
-rw-r--r--src/shared/telf.h88
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