source: XIOS3/trunk/extern/cpptrace/src/elf.hpp @ 2573

Last change on this file since 2573 was 2573, checked in by ymipsl, 9 months ago

create new external source lib : cpptrace, for statck trace output
YM

File size: 3.3 KB
Line 
1#ifndef ELF_HPP
2#define ELF_HPP
3
4#include "common.hpp"
5
6#if IS_LINUX
7#include <array>
8#include <cstdint>
9#include <cstdio>
10#include <cstring>
11
12#include <elf.h>
13
14template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
15T elf_byteswap_if_needed(T value, bool elf_is_little) {
16    if(is_little_endian() == elf_is_little) {
17        return value;
18    } else {
19        return byteswap(value);
20    }
21}
22
23// TODO: Address code duplication here. Do we actually have to care about 32-bit if the library is compiled as 64-bit?
24// I think probably not...
25
26// TODO: Re-evaluate use of off_t
27// I think we can rely on PT_PHDR https://stackoverflow.com/q/61568612/15675011...
28static uintptr_t elf_get_module_image_base_from_program_table(
29    FILE* file,
30    bool is_64,
31    bool is_little_endian,
32    off_t e_phoff,
33    off_t e_phentsize,
34    int e_phnum
35) {
36    for(int i = 0; i < e_phnum; i++) {
37        if(is_64) {
38            Elf64_Phdr program_header = load_bytes<Elf64_Phdr>(file, e_phoff + e_phentsize * i);
39            if(elf_byteswap_if_needed(program_header.p_type, is_little_endian) == PT_PHDR) {
40                return elf_byteswap_if_needed(program_header.p_vaddr, is_little_endian)
41                        - elf_byteswap_if_needed(program_header.p_offset, is_little_endian);
42            }
43        } else {
44            Elf32_Phdr program_header = load_bytes<Elf32_Phdr>(file, e_phoff + e_phentsize * i);
45            if(elf_byteswap_if_needed(program_header.p_type, is_little_endian) == PT_PHDR) {
46                return elf_byteswap_if_needed(program_header.p_vaddr, is_little_endian)
47                        - elf_byteswap_if_needed(program_header.p_offset, is_little_endian);
48            }
49        }
50    }
51    return 0;
52}
53
54static uintptr_t elf_get_module_image_base(const std::string& obj_path) {
55    FILE* file = fopen(obj_path.c_str(), "rb");
56    if(file == nullptr) {
57        throw file_error();
58    }
59    // Initial checks/metadata
60    auto magic = load_bytes<std::array<char, 4>>(file, 0);
61    internal_verify(magic == (std::array<char, 4>{0x7F, 'E', 'L', 'F'}));
62    bool is_64 = load_bytes<uint8_t>(file, 4) == 2;
63    bool is_little_endian = load_bytes<uint8_t>(file, 5) == 1;
64    internal_verify(load_bytes<uint8_t>(file, 6) == 1, "Unexpected ELF version");
65    //
66    if(is_64) {
67        Elf64_Ehdr file_header = load_bytes<Elf64_Ehdr>(file, 0);
68        internal_verify(file_header.e_ehsize == sizeof(Elf64_Ehdr));
69        return elf_get_module_image_base_from_program_table(
70            file,
71            is_64,
72            is_little_endian,
73            elf_byteswap_if_needed(file_header.e_phoff, is_little_endian),
74            elf_byteswap_if_needed(file_header.e_phentsize, is_little_endian),
75            elf_byteswap_if_needed(file_header.e_phnum, is_little_endian)
76        );
77    } else {
78        Elf32_Ehdr file_header = load_bytes<Elf32_Ehdr>(file, 0);
79        internal_verify(file_header.e_ehsize == sizeof(Elf32_Ehdr));
80        return elf_get_module_image_base_from_program_table(
81            file,
82            is_64,
83            is_little_endian,
84            elf_byteswap_if_needed(file_header.e_phoff, is_little_endian),
85            elf_byteswap_if_needed(file_header.e_phentsize, is_little_endian),
86            elf_byteswap_if_needed(file_header.e_phnum, is_little_endian)
87        );
88    }
89}
90
91#endif
92
93#endif
Note: See TracBrowser for help on using the repository browser.