* elfcpp_file.h (class Elf_file): Add large_shndx_offset_ field.
[external/binutils.git] / elfcpp / elfcpp_file.h
1 // elfcpp_file.h -- file access for elfcpp   -*- C++ -*-
2
3 // Copyright 2006, 2007, Free Software Foundation, Inc.
4 // Written by Ian Lance Taylor <iant@google.com>.
5
6 // This file is part of elfcpp.
7    
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public License
10 // as published by the Free Software Foundation; either version 2, or
11 // (at your option) any later version.
12
13 // In addition to the permissions in the GNU Library General Public
14 // License, the Free Software Foundation gives you unlimited
15 // permission to link the compiled version of this file into
16 // combinations with other programs, and to distribute those
17 // combinations without any restriction coming from the use of this
18 // file.  (The Library Public License restrictions do apply in other
19 // respects; for example, they cover modification of the file, and
20 /// distribution when not linked into a combined executable.)
21
22 // This program is distributed in the hope that it will be useful, but
23 // WITHOUT ANY WARRANTY; without even the implied warranty of
24 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25 // Library General Public License for more details.
26
27 // You should have received a copy of the GNU Library General Public
28 // License along with this program; if not, write to the Free Software
29 // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
30 // 02110-1301, USA.
31
32 // This header file defines the class Elf_file which can be used to
33 // read useful data from an ELF file.  The functions here are all
34 // templates which take a file interface object as a parameter.  This
35 // type must have a subtype View.  This type must support two methods:
36 //     View view(off_t file_offset, off_t data_size)
37 // returns a View for the specified part of the file.
38 //     void error(const char* printf_format, ...)
39 // prints an error message and does not return.  The subtype View must
40 // support a method
41 //     const unsigned char* data()
42 // which returns a pointer to a buffer containing the requested data.
43 // This general interface is used to read data from the file.  Objects
44 // of type View will never survive longer than the elfcpp function.
45
46 // Some of these functions must return a reference to part of the
47 // file.  To use these, the file interface must support a subtype
48 // Location:
49 //    Location(off_t file_offset, off_t data_size)
50 // To use this in conjunction with the accessors types Shdr, etc., the
51 // file interface should support an overload of view:
52 //    View view(Location)
53 // This permits writing
54 //    elfcpp::Shdr shdr(file, ef.section_header(n));
55
56 #ifndef ELFPCP_FILE_H
57 #define ELFCPP_FILE_H
58
59 #include <string>
60 #include <cstring>
61
62 namespace elfcpp
63 {
64
65 // This object is used to read an ELF file.
66 //   SIZE: The size of file, 32 or 64.
67 //   BIG_ENDIAN: Whether the file is in big-endian format.
68 //   FILE: A file reading type as described above.
69
70 template<int size, bool big_endian, typename File>
71 class Elf_file
72 {
73  private:
74   typedef Elf_file<size, big_endian, File> This;
75
76  public:
77   static const int ehdr_size = Elf_sizes<size>::ehdr_size;
78   static const int phdr_size = Elf_sizes<size>::phdr_size;
79   static const int shdr_size = Elf_sizes<size>::shdr_size;
80   static const int sym_size = Elf_sizes<size>::sym_size;
81   static const int rel_size = Elf_sizes<size>::rel_size;
82   static const int rela_size = Elf_sizes<size>::rela_size;
83
84   typedef Ehdr<size, big_endian> Ef_ehdr;
85   typedef Phdr<size, big_endian> Ef_phdr;
86   typedef Shdr<size, big_endian> Ef_shdr;
87   typedef Sym<size, big_endian> Ef_sym;
88
89   // Construct an Elf_file given an ELF file header.
90   Elf_file(File* file, const Ef_ehdr& ehdr)
91   { this->construct(file, ehdr); }
92
93   // Construct an ELF file.
94   inline
95   Elf_file(File* file);
96
97   // Return the file offset to the section headers.
98   off_t
99   shoff() const
100   { return this->shoff_; }
101
102   // Return the number of sections.
103   unsigned int
104   shnum()
105   {
106     this->initialize_shnum();
107     return this->shnum_;
108   }
109
110   // Return the section index of the section name string table.
111   unsigned int
112   shstrndx()
113   {
114     this->initialize_shnum();
115     return this->shstrndx_;
116   }
117
118   // Return the value to subtract from section indexes >=
119   // SHN_LORESERVE.  See the comment in initialize_shnum.
120   int
121   large_shndx_offset()
122   {
123     this->initialize_shnum();
124     return this->large_shndx_offset_;
125   }
126
127   // Return the location of the header of section SHNDX.
128   typename File::Location
129   section_header(unsigned int shndx)
130   {
131     return typename File::Location(this->section_header_offset(shndx),
132                                    shdr_size);
133   }
134
135   // Return the name of section SHNDX.
136   std::string
137   section_name(unsigned int shndx);
138
139   // Return the location of the contents of section SHNDX.
140   typename File::Location
141   section_contents(unsigned int shndx);
142
143   // Return the size of section SHNDX.
144   typename Elf_types<size>::Elf_WXword
145   section_size(unsigned int shndx);
146
147   // Return the flags of section SHNDX.
148   typename Elf_types<size>::Elf_WXword
149   section_flags(unsigned int shndx);
150
151   // Return the address of section SHNDX.
152   typename Elf_types<size>::Elf_Addr
153   section_addr(unsigned int shndx);
154
155   // Return the type of section SHNDX.
156   Elf_Word
157   section_type(unsigned int shndx);
158
159   // Return the link field of section SHNDX.
160   Elf_Word
161   section_link(unsigned int shndx);
162
163   // Return the info field of section SHNDX.
164   Elf_Word
165   section_info(unsigned int shndx);
166
167   // Return the addralign field of section SHNDX.
168   typename Elf_types<size>::Elf_WXword
169   section_addralign(unsigned int shndx);
170
171  private:
172   // Shared constructor code.
173   void
174   construct(File* file, const Ef_ehdr& ehdr);
175
176   // Initialize shnum_ and shstrndx_.
177   void
178   initialize_shnum();
179
180   // Return the file offset of the header of section SHNDX.
181   off_t
182   section_header_offset(unsigned int shndx);
183
184   // The file we are reading.
185   File* file_;
186   // The file offset to the section headers.
187   off_t shoff_;
188   // The number of sections.
189   unsigned int shnum_;
190   // The section index of the section name string table.
191   unsigned int shstrndx_;
192   // Offset to add to sections larger than SHN_LORESERVE.
193   int large_shndx_offset_;
194 };
195
196 // Template function definitions.
197
198 // Construct an Elf_file given an ELF file header.
199
200 template<int size, bool big_endian, typename File>
201 void
202 Elf_file<size, big_endian, File>::construct(File* file, const Ef_ehdr& ehdr)
203 {
204   this->file_ = file;
205   this->shoff_ = ehdr.get_e_shoff();
206   this->shnum_ = ehdr.get_e_shnum();
207   this->shstrndx_ = ehdr.get_e_shstrndx();
208   this->large_shndx_offset_ = 0;
209   if (ehdr.get_e_ehsize() != This::ehdr_size)
210     file->error(_("bad e_ehsize (%d != %d)"),
211                 ehdr.get_e_ehsize(), This::ehdr_size);
212   if (ehdr.get_e_shentsize() != This::shdr_size)
213     file->error(_("bad e_shentsize (%d != %d)"),
214                 ehdr.get_e_shentsize(), This::shdr_size);
215 }
216
217 // Construct an ELF file.
218
219 template<int size, bool big_endian, typename File>
220 inline
221 Elf_file<size, big_endian, File>::Elf_file(File* file)
222 {
223   typename File::View v(file->view(file_header_offset, This::ehdr_size));
224   this->construct(file, Ef_ehdr(v.data()));
225 }
226
227 // Initialize the shnum_ and shstrndx_ fields, handling overflow.
228
229 template<int size, bool big_endian, typename File>
230 void
231 Elf_file<size, big_endian, File>::initialize_shnum()
232 {
233   if ((this->shnum_ == 0 || this->shstrndx_ == SHN_XINDEX)
234       && this->shoff_ != 0)
235     {
236       typename File::View v(this->file_->view(this->shoff_, This::shdr_size));
237       Ef_shdr shdr(v.data());
238
239       if (this->shnum_ == 0)
240         this->shnum_ = shdr.get_sh_size();
241
242       if (this->shstrndx_ == SHN_XINDEX)
243         {
244           this->shstrndx_ = shdr.get_sh_link();
245
246           // Versions of the GNU binutils between 2.12 and 2.18 did
247           // not handle objects with more than SHN_LORESERVE sections
248           // correctly.  All large section indexes were offset by
249           // 0x100.  Some information can be found here:
250           // http://sourceware.org/bugzilla/show_bug.cgi?id=5900 .
251           // Fortunately these object files are easy to detect, as the
252           // GNU binutils always put the section header string table
253           // near the end of the list of sections.  Thus if the
254           // section header string table index is larger than the
255           // number of sections, then we know we have to subtract
256           // 0x100 to get the real section index.
257           if (this->shstrndx_ >= this->shnum_)
258             {
259               if (this->shstrndx_ >= elfcpp::SHN_LORESERVE + 0x100)
260                 {
261                   this->large_shndx_offset_ = - 0x100;
262                   this->shstrndx_ -= 0x100;
263                 }
264               if (this->shstrndx_ >= this->shnum_)
265                 this->file_->error(_("bad shstrndx: %u >= %u"),
266                                    this->shstrndx_, this->shnum_);
267             }
268         }
269     }
270 }
271
272 // Return the file offset of the section header of section SHNDX.
273
274 template<int size, bool big_endian, typename File>
275 off_t
276 Elf_file<size, big_endian, File>::section_header_offset(unsigned int shndx)
277 {
278   if (shndx >= this->shnum())
279     this->file_->error(_("section_header_offset: bad shndx %u >= %u"),
280                        shndx, this->shnum());
281   return this->shoff_ + This::shdr_size * shndx;
282 }
283
284 // Return the name of section SHNDX.
285
286 template<int size, bool big_endian, typename File>
287 std::string
288 Elf_file<size, big_endian, File>::section_name(unsigned int shndx)
289 {
290   File* const file = this->file_;
291
292   // Get the section name offset.
293   unsigned int sh_name;
294   {
295     typename File::View v(file->view(this->section_header_offset(shndx),
296                                      This::shdr_size));
297     Ef_shdr shdr(v.data());
298     sh_name = shdr.get_sh_name();
299   }
300
301   // Get the file offset for the section name string table data.
302   off_t shstr_off;
303   off_t shstr_size;
304   {
305     const unsigned int shstrndx = this->shstrndx_;
306     typename File::View v(file->view(this->section_header_offset(shstrndx),
307                                      This::shdr_size));
308     Ef_shdr shstr_shdr(v.data());
309     shstr_off = shstr_shdr.get_sh_offset();
310     shstr_size = shstr_shdr.get_sh_size();
311   }
312
313   if (sh_name >= shstr_size)
314     file->error(_("bad section name offset for section %u: %u"),
315                 shndx, sh_name);
316
317   typename File::View v(file->view(shstr_off, shstr_size));
318
319   const unsigned char* datau = v.data();
320   const char* data = reinterpret_cast<const char*>(datau);
321   const void* p = ::memchr(data + sh_name, '\0', shstr_size - sh_name);
322   if (p == NULL)
323     file->error(_("missing null terminator for name of section %u"),
324                 shndx);
325
326   size_t len = static_cast<const char*>(p) - (data + sh_name);
327
328   return std::string(data + sh_name, len);
329 }
330
331 // Return the contents of section SHNDX.
332
333 template<int size, bool big_endian, typename File>
334 typename File::Location
335 Elf_file<size, big_endian, File>::section_contents(unsigned int shndx)
336 {
337   File* const file = this->file_;
338
339   if (shndx >= this->shnum())
340     file->error(_("section_contents: bad shndx %u >= %u"),
341                 shndx, this->shnum());
342
343   typename File::View v(file->view(this->section_header_offset(shndx),
344                                    This::shdr_size));
345   Ef_shdr shdr(v.data());
346   return typename File::Location(shdr.get_sh_offset(), shdr.get_sh_size());
347 }
348
349 // Get the size of section SHNDX.
350
351 template<int size, bool big_endian, typename File>
352 typename Elf_types<size>::Elf_WXword
353 Elf_file<size, big_endian, File>::section_size(unsigned int shndx)
354 {
355   File* const file = this->file_;
356
357   if (shndx >= this->shnum())
358     file->error(_("section_size: bad shndx %u >= %u"),
359                 shndx, this->shnum());
360
361   typename File::View v(file->view(this->section_header_offset(shndx),
362                                    This::shdr_size));
363
364   Ef_shdr shdr(v.data());
365   return shdr.get_sh_size();
366 }
367
368 // Return the section flags of section SHNDX.
369
370 template<int size, bool big_endian, typename File>
371 typename Elf_types<size>::Elf_WXword
372 Elf_file<size, big_endian, File>::section_flags(unsigned int shndx)
373 {
374   File* const file = this->file_;
375
376   if (shndx >= this->shnum())
377     file->error(_("section_flags: bad shndx %u >= %u"),
378                 shndx, this->shnum());
379
380   typename File::View v(file->view(this->section_header_offset(shndx),
381                                    This::shdr_size));
382
383   Ef_shdr shdr(v.data());
384   return shdr.get_sh_flags();
385 }
386
387 // Return the address of section SHNDX.
388
389 template<int size, bool big_endian, typename File>
390 typename Elf_types<size>::Elf_Addr
391 Elf_file<size, big_endian, File>::section_addr(unsigned int shndx)
392 {
393   File* const file = this->file_;
394
395   if (shndx >= this->shnum())
396     file->error(_("section_flags: bad shndx %u >= %u"),
397                 shndx, this->shnum());
398
399   typename File::View v(file->view(this->section_header_offset(shndx),
400                                    This::shdr_size));
401
402   Ef_shdr shdr(v.data());
403   return shdr.get_sh_addr();
404 }
405
406 // Return the type of section SHNDX.
407
408 template<int size, bool big_endian, typename File>
409 Elf_Word
410 Elf_file<size, big_endian, File>::section_type(unsigned int shndx)
411 {
412   File* const file = this->file_;
413
414   if (shndx >= this->shnum())
415     file->error(_("section_type: bad shndx %u >= %u"),
416                 shndx, this->shnum());
417
418   typename File::View v(file->view(this->section_header_offset(shndx),
419                                    This::shdr_size));
420
421   Ef_shdr shdr(v.data());
422   return shdr.get_sh_type();
423 }
424
425 // Return the sh_link field of section SHNDX.
426
427 template<int size, bool big_endian, typename File>
428 Elf_Word
429 Elf_file<size, big_endian, File>::section_link(unsigned int shndx)
430 {
431   File* const file = this->file_;
432
433   if (shndx >= this->shnum())
434     file->error(_("section_link: bad shndx %u >= %u"),
435                 shndx, this->shnum());
436
437   typename File::View v(file->view(this->section_header_offset(shndx),
438                                    This::shdr_size));
439
440   Ef_shdr shdr(v.data());
441   return shdr.get_sh_link();
442 }
443
444 // Return the sh_info field of section SHNDX.
445
446 template<int size, bool big_endian, typename File>
447 Elf_Word
448 Elf_file<size, big_endian, File>::section_info(unsigned int shndx)
449 {
450   File* const file = this->file_;
451
452   if (shndx >= this->shnum())
453     file->error(_("section_info: bad shndx %u >= %u"),
454                 shndx, this->shnum());
455
456   typename File::View v(file->view(this->section_header_offset(shndx),
457                                    This::shdr_size));
458
459   Ef_shdr shdr(v.data());
460   return shdr.get_sh_info();
461 }
462
463 // Return the sh_addralign field of section SHNDX.
464
465 template<int size, bool big_endian, typename File>
466 typename Elf_types<size>::Elf_WXword
467 Elf_file<size, big_endian, File>::section_addralign(unsigned int shndx)
468 {
469   File* const file = this->file_;
470
471   if (shndx >= this->shnum())
472     file->error(_("section_addralign: bad shndx %u >= %u"),
473                 shndx, this->shnum());
474
475   typename File::View v(file->view(this->section_header_offset(shndx),
476                                    This::shdr_size));
477
478   Ef_shdr shdr(v.data());
479   return shdr.get_sh_addralign();
480 }
481
482 } // End namespace elfcpp.
483
484 #endif // !defined(ELFCPP_FILE_H)