pstore2
generic_section.hpp
Go to the documentation of this file.
1 //===- include/pstore/mcrepo/generic_section.hpp ----------*- mode: C++ -*-===//
2 //* _ _ _ *
3 //* __ _ ___ _ __ ___ _ __(_) ___ ___ ___ ___| |_(_) ___ _ __ *
4 //* / _` |/ _ \ '_ \ / _ \ '__| |/ __| / __|/ _ \/ __| __| |/ _ \| '_ \ *
5 //* | (_| | __/ | | | __/ | | | (__ \__ \ __/ (__| |_| | (_) | | | | *
6 //* \__, |\___|_| |_|\___|_| |_|\___| |___/\___|\___|\__|_|\___/|_| |_| *
7 //* |___/ *
8 //===----------------------------------------------------------------------===//
9 //
10 // Part of the pstore project, under the Apache License v2.0 with LLVM Exceptions.
11 // See https://github.com/SNSystems/pstore/blob/master/LICENSE.txt for license
12 // information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //===----------------------------------------------------------------------===//
19 #ifndef PSTORE_MCREPO_GENERIC_SECTION_HPP
20 #define PSTORE_MCREPO_GENERIC_SECTION_HPP
21 
22 #include <algorithm>
23 #include <memory>
24 #include <cstring>
25 
27 #include "pstore/core/address.hpp"
28 #include "pstore/mcrepo/section.hpp"
32 #include "pstore/support/gsl.hpp"
33 
34 namespace pstore {
35  class indirect_string;
36 
37  namespace repo {
38 
39  using relocation_type = std::uint8_t;
40 
41  //* _ _ _ __ _ *
42  //* (_)_ _| |_ ___ _ _ _ _ __ _| | / _(_)_ ___ _ _ __ *
43  //* | | ' \ _/ -_) '_| ' \/ _` | | | _| \ \ / || | '_ \ *
44  //* |_|_||_\__\___|_| |_||_\__,_|_| |_| |_/_\_\\_,_| .__/ *
45  //* |_| *
46  struct internal_fixup {
47  constexpr internal_fixup (section_kind const section_, relocation_type const type_,
48  std::uint64_t const offset_,
49  std::int64_t const addend_) noexcept
50  : section{section_}
51  , type{type_}
52  , offset{offset_}
53  , addend{addend_} {}
54  internal_fixup (internal_fixup const &) noexcept = default;
55  internal_fixup (internal_fixup &&) noexcept = default;
56  internal_fixup & operator= (internal_fixup const &) noexcept = default;
57  internal_fixup & operator= (internal_fixup &&) noexcept = default;
58 
59  bool operator== (internal_fixup const & rhs) const noexcept {
60  return section == rhs.section && type == rhs.type && offset == rhs.offset &&
61  addend == rhs.addend;
62  }
63  bool operator!= (internal_fixup const & rhs) const noexcept {
64  return !operator== (rhs);
65  }
66 
67  section_kind section;
68  relocation_type type;
69  // TODO: much padding here.
70  std::uint16_t padding1 = 0;
71  std::uint32_t padding2 = 0;
72  std::uint64_t offset;
73  std::int64_t addend;
74  };
75 
76 
77  static_assert (std::is_standard_layout<internal_fixup>::value,
78  "internal_fixup must satisfy StandardLayoutType");
79 
80  static_assert (offsetof (internal_fixup, section) == 0,
81  "section offset differs from expected value");
82  static_assert (offsetof (internal_fixup, type) == 1,
83  "type offset differs from expected value");
84  static_assert (offsetof (internal_fixup, padding1) == 2,
85  "padding1 offset differs from expected value");
86  static_assert (offsetof (internal_fixup, padding2) == 4,
87  "padding2 offset differs from expected value");
88  static_assert (offsetof (internal_fixup, offset) == 8,
89  "offset offset differs from expected value");
90  static_assert (offsetof (internal_fixup, addend) == 16,
91  "addend offset differs from expected value");
92  static_assert (sizeof (internal_fixup) == 24,
93  "internal_fixup size differs from expected value");
94 
95  std::ostream & operator<< (std::ostream & os, internal_fixup const & xfx);
96 
99  enum class binding {
100  strong,
101  weak,
102  };
103 
104  std::ostream & operator<< (std::ostream & os, binding const & b);
105 
106 
107  //* _ _ __ _ *
108  //* _____ _| |_ ___ _ _ _ _ __ _| | / _(_)_ ___ _ _ __ *
109  //* / -_) \ / _/ -_) '_| ' \/ _` | | | _| \ \ / || | '_ \ *
110  //* \___/_\_\\__\___|_| |_||_\__,_|_| |_| |_/_\_\\_,_| .__/ *
111  //* |_| *
112  struct external_fixup {
113  constexpr external_fixup (typed_address<indirect_string> const name_,
114  relocation_type const type_, binding const strength,
115  std::uint64_t const offset_,
116  std::int64_t const addend_) noexcept
117  : name{name_}
118  , type{type_}
119  , is_weak{strength == binding::weak}
120  , offset{offset_}
121  , addend{addend_} {}
122 
123  external_fixup (external_fixup const &) noexcept = default;
124  external_fixup (external_fixup &&) noexcept = default;
125  external_fixup & operator= (external_fixup const &) noexcept = default;
126  external_fixup & operator= (external_fixup &&) noexcept = default;
127 
128  bool operator== (external_fixup const & rhs) const noexcept {
129  return name == rhs.name && type == rhs.type && is_weak == rhs.is_weak &&
130  offset == rhs.offset && addend == rhs.addend;
131  }
132  bool operator!= (external_fixup const & rhs) const noexcept {
133  return !operator== (rhs);
134  }
135 
136  constexpr binding strength () const noexcept {
137  return is_weak ? binding::weak : binding::strong;
138  }
139 
141  relocation_type type;
142  bool is_weak = false;
143  // TODO: much padding here.
144  std::uint16_t padding1 = 0;
145  std::uint32_t padding2 = 0;
146  std::uint64_t offset;
147  std::int64_t addend;
148  };
149 
150  static_assert (std::is_standard_layout<external_fixup>::value,
151  "external_fixup must satisfy StandardLayoutType");
152  static_assert (offsetof (external_fixup, name) == 0,
153  "name offset differs from expected value");
154  static_assert (offsetof (external_fixup, type) == 8,
155  "type offset differs from expected value");
156  static_assert (offsetof (external_fixup, is_weak) == 9,
157  "is_weak offset differs from expected value");
158  static_assert (offsetof (external_fixup, padding1) == 10,
159  "padding1 offset differs from expected value");
160  static_assert (offsetof (external_fixup, padding2) == 12,
161  "padding2 offset differs from expected value");
162  static_assert (offsetof (external_fixup, offset) == 16,
163  "offset offset differs from expected value");
164  static_assert (offsetof (external_fixup, addend) == 24,
165  "addend offset differs from expected value");
166  static_assert (alignof (external_fixup) == 8, "external_fixup alignment should be 8");
167  static_assert (sizeof (external_fixup) == 32,
168  "external_fixup size differs from expected value");
169 
170  std::ostream & operator<< (std::ostream & os, external_fixup const & xfx);
171 
172  //* _ _ _ *
173  //* __ _ ___ _ _ ___ _ _(_)__ ___ ___ __| |_(_)___ _ _ *
174  //* / _` / -_) ' \/ -_) '_| / _| (_-</ -_) _| _| / _ \ ' \ *
175  //* \__, \___|_||_\___|_| |_\__| /__/\___\__|\__|_\___/_||_| *
176  //* |___/ *
177  class generic_section : public section_base {
178  public:
179  void * operator new (std::size_t const size, void * const ptr) {
180  return ::operator new (size, ptr);
181  }
182  void operator delete (void * const ptr, void * const p) { ::operator delete (ptr, p); }
183 
186  template <typename DataRangeType, typename IFixupRangeType, typename XFixupRangeType>
187  struct sources {
188  DataRangeType data_range;
189  IFixupRangeType ifixups_range;
190  XFixupRangeType xfixups_range;
191  };
192 
193  template <typename DataRange, typename IFixupRange, typename XFixupRange>
194  static inline auto make_sources (DataRange const & d, IFixupRange const & i,
195  XFixupRange const & x)
197  return {d, i, x};
198  }
199 
200  template <typename DataRange, typename IFixupRange, typename XFixupRange>
201  generic_section (DataRange const & d, IFixupRange const & i, XFixupRange const & x,
202  std::uint8_t align);
203 
204  template <typename DataRange, typename IFixupRange, typename XFixupRange>
206  std::uint8_t align)
207  : generic_section (src.data_range, src.ifixups_range, src.xfixups_range,
208  align) {}
209 
210  generic_section (generic_section const &) = delete;
211  generic_section (generic_section &&) = delete;
212 
213  generic_section & operator= (generic_section const &) = delete;
214  generic_section & operator= (generic_section &&) = delete;
215 
216  unsigned align () const noexcept { return 1U << align_; }
218  std::uint64_t size () const noexcept { return data_size_; }
219 
220  container<std::uint8_t> payload () const noexcept {
221  auto const * const begin = aligned_ptr<std::uint8_t> (this + 1);
222  return {begin, begin + data_size_};
223  }
224  container<internal_fixup> ifixups () const {
225  auto const * const begin = aligned_ptr<internal_fixup> (payload ().end ());
226  return {begin, begin + this->num_ifixups ()};
227  }
228  container<external_fixup> xfixups () const {
229  auto const * const begin = aligned_ptr<external_fixup> (ifixups ().end ());
230  return {begin, begin + num_xfixups_};
231  }
232 
236 
238  std::size_t size_bytes () const;
239 
242  static std::size_t size_bytes (std::size_t data_size, std::size_t num_ifixups,
243  std::size_t num_xfixups);
244 
245  template <typename DataRange, typename IFixupRange, typename XFixupRange>
246  static std::size_t size_bytes (DataRange const & d, IFixupRange const & i,
247  XFixupRange const & x);
248 
249  template <typename DataRange, typename IFixupRange, typename XFixupRange>
250  static std::size_t
251  size_bytes (sources<DataRange, IFixupRange, XFixupRange> const & src) {
252  return size_bytes (src.data_range, src.ifixups_range, src.xfixups_range);
253  }
255 
256  private:
257  // The ctor assumes that memory has been allocated for the variable length arrays that
258  // follow an instance of this type. This is performed by the
259  // generic_section_creation_dispatcher. Prevent usage of standard operator new and
260  // friends to avoid someone forgetting to use that helper in the future.
261  void * operator new (std::size_t) = delete;
262  void * operator new (std::size_t, std::nothrow_t const &) noexcept = delete;
263  void * operator new[] (std::size_t) = delete;
264  void * operator new[] (std::size_t, std::nothrow_t const &) = delete;
265  void operator delete (void *) noexcept = delete;
266  void operator delete (void * ptr, std::nothrow_t const &) noexcept = delete;
267  void operator delete[] (void *) noexcept = delete;
268  void operator delete[] (void *, std::nothrow_t const &) noexcept = delete;
269 
270  union {
271  std::uint32_t field32_ = 0;
277  };
279  std::uint32_t num_xfixups_ = 0;
281  std::uint64_t data_size_ = 0;
282 
283  std::uint32_t num_ifixups () const noexcept;
284 
287  template <typename IntType, typename Iterator,
288  typename = typename std::enable_if<std::is_unsigned<IntType>::value>::type>
289  static IntType set_size (Iterator first, Iterator last);
290 
296  template <typename Ty>
297  static inline std::size_t part_size_bytes (std::size_t pos, std::size_t const num) {
298  if (num > 0) {
299  pos = aligned<Ty> (pos) + num * sizeof (Ty);
300  }
301  return pos;
302  }
303  };
304 
305  // (ctor)
306  // ~~~~~~
307  template <typename DataRange, typename IFixupRange, typename XFixupRange>
308  generic_section::generic_section (DataRange const & d, IFixupRange const & i,
309  XFixupRange const & x, std::uint8_t const align) {
310  align_ = bit_count::ctz (align);
311  num_ifixups_ = std::uint32_t{0};
312 
313  PSTORE_STATIC_ASSERT (std::is_standard_layout<generic_section>::value);
314 
315  PSTORE_STATIC_ASSERT (offsetof (generic_section, field32_) == 0);
316  PSTORE_STATIC_ASSERT (offsetof (generic_section, align_) ==
317  offsetof (generic_section, field32_));
318  PSTORE_STATIC_ASSERT (offsetof (generic_section, num_ifixups_) ==
319  offsetof (generic_section, field32_));
320 
321  PSTORE_STATIC_ASSERT (offsetof (generic_section, num_xfixups_) == 4);
322  PSTORE_STATIC_ASSERT (offsetof (generic_section, data_size_) == 8);
323  PSTORE_STATIC_ASSERT (sizeof (generic_section) == 16);
324  PSTORE_STATIC_ASSERT (alignof (generic_section) == 8);
325 #ifndef NDEBUG
326  auto * const start = reinterpret_cast<std::uint8_t const *> (this);
327 #endif
328  // Note that the memory pointed to by 'p' is uninitialized.
329  auto * p = reinterpret_cast<std::uint8_t *> (this + 1);
330  PSTORE_ASSERT (bit_count::pop_count (align) == 1);
331 
332  if (d.first != d.second) {
333  data_size_ = generic_section::set_size<decltype (data_size_)> (d.first, d.second);
334  p = std::uninitialized_copy (d.first, d.second, p);
335  }
336  if (i.first != i.second) {
337  p = reinterpret_cast<std::uint8_t *> (
338  std::uninitialized_copy (i.first, i.second, aligned_ptr<internal_fixup> (p)));
339  num_ifixups_ = generic_section::set_size<decltype (num_ifixups_)::value_type> (
340  i.first, i.second);
341  }
342  if (x.first != x.second) {
343  p = reinterpret_cast<std::uint8_t *> (
344  std::uninitialized_copy (x.first, x.second, aligned_ptr<external_fixup> (p)));
345  num_xfixups_ =
346  generic_section::set_size<decltype (num_xfixups_)> (x.first, x.second);
347  }
348  PSTORE_ASSERT (p >= start &&
349  static_cast<std::size_t> (p - start) == size_bytes (d, i, x));
350  }
351 
352  // set_size
353  // ~~~~~~~~
354  template <typename IntType, typename Iterator, typename>
355  inline IntType generic_section::set_size (Iterator first, Iterator last) {
356  auto const size = std::distance (first, last);
357  if (size <= 0) {
358  return 0;
359  }
360  using common =
361  typename std::common_type<IntType,
362  typename std::make_unsigned<decltype (size)>::type>::type;
363  return static_cast<IntType> (
364  std::min (static_cast<common> (size),
365  static_cast<common> (std::numeric_limits<IntType>::max ())));
366  }
367 
368  // size_bytes
369  // ~~~~~~~~~~
370  template <typename DataRange, typename IFixupRange, typename XFixupRange>
371  std::size_t generic_section::size_bytes (DataRange const & d, IFixupRange const & i,
372  XFixupRange const & x) {
373  auto const data_size = std::distance (d.first, d.second);
374  auto const num_ifixups = std::distance (i.first, i.second);
375  auto const num_xfixups = std::distance (x.first, x.second);
376  PSTORE_ASSERT (data_size >= 0 && num_ifixups >= 0 && num_xfixups >= 0);
377  return size_bytes (static_cast<std::size_t> (data_size),
378  static_cast<std::size_t> (num_ifixups),
379  static_cast<std::size_t> (num_xfixups));
380  }
381 
382  // num_ifixups
383  // ~~~~~~~~~~~
384  inline std::uint32_t generic_section::num_ifixups () const noexcept { return num_ifixups_; }
385 
387  section_content () noexcept = default;
388  explicit section_content (section_kind const kind_) noexcept
389  : kind{kind_} {}
390  section_content (section_kind const kind_, std::uint8_t const align_) noexcept
391  : kind{kind_}
392  , align{align_} {}
393  section_content (section_content const &) = delete;
394  section_content (section_content &&) noexcept = default;
395  section_content & operator= (section_content const &) = delete;
396  section_content & operator= (section_content &&) noexcept = default;
397 
398  template <typename Iterator>
399  using range = std::pair<Iterator, Iterator>;
400 
401  template <typename Iterator>
402  static inline auto make_range (Iterator begin, Iterator end) -> range<Iterator> {
403  return {begin, end};
404  }
405 
406  section_kind kind = section_kind::text;
407  std::uint8_t align = 1;
409  std::vector<internal_fixup> ifixups;
410  std::vector<external_fixup> xfixups;
411 
412  auto make_sources () const
414  range<decltype (ifixups)::const_iterator>,
415  range<decltype (xfixups)::const_iterator>> {
416 
417  return generic_section::make_sources (
418  make_range (std::begin (data), std::end (data)),
419  make_range (std::begin (ifixups), std::end (ifixups)),
420  make_range (std::begin (xfixups), std::end (xfixups)));
421  }
422  };
423 
424  bool operator== (section_content const & lhs, section_content const & rhs);
425  bool operator!= (section_content const & lhs, section_content const & rhs);
426  std::ostream & operator<< (std::ostream & os, section_content const & c);
427 
428  template <>
429  inline unsigned section_alignment<pstore::repo::generic_section> (
430  pstore::repo::generic_section const & s) noexcept {
431  return s.align ();
432  }
433  template <>
434  inline std::uint64_t section_size<pstore::repo::generic_section> (
435  pstore::repo::generic_section const & s) noexcept {
436  return s.size ();
437  }
438 
439 
440  //* _ _ _ _ _ _ *
441  //* __ _ _ ___ __ _| |_(_)___ _ _ __| (_)____ __ __ _| |_ __| |_ ___ _ _ *
442  //* / _| '_/ -_) _` | _| / _ \ ' \ / _` | (_-< '_ \/ _` | _/ _| ' \/ -_) '_| *
443  //* \__|_| \___\__,_|\__|_\___/_||_| \__,_|_/__/ .__/\__,_|\__\__|_||_\___|_| *
444  //* |_| *
446  public:
447  explicit generic_section_creation_dispatcher (section_kind const kind)
448  : section_creation_dispatcher (kind) {}
449 
450  generic_section_creation_dispatcher (section_kind const kind,
453  , section_{sec} {}
454 
456  delete;
458  operator= (generic_section_creation_dispatcher const &) = delete;
459 
460  void set_content (gsl::not_null<section_content const *> const content) {
461  section_ = content;
462  }
463 
464  std::size_t size_bytes () const final;
465 
466  // Write the section data to the memory which the pointer 'out' pointed to.
467  std::uint8_t * write (std::uint8_t * out) const final;
468 
469  private:
470  std::uintptr_t aligned_impl (std::uintptr_t in) const final;
471  section_content const * section_ = nullptr;
472  };
473 
474  template <>
477  };
478 
479  //* _ _ _ _ _ _ *
480  //* ___ ___ __| |_(_)___ _ _ __| (_)____ __ __ _| |_ __| |_ ___ _ _ *
481  //* (_-</ -_) _| _| / _ \ ' \ / _` | (_-< '_ \/ _` | _/ _| ' \/ -_) '_| *
482  //* /__/\___\__|\__|_\___/_||_| \__,_|_/__/ .__/\__,_|\__\__|_||_\___|_| *
483  //* |_| *
484  class section_dispatcher final : public dispatcher {
485  public:
486  explicit section_dispatcher (generic_section const & s) noexcept
487  : s_{s} {}
488  ~section_dispatcher () noexcept override;
489 
490  std::size_t size_bytes () const final { return s_.size_bytes (); }
491  unsigned align () const final { return s_.align (); }
492  std::size_t size () const final { return s_.size (); }
493  container<internal_fixup> ifixups () const final { return s_.ifixups (); }
494  container<external_fixup> xfixups () const final { return s_.xfixups (); }
495  container<std::uint8_t> payload () const final { return s_.payload (); }
496 
497  private:
498  generic_section const & s_;
499  };
500 
501  template <>
503  using type = section_dispatcher;
504  };
505 
506  } // end namespace repo
507 } // end namespace pstore
508 
509 #endif // PSTORE_MCREPO_GENERIC_SECTION_HPP
Definition: generic_section.hpp:112
A portable bit-field type.
A simple wrapper around the elements of one of the three arrays that make up a section.
Definition: section.hpp:152
std::uint64_t size() const noexcept
The number of data bytes contained by this section.
Definition: generic_section.hpp:218
Definition: chunked_sequence.hpp:607
Maps from the type of data that is associated with a fragment&#39;s section to a "dispatcher" subclass wh...
Definition: section.hpp:146
transaction< transaction_lock > begin(database &db, transaction_lock &lock)
Creates a new transaction. Every operation performed on a transaction instance can be potentially und...
Definition: transaction.hpp:311
Describes the three members of a section as three pairs of iterators: one each for the data...
Definition: generic_section.hpp:187
This class is used to add virtual methods to a fragment&#39;s section.
Definition: section.hpp:195
Definition: address.hpp:231
Definition: generic_section.hpp:177
An empty class used as the base type for all sections.
Definition: section.hpp:69
Definition: gsl.hpp:589
Maps from the type of data that is associated with a fragment&#39;s section to a "dispatcher" subclass wh...
Definition: section.hpp:214
std::size_t size_bytes() const
A group of member functions which return the number of bytes occupied by a fragment instance...
Definition: generic_section.cpp:83
Definition: common.py:1
Definition: nonpod2.cpp:40
bit_field< std::uint32_t, 8, 24 > num_ifixups_
The number of internal fixups.
Definition: generic_section.hpp:276
Definition: generic_section.hpp:386
Implements portable functions for bit twiddling operations including counting leading and trailing ze...
Definition: generic_section.hpp:445
container< std::uint8_t > payload() const final
Return the data section stored in the object file.
Definition: generic_section.hpp:495
bit_field< std::uint32_t, 0, 8 > align_
The alignment of this section expressed as a power of two (i.e.
Definition: generic_section.hpp:274
Definition: generic_section.hpp:484
A section creation dispatcher is used to instantiate and construct each of a fragment&#39;s sections in p...
Definition: section.hpp:91
Provides a small, normally stack allocated, buffer but which can be resized dynamically when necessar...
Definition: generic_section.hpp:46
binding
Defines the strength of an external reference.
Definition: generic_section.hpp:99
Functions for aligning values and pointers.