1#if defined(__ELF__) && !defined(__FreeBSD__)
2
3#include <Common/Elf.h>
4#include <Common/Exception.h>
5
6#include <string.h>
7
8
9namespace DB
10{
11
12namespace ErrorCodes
13{
14 extern const int CANNOT_PARSE_ELF;
15}
16
17
18Elf::Elf(const std::string & path)
19 : in(path, 0)
20{
21 /// Check if it's an elf.
22 elf_size = in.buffer().size();
23 if (elf_size < sizeof(ElfEhdr))
24 throw Exception("The size of supposedly ELF file is too small", ErrorCodes::CANNOT_PARSE_ELF);
25
26 mapped = in.buffer().begin();
27 header = reinterpret_cast<const ElfEhdr *>(mapped);
28
29 if (memcmp(header->e_ident, "\x7F""ELF", 4) != 0)
30 throw Exception("The file is not ELF according to magic", ErrorCodes::CANNOT_PARSE_ELF);
31
32 /// Get section header.
33 ElfOff section_header_offset = header->e_shoff;
34 uint16_t section_header_num_entries = header->e_shnum;
35
36 if (!section_header_offset
37 || !section_header_num_entries
38 || section_header_offset + section_header_num_entries * sizeof(ElfShdr) > elf_size)
39 throw Exception("The ELF is truncated (section header points after end of file)", ErrorCodes::CANNOT_PARSE_ELF);
40
41 section_headers = reinterpret_cast<const ElfShdr *>(mapped + section_header_offset);
42
43 /// The string table with section names.
44 auto section_names_strtab = findSection([&](const Section & section, size_t idx)
45 {
46 return section.header.sh_type == SHT_STRTAB && header->e_shstrndx == idx;
47 });
48
49 if (!section_names_strtab)
50 throw Exception("The ELF doesn't have string table with section names", ErrorCodes::CANNOT_PARSE_ELF);
51
52 ElfOff section_names_offset = section_names_strtab->header.sh_offset;
53 if (section_names_offset >= elf_size)
54 throw Exception("The ELF is truncated (section names string table points after end of file)", ErrorCodes::CANNOT_PARSE_ELF);
55
56 section_names = reinterpret_cast<const char *>(mapped + section_names_offset);
57}
58
59
60Elf::Section::Section(const ElfShdr & header_, const Elf & elf_)
61 : header(header_), elf(elf_)
62{
63}
64
65
66bool Elf::iterateSections(std::function<bool(const Section & section, size_t idx)> && pred) const
67{
68 for (size_t idx = 0; idx < header->e_shnum; ++idx)
69 {
70 Section section(section_headers[idx], *this);
71
72 /// Sections spans after end of file.
73 if (section.header.sh_offset + section.header.sh_size > elf_size)
74 continue;
75
76 if (pred(section, idx))
77 return true;
78 }
79 return false;
80}
81
82
83std::optional<Elf::Section> Elf::findSection(std::function<bool(const Section & section, size_t idx)> && pred) const
84{
85 std::optional<Elf::Section> result;
86
87 iterateSections([&](const Section & section, size_t idx)
88 {
89 if (pred(section, idx))
90 {
91 result.emplace(section);
92 return true;
93 }
94 return false;
95 });
96
97 return result;
98}
99
100
101std::optional<Elf::Section> Elf::findSectionByName(const char * name) const
102{
103 return findSection([&](const Section & section, size_t) { return 0 == strcmp(name, section.name()); });
104}
105
106
107const char * Elf::Section::name() const
108{
109 if (!elf.section_names)
110 throw Exception("Section names are not initialized", ErrorCodes::CANNOT_PARSE_ELF);
111
112 /// TODO buffer overflow is possible, we may need to check strlen.
113 return elf.section_names + header.sh_name;
114}
115
116
117const char * Elf::Section::begin() const
118{
119 return elf.mapped + header.sh_offset;
120}
121
122const char * Elf::Section::end() const
123{
124 return begin() + size();
125}
126
127size_t Elf::Section::size() const
128{
129 return header.sh_size;
130}
131
132}
133
134#endif
135