]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright 2014 Renato Tegon Forti, Antony Polukhin. |
2 | // Copyright 2015 Antony Polukhin. | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0. | |
5 | // (See accompanying file LICENSE_1_0.txt | |
6 | // or copy at http://www.boost.org/LICENSE_1_0.txt) | |
7 | ||
8 | #ifndef BOOST_DLL_DETAIL_POSIX_ELF_INFO_HPP | |
9 | #define BOOST_DLL_DETAIL_POSIX_ELF_INFO_HPP | |
10 | ||
11 | #include <boost/config.hpp> | |
12 | ||
13 | #ifdef BOOST_HAS_PRAGMA_ONCE | |
14 | # pragma once | |
15 | #endif | |
16 | ||
17 | #include <cstring> | |
18 | #include <boost/filesystem/fstream.hpp> | |
19 | #include <boost/dll/detail/x_info_interface.hpp> | |
20 | ||
21 | namespace boost { namespace dll { namespace detail { | |
22 | ||
23 | template <class AddressOffsetT> | |
24 | struct Elf_Ehdr_template { | |
25 | unsigned char e_ident[16]; /* Magic number and other info */ | |
26 | boost::uint16_t e_type; /* Object file type */ | |
27 | boost::uint16_t e_machine; /* Architecture */ | |
28 | boost::uint32_t e_version; /* Object file version */ | |
29 | AddressOffsetT e_entry; /* Entry point virtual address */ | |
30 | AddressOffsetT e_phoff; /* Program header table file offset */ | |
31 | AddressOffsetT e_shoff; /* Section header table file offset */ | |
32 | boost::uint32_t e_flags; /* Processor-specific flags */ | |
33 | boost::uint16_t e_ehsize; /* ELF header size in bytes */ | |
34 | boost::uint16_t e_phentsize; /* Program header table entry size */ | |
35 | boost::uint16_t e_phnum; /* Program header table entry count */ | |
36 | boost::uint16_t e_shentsize; /* Section header table entry size */ | |
37 | boost::uint16_t e_shnum; /* Section header table entry count */ | |
38 | boost::uint16_t e_shstrndx; /* Section header string table index */ | |
39 | }; | |
40 | ||
41 | typedef Elf_Ehdr_template<boost::uint32_t> Elf32_Ehdr_; | |
42 | typedef Elf_Ehdr_template<boost::uint64_t> Elf64_Ehdr_; | |
43 | ||
44 | template <class AddressOffsetT> | |
45 | struct Elf_Shdr_template { | |
46 | boost::uint32_t sh_name; /* Section name (string tbl index) */ | |
47 | boost::uint32_t sh_type; /* Section type */ | |
48 | AddressOffsetT sh_flags; /* Section flags */ | |
49 | AddressOffsetT sh_addr; /* Section virtual addr at execution */ | |
50 | AddressOffsetT sh_offset; /* Section file offset */ | |
51 | AddressOffsetT sh_size; /* Section size in bytes */ | |
52 | boost::uint32_t sh_link; /* Link to another section */ | |
53 | boost::uint32_t sh_info; /* Additional section information */ | |
54 | AddressOffsetT sh_addralign; /* Section alignment */ | |
55 | AddressOffsetT sh_entsize; /* Entry size if section holds table */ | |
56 | }; | |
57 | ||
58 | typedef Elf_Shdr_template<boost::uint32_t> Elf32_Shdr_; | |
59 | typedef Elf_Shdr_template<boost::uint64_t> Elf64_Shdr_; | |
60 | ||
61 | template <class AddressOffsetT> | |
62 | struct Elf_Sym_template; | |
63 | ||
64 | template <> | |
65 | struct Elf_Sym_template<boost::uint32_t> { | |
66 | typedef boost::uint32_t AddressOffsetT; | |
67 | ||
68 | boost::uint32_t st_name; /* Symbol name (string tbl index) */ | |
69 | AddressOffsetT st_value; /* Symbol value */ | |
70 | AddressOffsetT st_size; /* Symbol size */ | |
71 | unsigned char st_info; /* Symbol type and binding */ | |
72 | unsigned char st_other; /* Symbol visibility */ | |
73 | boost::uint16_t st_shndx; /* Section index */ | |
74 | }; | |
75 | ||
76 | template <> | |
77 | struct Elf_Sym_template<boost::uint64_t> { | |
78 | typedef boost::uint64_t AddressOffsetT; | |
79 | ||
80 | boost::uint32_t st_name; /* Symbol name (string tbl index) */ | |
81 | unsigned char st_info; /* Symbol type and binding */ | |
82 | unsigned char st_other; /* Symbol visibility */ | |
83 | boost::uint16_t st_shndx; /* Section index */ | |
84 | AddressOffsetT st_value; /* Symbol value */ | |
85 | AddressOffsetT st_size; /* Symbol size */ | |
86 | }; | |
87 | ||
88 | ||
89 | typedef Elf_Sym_template<boost::uint32_t> Elf32_Sym_; | |
90 | typedef Elf_Sym_template<boost::uint64_t> Elf64_Sym_; | |
91 | ||
92 | template <class AddressOffsetT> | |
93 | class elf_info: public x_info_interface { | |
94 | boost::filesystem::ifstream& f_; | |
95 | ||
96 | typedef boost::dll::detail::Elf_Ehdr_template<AddressOffsetT> header_t; | |
97 | typedef boost::dll::detail::Elf_Shdr_template<AddressOffsetT> section_t; | |
98 | typedef boost::dll::detail::Elf_Sym_template<AddressOffsetT> symbol_t; | |
99 | ||
100 | BOOST_STATIC_CONSTANT(boost::uint32_t, SHT_SYMTAB_ = 2); | |
101 | BOOST_STATIC_CONSTANT(boost::uint32_t, SHT_STRTAB_ = 3); | |
102 | ||
103 | BOOST_STATIC_CONSTANT(unsigned char, STB_LOCAL_ = 0); /* Local symbol */ | |
104 | BOOST_STATIC_CONSTANT(unsigned char, STB_GLOBAL_ = 1); /* Global symbol */ | |
105 | BOOST_STATIC_CONSTANT(unsigned char, STB_WEAK_ = 2); /* Weak symbol */ | |
106 | ||
107 | /* Symbol visibility specification encoded in the st_other field. */ | |
108 | BOOST_STATIC_CONSTANT(unsigned char, STV_DEFAULT_ = 0); /* Default symbol visibility rules */ | |
109 | BOOST_STATIC_CONSTANT(unsigned char, STV_INTERNAL_ = 1); /* Processor specific hidden class */ | |
110 | BOOST_STATIC_CONSTANT(unsigned char, STV_HIDDEN_ = 2); /* Sym unavailable in other modules */ | |
111 | BOOST_STATIC_CONSTANT(unsigned char, STV_PROTECTED_ = 3); /* Not preemptible, not exported */ | |
112 | ||
113 | public: | |
114 | static bool parsing_supported(boost::filesystem::ifstream& f) { | |
115 | const unsigned char magic_bytes[5] = { | |
116 | 0x7f, 'E', 'L', 'F', sizeof(boost::uint32_t) == sizeof(AddressOffsetT) ? 1 : 2 | |
117 | }; | |
118 | ||
119 | unsigned char ch; | |
120 | f.seekg(0); | |
121 | for (std::size_t i = 0; i < sizeof(magic_bytes); ++i) { | |
122 | f >> ch; | |
123 | if (ch != magic_bytes[i]) { | |
124 | return false; | |
125 | } | |
126 | } | |
127 | ||
128 | return true; | |
129 | } | |
130 | ||
131 | explicit elf_info(boost::filesystem::ifstream& f) BOOST_NOEXCEPT | |
132 | : f_(f) | |
133 | {} | |
134 | ||
135 | std::vector<std::string> sections() { | |
136 | std::vector<std::string> ret; | |
137 | std::vector<char> names; | |
138 | sections_names_raw(names); | |
139 | ||
140 | const char* name_begin = &names[0]; | |
141 | const char* const name_end = name_begin + names.size(); | |
142 | ret.reserve(header().e_shnum); | |
143 | do { | |
144 | ret.push_back(name_begin); | |
145 | name_begin += ret.back().size() + 1; | |
146 | } while (name_begin != name_end); | |
147 | ||
148 | return ret; | |
149 | } | |
150 | ||
151 | private: | |
152 | template <class T> | |
153 | inline void read_raw(T& value, std::size_t size = sizeof(T)) const { | |
154 | f_.read(reinterpret_cast<char*>(&value), size); | |
155 | } | |
156 | ||
157 | inline header_t header() { | |
158 | header_t elf; | |
159 | ||
160 | f_.seekg(0); | |
161 | read_raw(elf); | |
162 | ||
163 | return elf; | |
164 | } | |
165 | ||
166 | void sections_names_raw(std::vector<char>& sections) { | |
167 | const header_t elf = header(); | |
168 | ||
169 | section_t section_names_section; | |
170 | f_.seekg(elf.e_shoff + elf.e_shstrndx * sizeof(section_t)); | |
171 | read_raw(section_names_section); | |
172 | ||
173 | sections.resize(static_cast<std::size_t>(section_names_section.sh_size)); | |
174 | f_.seekg(section_names_section.sh_offset); | |
175 | read_raw(sections[0], static_cast<std::size_t>(section_names_section.sh_size)); | |
176 | } | |
177 | ||
178 | void symbols_text(std::vector<symbol_t>& symbols, std::vector<char>& text) { | |
179 | const header_t elf = header(); | |
180 | f_.seekg(elf.e_shoff); | |
181 | ||
182 | for (std::size_t i = 0; i < elf.e_shnum; ++i) { | |
183 | section_t section; | |
184 | read_raw(section); | |
185 | ||
186 | if (section.sh_type == SHT_SYMTAB_) { | |
187 | symbols.resize(static_cast<std::size_t>(section.sh_size / sizeof(symbol_t))); | |
188 | ||
189 | const boost::filesystem::ifstream::pos_type pos = f_.tellg(); | |
190 | f_.seekg(section.sh_offset); | |
191 | read_raw(symbols[0], static_cast<std::size_t>(section.sh_size - (section.sh_size % sizeof(symbol_t))) ); | |
192 | f_.seekg(pos); | |
193 | } else if (section.sh_type == SHT_STRTAB_) { | |
194 | text.resize(static_cast<std::size_t>(section.sh_size)); | |
195 | ||
196 | const boost::filesystem::ifstream::pos_type pos = f_.tellg(); | |
197 | f_.seekg(section.sh_offset); | |
198 | read_raw(text[0], static_cast<std::size_t>(section.sh_size)); | |
199 | f_.seekg(pos); | |
200 | } | |
201 | } | |
202 | } | |
203 | ||
204 | static bool is_visible(const symbol_t& sym) BOOST_NOEXCEPT { | |
205 | // `(sym.st_info >> 4) != STB_LOCAL_ && !!sym.st_size` check also workarounds the | |
206 | // GCC's issue https://sourceware.org/bugzilla/show_bug.cgi?id=13621 | |
207 | return (sym.st_other & 0x03) == STV_DEFAULT_ && (sym.st_info >> 4) != STB_LOCAL_ && !!sym.st_size; | |
208 | } | |
209 | ||
210 | public: | |
211 | std::vector<std::string> symbols() { | |
212 | std::vector<std::string> ret; | |
213 | ||
214 | std::vector<symbol_t> symbols; | |
215 | std::vector<char> text; | |
216 | symbols_text(symbols, text); | |
217 | ||
218 | ret.reserve(symbols.size()); | |
219 | for (std::size_t i = 0; i < symbols.size(); ++i) { | |
220 | if (is_visible(symbols[i])) { | |
221 | ret.push_back(&text[0] + symbols[i].st_name); | |
222 | if (ret.back().empty()) { | |
223 | ret.pop_back(); // Do not show empty names | |
224 | } | |
225 | } | |
226 | } | |
227 | ||
228 | return ret; | |
229 | } | |
230 | ||
231 | std::vector<std::string> symbols(const char* section_name) { | |
232 | std::vector<std::string> ret; | |
233 | ||
234 | std::size_t index = 0; | |
235 | std::size_t ptrs_in_section_count = 0; | |
236 | { | |
237 | std::vector<char> names; | |
238 | sections_names_raw(names); | |
239 | ||
240 | const header_t elf = header(); | |
241 | ||
242 | for (; index < elf.e_shnum; ++index) { | |
243 | section_t section; | |
244 | f_.seekg(elf.e_shoff + index * sizeof(section_t)); | |
245 | read_raw(section); | |
246 | ||
247 | if (!std::strcmp(&names[0] + section.sh_name, section_name)) { | |
248 | if (!section.sh_entsize) { | |
249 | section.sh_entsize = 1; | |
250 | } | |
251 | ptrs_in_section_count = static_cast<std::size_t>(section.sh_size / section.sh_entsize); | |
252 | break; | |
253 | } | |
254 | } | |
255 | } | |
256 | ||
257 | std::vector<symbol_t> symbols; | |
258 | std::vector<char> text; | |
259 | symbols_text(symbols, text); | |
260 | ||
261 | if (ptrs_in_section_count < symbols.size()) { | |
262 | ret.reserve(ptrs_in_section_count); | |
263 | } else { | |
264 | ret.reserve(symbols.size()); | |
265 | } | |
266 | ||
267 | for (std::size_t i = 0; i < symbols.size(); ++i) { | |
268 | if (symbols[i].st_shndx == index && is_visible(symbols[i])) { | |
269 | ret.push_back(&text[0] + symbols[i].st_name); | |
270 | if (ret.back().empty()) { | |
271 | ret.pop_back(); // Do not show empty names | |
272 | } | |
273 | } | |
274 | } | |
275 | ||
276 | return ret; | |
277 | } | |
278 | }; | |
279 | ||
280 | typedef elf_info<boost::uint32_t> elf_info32; | |
281 | typedef elf_info<boost::uint64_t> elf_info64; | |
282 | ||
283 | }}} // namespace boost::dll::detail | |
284 | ||
285 | #endif // BOOST_DLL_DETAIL_POSIX_ELF_INFO_HPP |