COFFI
1.2
               
coffi_section.hpp
Go to the documentation of this file.
1 /*
2 Copyright (C) 2014-2014 by Serge Lamikhov-Center
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22 
23 /*! @file coffi_section.hpp
24  * @brief COFFI library classes for the COFF sections.
25  *
26  * Do not include this file directly. This file is included by coffi.hpp.
27  */
28 
29 #ifndef COFFI_SECTION_HPP
30 #define COFFI_SECTION_HPP
31 
32 #include <string>
33 #include <iostream>
34 
35 #include <coffi/coffi_utils.hpp>
37 
38 #if defined(__has_include) && __has_include(<gsl/narrow>)
39 #include <gsl/narrow>
40 using gsl::narrow_cast;
41 #else
42 #ifndef narrow_cast
43 #define narrow_cast static_cast
44 #endif
45 #endif
46 
47 namespace COFFI {
48 
49 //------------------------------------------------------------------------------
50 //! Interface class for accessing a COFF section, for all the COFF architectures.
51 class section
52 {
53  public:
54  //------------------------------------------------------------------------------
55  virtual ~section(){};
56 
57  //! @accessors{section}
58  COFFI_GET_SET_ACCESS_DECL(uint32_t, index);
59  COFFI_GET_SET_ACCESS_DECL(uint32_t, virtual_size);
60  COFFI_GET_SET_ACCESS_DECL(uint32_t, physical_address);
61  COFFI_GET_SET_ACCESS_DECL(uint32_t, virtual_address);
62  COFFI_GET_SET_ACCESS_DECL(uint32_t, data_size);
63  COFFI_GET_SET_ACCESS_DECL(uint32_t, data_offset);
64  COFFI_GET_SET_ACCESS_DECL(uint32_t, reloc_offset);
65  COFFI_GET_SET_ACCESS_DECL(uint32_t, line_num_offset);
66  COFFI_GET_SET_ACCESS_DECL(uint32_t, reloc_count);
67  COFFI_GET_SET_ACCESS_DECL(uint32_t, line_num_count);
68  COFFI_GET_SET_ACCESS_DECL(uint32_t, flags);
69  COFFI_GET_SET_ACCESS_DECL(uint16_t, page_number);
70  COFFI_GET_SET_ACCESS_DECL(uint32_t, alignment);
71 
72  COFFI_GET_SIZEOF_DECL();
73  //! @endaccessors
74 
75  virtual const std::string& get_name() const = 0;
76  virtual void set_name(const std::string& name) = 0;
77  virtual const char* get_data() const = 0;
78  virtual void set_data(const char* data, uint32_t size) = 0;
79  virtual void set_data(const std::string& data) = 0;
80  virtual void append_data(const char* data, uint32_t size) = 0;
81  virtual void append_data(const std::string& data) = 0;
82 
83  //------------------------------------------------------------------------------
84  virtual bool load(std::istream& stream, std::streampos header_offset) = 0;
85  virtual void save_header(std::ostream& stream) = 0;
86  virtual void save_data(std::ostream& stream) = 0;
87  virtual void save_relocations(std::ostream& stream) = 0;
88  virtual uint32_t get_relocations_filesize() = 0;
89  virtual void save_line_numbers(std::ostream& stream) = 0;
90  virtual uint32_t get_line_numbers_filesize() = 0;
91 
92  //------------------------------------------------------------------------------
93  virtual const std::vector<relocation>& get_relocations() const = 0;
94  virtual void add_relocation_entry(const rel_entry_generic* entry) = 0;
95 };
96 
97 /*! @brief Template class for accessing a COFF section, depends on the underlying section header format.
98  *
99  * The template parameter **class T** is one of:
100  * - section_header: @copybrief section_header
101  * - section_header_ti: @copybrief section_header_ti
102  */
103 template <class T> class section_impl_tmpl : public section
104 {
105  public:
106  //------------------------------------------------------------------------------
108  symbol_provider* sym,
109  architecture_provider* arch)
110  {
111  std::fill_n(reinterpret_cast<char*>(&header), sizeof(header), '\0');
112  data_ = 0;
113  data_reserved_ = 0;
114  stn_ = stn;
115  sym_ = sym;
116  arch_ = arch;
117  }
118 
119  //------------------------------------------------------------------------------
120  //! Discards the copy constructor
122 
123  //------------------------------------------------------------------------------
124  ~section_impl_tmpl() { clean(); }
125 
126  //------------------------------------------------------------------------------
127  // Section info functions
128 
129  //! @accessors{section_impl_tmpl}
130  COFFI_GET_SET_ACCESS(uint32_t, virtual_address);
131  COFFI_GET_SET_ACCESS(uint32_t, data_offset);
132  COFFI_GET_SET_ACCESS(uint32_t, reloc_offset);
133  COFFI_GET_SET_ACCESS(uint32_t, reloc_count);
134  COFFI_GET_SET_ACCESS(uint32_t, line_num_count);
135  COFFI_GET_SET_ACCESS(uint32_t, flags);
136 
137  COFFI_GET_SIZEOF();
138  //! @endaccessors
139 
140  //------------------------------------------------------------------------------
141  uint32_t get_index() const { return index; }
142 
143  //------------------------------------------------------------------------------
144  void set_index(uint32_t value) { index = value; }
145 
146  //------------------------------------------------------------------------------
147  const std::string& get_name() const { return name; }
148 
149  //------------------------------------------------------------------------------
150  void set_name(const std::string& value)
151  {
152  stn_->name_to_section_string(value, header.name);
153  }
154 
155  //------------------------------------------------------------------------------
156  const char* get_data() const { return data_; }
157 
158  //------------------------------------------------------------------------------
159  void set_data(const char* data, uint32_t size)
160  {
161  clean();
162  if (!data) {
163  data_reserved_ = 0;
164  }
165  else {
166  data_ = new char[size];
167  if (data_) {
168  data_reserved_ = size;
169  std::copy(data, data + size, data_);
170  }
171  else {
172  data_reserved_ = 0;
173  }
174  }
175  set_data_size(data_reserved_);
176  }
177 
178  //------------------------------------------------------------------------------
179  void set_data(const std::string& data)
180  {
181  set_data(data.c_str(), (uint32_t)data.size());
182  }
183 
184  //------------------------------------------------------------------------------
185  virtual void append_data(const char* data, uint32_t size)
186  {
187  if (!data_) {
188  set_data(data, size);
189  }
190  if (get_data_size() + size <= data_reserved_) {
191  std::copy(data, data + size, data_ + get_data_size());
192  }
193  else {
194  uint32_t new_data_size = 2 * (data_reserved_ + size);
195  char* new_data = new char[new_data_size];
196  if (!new_data) {
197  size = 0;
198  }
199  else {
200  data_reserved_ = new_data_size;
201  std::copy(data_, data_ + get_data_size(), new_data);
202  std::copy(data, data + size, new_data + get_data_size());
203  delete[] data_;
204  data_ = new_data;
205  }
206  }
207  set_data_size(get_data_size() + size);
208  }
209 
210  //------------------------------------------------------------------------------
211  virtual void append_data(const std::string& data)
212  {
213  append_data(data.c_str(), (uint32_t)data.size());
214  }
215 
216  //------------------------------------------------------------------------------
217  virtual const std::vector<relocation>& get_relocations() const
218  {
219  return relocations;
220  }
221 
222  //------------------------------------------------------------------------------
223  virtual void add_relocation_entry(const rel_entry_generic* entry)
224  {
225  relocation r{stn_, sym_, arch_};
226  r.set_type(entry->type);
227  r.set_virtual_address(entry->virtual_address);
228  r.set_symbol(entry->symbol_table_index);
229  relocations.push_back(r);
230  set_reloc_count(narrow_cast<uint32_t>(relocations.size()));
231  }
232 
233  //------------------------------------------------------------------------------
234  bool load(std::istream& stream, std::streampos header_offset)
235  {
236  std::fill_n(reinterpret_cast<char*>(&header), sizeof(header), '\0');
237  stream.seekg(header_offset);
238  stream.read(reinterpret_cast<char*>(&header), sizeof(header));
239 
240  name = stn_->section_string_to_name(header.name);
241 
242  // Read the raw section data
243  bool dont = (arch_->get_architecture() == COFFI_ARCHITECTURE_CEVA) &&
244  ((get_flags() & CEVA_UNINITIALIZED_DATA) ==
245  CEVA_UNINITIALIZED_DATA);
246  if (!dont) {
247  data_reserved_ = get_data_size();
248  if ((get_data_offset() != 0) && (data_reserved_ != 0)) {
249  data_ = new char[data_reserved_];
250  if (!data_) {
251  return false;
252  }
253  stream.seekg(get_data_offset());
254  stream.read(data_, data_reserved_);
255  }
256  }
257 
258  // Read relocations
259  if (get_reloc_count() != 0) {
260  stream.seekg(get_reloc_offset());
261  for (uint32_t i = 0; i < get_reloc_count(); ++i) {
262  relocation rel{stn_, sym_, arch_};
263  rel.load(stream);
264  relocations.push_back(rel);
265  }
266  }
267 
268  // Read line numbers
269  if (get_line_num_count() != 0) {
270  stream.seekg(get_line_num_offset());
271  for (uint32_t i = 0; i < get_line_num_count(); ++i) {
272  line_number lnum;
273  stream.read(reinterpret_cast<char*>(&lnum),
274  sizeof(line_number));
275  line_numbers.push_back(lnum);
276  }
277  }
278  return true;
279  }
280 
281  //------------------------------------------------------------------------------
282  virtual void save_header(std::ostream& stream)
283  {
284  stream.write(reinterpret_cast<char*>(&header), sizeof(header));
285  }
286 
287  //------------------------------------------------------------------------------
288  virtual void save_data(std::ostream& stream)
289  {
290  if (!data_ || get_data_offset() == 0) {
291  return;
292  }
293  stream.write(data_, get_data_size());
294  }
295 
296  //------------------------------------------------------------------------------
297  virtual void save_relocations(std::ostream& stream)
298  {
299  for (auto entry : relocations) {
300  entry.save(stream);
301  }
302  }
303 
304  //------------------------------------------------------------------------------
305  virtual uint32_t get_relocations_filesize()
306  {
307  relocation rel{stn_, sym_, arch_};
308  return rel.get_sizeof() * narrow_cast<uint32_t>(relocations.size());
309  }
310 
311  //------------------------------------------------------------------------------
312  virtual void save_line_numbers(std::ostream& stream)
313  {
314  for (auto lnum : line_numbers) {
315  stream.write(reinterpret_cast<char*>(&lnum), sizeof(line_number));
316  }
317  }
318 
319  //------------------------------------------------------------------------------
320  virtual uint32_t get_line_numbers_filesize()
321  {
322  return sizeof(line_number) * narrow_cast<uint32_t>(line_numbers.size());
323  }
324 
325  //------------------------------------------------------------------------------
326  protected:
327  //------------------------------------------------------------------------------
328  void clean()
329  {
330  if (data_) {
331  delete[] data_;
332  data_ = 0;
333  data_reserved_ = 0;
334  }
335  }
336 
337  //------------------------------------------------------------------------------
338  uint32_t get_bit_number(uint32_t v)
339  {
340  v--;
341  v |= v >> 1;
342  v |= v >> 2;
343  v |= v >> 4;
344  v |= v >> 8;
345  v |= v >> 16;
346  v++;
347  for (uint32_t i = 0; i < 32; i++) {
348  if (v & 1)
349  return i;
350  v = v >> 1;
351  }
352  return 32;
353  }
354 
355  //------------------------------------------------------------------------------
356  T header;
357  uint32_t index{};
358  std::string name;
359  char* data_;
360  uint32_t data_reserved_;
361  string_to_name_provider* stn_;
362  symbol_provider* sym_;
363  architecture_provider* arch_;
364 
365  std::vector<relocation> relocations;
366  std::vector<line_number> line_numbers;
367 };
368 
369 //------------------------------------------------------------------------------
370 //! Class for accessing a COFF section, for the PE format.
371 class section_impl : public section_impl_tmpl<section_header>
372 {
373  public:
374  //------------------------------------------------------------------------------
376  symbol_provider* sym,
377  architecture_provider* arch)
378  : section_impl_tmpl{stn, sym, arch}
379  {
380  }
381 
382  //! @accessors{section_impl}
383  COFFI_GET_SET_ACCESS(uint32_t, virtual_size);
384  COFFI_GET_SET_ACCESS(uint32_t, data_size);
385  COFFI_GET_SET_ACCESS_NONE(uint32_t, physical_address);
386  COFFI_GET_SET_ACCESS(uint32_t, line_num_offset);
387  COFFI_GET_SET_ACCESS_NONE(uint16_t, page_number);
388  //! @endaccessors
389 
390  //------------------------------------------------------------------------------
391  uint32_t get_alignment() const
392  {
393  return 1 << (((get_flags() >> 20) & 0xF) - 1);
394  }
395 
396  //------------------------------------------------------------------------------
397  void set_alignment(uint32_t value)
398  {
399  set_flags((get_flags() & ~0xF00000) |
400  ((get_bit_number(value) & 0xF) << 20));
401  }
402 };
403 
404 //------------------------------------------------------------------------------
405 //! Class for accessing a COFF section, for the Texas Instruments format.
406 class section_impl_ti : public section_impl_tmpl<section_header_ti>
407 {
408  public:
409  //------------------------------------------------------------------------------
411  symbol_provider* sym,
412  architecture_provider* arch)
413  : section_impl_tmpl{stn, sym, arch}
414  {
415  }
416 
417  //! @accessors{section_impl_ti}
418  COFFI_GET_SET_ACCESS_NONE(uint32_t, virtual_size);
419  COFFI_GET_SET_ACCESS(uint32_t, physical_address);
420  COFFI_GET_SET_ACCESS_NONE(uint32_t, line_num_offset);
421  COFFI_GET_SET_ACCESS(uint16_t, page_number);
422  //! @endaccessors
423 
424  //------------------------------------------------------------------------------
425  uint32_t get_data_size() const
426  {
427  auto sec_type = get_flags() & 0x1F;
428  bool is_allocated = (sec_type == STYP_REG) || (sec_type == STYP_NOLOAD);
429  if (is_allocated) {
430  return header.data_size * arch_->get_addressable_unit();
431  }
432  else {
433  return header.data_size;
434  }
435  }
436 
437  //------------------------------------------------------------------------------
438  void set_data_size(uint32_t value)
439  {
440  auto sec_type = get_flags() & 0x1F;
441  bool is_allocated = (sec_type == STYP_REG) || (sec_type == STYP_NOLOAD);
442  if (is_allocated) {
443  header.data_size = value / arch_->get_addressable_unit();
444  }
445  else {
446  header.data_size = value;
447  }
448  }
449 
450  //------------------------------------------------------------------------------
451  uint32_t get_alignment() const { return 1 << ((get_flags() >> 8) & 0xF); }
452 
453  //------------------------------------------------------------------------------
454  void set_alignment(uint32_t value)
455  {
456  set_flags((get_flags() & ~0xF00) |
457  ((get_bit_number(value) & 0xF) << 8));
458  }
459 };
460 
461 /*! @brief List of sections
462  *
463  * It is implemented as a vector of @ref section pointers.
464  * This allows to manage easily all the different section implementations (for every COFF format),
465  * with pointers to their base interface class (@ref section).
466  */
467 //------------------------------------------------------------------------------
468 class sections : public std::vector<section*>
469 {
470  public:
471  //------------------------------------------------------------------------------
472  sections() {}
473 
474  //------------------------------------------------------------------------------
475  //! Discards the copy constructor
476  sections(const sections&) = delete;
477 
478  //------------------------------------------------------------------------------
479  virtual ~sections() { clean(); }
480 
481  //------------------------------------------------------------------------------
482  void clean()
483  {
484  for (auto sec : *this) {
485  delete sec;
486  }
487  clear();
488  }
489 
490  //------------------------------------------------------------------------------
491  /*! @brief Subscript operator, finds a section by its index
492  *
493  * @param[in] i Index of the section
494  * @return A reference to the element at specified location **i**
495  */
496  section* operator[](size_t i)
497  {
498  return std::vector<section*>::operator[](i);
499  }
500 
501  //------------------------------------------------------------------------------
502  /*! @copydoc operator[](size_t)
503  */
504  const section* operator[](size_t i) const
505  {
506  return std::vector<section*>::operator[](i);
507  }
508 
509  //------------------------------------------------------------------------------
510  /*! @brief Subscript operator, finds a section by its symbolic name
511  *
512  * @param[in] name Symbolic name of the section
513  * @return A reference to the element with the section symbolic name **name**
514  */
515  section* operator[](const std::string& name)
516  {
517  return (section*)((const sections*)this)->operator[](name);
518  }
519 
520  //------------------------------------------------------------------------------
521  /*! @copydoc operator[](const std::string&)
522  */
523  const section* operator[](const std::string& name) const
524  {
525  for (section* sec : *this) {
526  if (sec->get_name() == name) {
527  return sec;
528  }
529  }
530  return 0;
531  }
532 };
533 
534 } // namespace COFFI
535 
536 #endif // COFFI_SECTION_HPP
Interface for architecture information.
virtual coffi_architecture_t get_architecture() const =0
Returns the coffi object architecture.
Class for accessing a COFF section, for the Texas Instruments format.
Template class for accessing a COFF section, depends on the underlying section header format.
section_impl_tmpl(const section_impl_tmpl &)=delete
Discards the copy constructor.
Class for accessing a COFF section, for the PE format.
Interface class for accessing a COFF section, for all the COFF architectures.
List of sections.
const section * operator[](size_t i) const
Subscript operator, finds a section by its index.
const section * operator[](const std::string &name) const
Subscript operator, finds a section by its symbolic name.
section * operator[](const std::string &name)
Subscript operator, finds a section by its symbolic name.
section * operator[](size_t i)
Subscript operator, finds a section by its index.
sections(const sections &)=delete
Discards the copy constructor.
Interface for accessing to the string table.
virtual void name_to_section_string(const std::string &name, char *str)=0
Converts section full name into an 8-bytes short name, eventually creating an entry in the strings ta...
virtual std::string section_string_to_name(const char *str) const =0
Converts an 8-bytes section short name into a full name, eventually by looking into the strings table...
Interface for accessing to the symbol table.
COFFI library classes for the COFF relocation entries.
COFFI library utilities.
COFFI library namespace.
Definition: coffi.hpp:66
@ COFFI_ARCHITECTURE_CEVA
CEVA Inc.
Structure capable of storing all the architecture-specific relocation entry structures.