/thirdparty/breakpad/common/dwarf/cfi_assembler.h

http://github.com/tomahawk-player/tomahawk · C++ Header · 269 lines · 97 code · 38 blank · 134 comment · 0 complexity · 792c84eef9e4ba9eb79905dba23386ea MD5 · raw file

  1. // -*- mode: C++ -*-
  2. // Copyright (c) 2010, Google Inc.
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
  31. // cfi_assembler.h: Define CFISection, a class for creating properly
  32. // (and improperly) formatted DWARF CFI data for unit tests.
  33. #ifndef PROCESSOR_CFI_ASSEMBLER_H_
  34. #define PROCESSOR_CFI_ASSEMBLER_H_
  35. #include <string>
  36. #include "common/dwarf/dwarf2enums.h"
  37. #include "common/test_assembler.h"
  38. #include "google_breakpad/common/breakpad_types.h"
  39. namespace google_breakpad {
  40. using dwarf2reader::DwarfPointerEncoding;
  41. using google_breakpad::test_assembler::Endianness;
  42. using google_breakpad::test_assembler::Label;
  43. using google_breakpad::test_assembler::Section;
  44. using std::string;
  45. class CFISection: public Section {
  46. public:
  47. // CFI augmentation strings beginning with 'z', defined by the
  48. // Linux/IA-64 C++ ABI, can specify interesting encodings for
  49. // addresses appearing in FDE headers and call frame instructions (and
  50. // for additional fields whose presence the augmentation string
  51. // specifies). In particular, pointers can be specified to be relative
  52. // to various base address: the start of the .text section, the
  53. // location holding the address itself, and so on. These allow the
  54. // frame data to be position-independent even when they live in
  55. // write-protected pages. These variants are specified at the
  56. // following two URLs:
  57. //
  58. // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html
  59. // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
  60. //
  61. // CFISection leaves the production of well-formed 'z'-augmented CIEs and
  62. // FDEs to the user, but does provide EncodedPointer, to emit
  63. // properly-encoded addresses for a given pointer encoding.
  64. // EncodedPointer uses an instance of this structure to find the base
  65. // addresses it should use; you can establish a default for all encoded
  66. // pointers appended to this section with SetEncodedPointerBases.
  67. struct EncodedPointerBases {
  68. EncodedPointerBases() : cfi(), text(), data() { }
  69. // The starting address of this CFI section in memory, for
  70. // DW_EH_PE_pcrel. DW_EH_PE_pcrel pointers may only be used in data
  71. // that has is loaded into the program's address space.
  72. u_int64_t cfi;
  73. // The starting address of this file's .text section, for DW_EH_PE_textrel.
  74. u_int64_t text;
  75. // The starting address of this file's .got or .eh_frame_hdr section,
  76. // for DW_EH_PE_datarel.
  77. u_int64_t data;
  78. };
  79. // Create a CFISection whose endianness is ENDIANNESS, and where
  80. // machine addresses are ADDRESS_SIZE bytes long. If EH_FRAME is
  81. // true, use the .eh_frame format, as described by the Linux
  82. // Standards Base Core Specification, instead of the DWARF CFI
  83. // format.
  84. CFISection(Endianness endianness, size_t address_size,
  85. bool eh_frame = false)
  86. : Section(endianness), address_size_(address_size), eh_frame_(eh_frame),
  87. pointer_encoding_(dwarf2reader::DW_EH_PE_absptr),
  88. encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) {
  89. // The 'start', 'Here', and 'Mark' members of a CFISection all refer
  90. // to section offsets.
  91. start() = 0;
  92. }
  93. // Return this CFISection's address size.
  94. size_t AddressSize() const { return address_size_; }
  95. // Return true if this CFISection uses the .eh_frame format, or
  96. // false if it contains ordinary DWARF CFI data.
  97. bool ContainsEHFrame() const { return eh_frame_; }
  98. // Use ENCODING for pointers in calls to FDEHeader and EncodedPointer.
  99. void SetPointerEncoding(DwarfPointerEncoding encoding) {
  100. pointer_encoding_ = encoding;
  101. }
  102. // Use the addresses in BASES as the base addresses for encoded
  103. // pointers in subsequent calls to FDEHeader or EncodedPointer.
  104. // This function makes a copy of BASES.
  105. void SetEncodedPointerBases(const EncodedPointerBases &bases) {
  106. encoded_pointer_bases_ = bases;
  107. }
  108. // Append a Common Information Entry header to this section with the
  109. // given values. If dwarf64 is true, use the 64-bit DWARF initial
  110. // length format for the CIE's initial length. Return a reference to
  111. // this section. You should call FinishEntry after writing the last
  112. // instruction for the CIE.
  113. //
  114. // Before calling this function, you will typically want to use Mark
  115. // or Here to make a label to pass to FDEHeader that refers to this
  116. // CIE's position in the section.
  117. CFISection &CIEHeader(u_int64_t code_alignment_factor,
  118. int data_alignment_factor,
  119. unsigned return_address_register,
  120. u_int8_t version = 3,
  121. const string &augmentation = "",
  122. bool dwarf64 = false);
  123. // Append a Frame Description Entry header to this section with the
  124. // given values. If dwarf64 is true, use the 64-bit DWARF initial
  125. // length format for the CIE's initial length. Return a reference to
  126. // this section. You should call FinishEntry after writing the last
  127. // instruction for the CIE.
  128. //
  129. // This function doesn't support entries that are longer than
  130. // 0xffffff00 bytes. (The "initial length" is always a 32-bit
  131. // value.) Nor does it support .debug_frame sections longer than
  132. // 0xffffff00 bytes.
  133. CFISection &FDEHeader(Label cie_pointer,
  134. u_int64_t initial_location,
  135. u_int64_t address_range,
  136. bool dwarf64 = false);
  137. // Note the current position as the end of the last CIE or FDE we
  138. // started, after padding with DW_CFA_nops for alignment. This
  139. // defines the label representing the entry's length, cited in the
  140. // entry's header. Return a reference to this section.
  141. CFISection &FinishEntry();
  142. // Append the contents of BLOCK as a DW_FORM_block value: an
  143. // unsigned LEB128 length, followed by that many bytes of data.
  144. CFISection &Block(const string &block) {
  145. ULEB128(block.size());
  146. Append(block);
  147. return *this;
  148. }
  149. // Append ADDRESS to this section, in the appropriate size and
  150. // endianness. Return a reference to this section.
  151. CFISection &Address(u_int64_t address) {
  152. Section::Append(endianness(), address_size_, address);
  153. return *this;
  154. }
  155. CFISection &Address(Label address) {
  156. Section::Append(endianness(), address_size_, address);
  157. return *this;
  158. }
  159. // Append ADDRESS to this section, using ENCODING and BASES. ENCODING
  160. // defaults to this section's default encoding, established by
  161. // SetPointerEncoding. BASES defaults to this section's bases, set by
  162. // SetEncodedPointerBases. If the DW_EH_PE_indirect bit is set in the
  163. // encoding, assume that ADDRESS is where the true address is stored.
  164. // Return a reference to this section.
  165. //
  166. // (C++ doesn't let me use default arguments here, because I want to
  167. // refer to members of *this in the default argument expression.)
  168. CFISection &EncodedPointer(u_int64_t address) {
  169. return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_);
  170. }
  171. CFISection &EncodedPointer(u_int64_t address, DwarfPointerEncoding encoding) {
  172. return EncodedPointer(address, encoding, encoded_pointer_bases_);
  173. }
  174. CFISection &EncodedPointer(u_int64_t address, DwarfPointerEncoding encoding,
  175. const EncodedPointerBases &bases);
  176. // Restate some member functions, to keep chaining working nicely.
  177. CFISection &Mark(Label *label) { Section::Mark(label); return *this; }
  178. CFISection &D8(u_int8_t v) { Section::D8(v); return *this; }
  179. CFISection &D16(u_int16_t v) { Section::D16(v); return *this; }
  180. CFISection &D16(Label v) { Section::D16(v); return *this; }
  181. CFISection &D32(u_int32_t v) { Section::D32(v); return *this; }
  182. CFISection &D32(const Label &v) { Section::D32(v); return *this; }
  183. CFISection &D64(u_int64_t v) { Section::D64(v); return *this; }
  184. CFISection &D64(const Label &v) { Section::D64(v); return *this; }
  185. CFISection &LEB128(long long v) { Section::LEB128(v); return *this; }
  186. CFISection &ULEB128(u_int64_t v) { Section::ULEB128(v); return *this; }
  187. private:
  188. // A length value that we've appended to the section, but is not yet
  189. // known. LENGTH is the appended value; START is a label referring
  190. // to the start of the data whose length was cited.
  191. struct PendingLength {
  192. Label length;
  193. Label start;
  194. };
  195. // Constants used in CFI/.eh_frame data:
  196. // If the first four bytes of an "initial length" are this constant, then
  197. // the data uses the 64-bit DWARF format, and the length itself is the
  198. // subsequent eight bytes.
  199. static const u_int32_t kDwarf64InitialLengthMarker = 0xffffffffU;
  200. // The CIE identifier for 32- and 64-bit DWARF CFI and .eh_frame data.
  201. static const u_int32_t kDwarf32CIEIdentifier = ~(u_int32_t)0;
  202. static const u_int64_t kDwarf64CIEIdentifier = ~(u_int64_t)0;
  203. static const u_int32_t kEHFrame32CIEIdentifier = 0;
  204. static const u_int64_t kEHFrame64CIEIdentifier = 0;
  205. // The size of a machine address for the data in this section.
  206. size_t address_size_;
  207. // If true, we are generating a Linux .eh_frame section, instead of
  208. // a standard DWARF .debug_frame section.
  209. bool eh_frame_;
  210. // The encoding to use for FDE pointers.
  211. DwarfPointerEncoding pointer_encoding_;
  212. // The base addresses to use when emitting encoded pointers.
  213. EncodedPointerBases encoded_pointer_bases_;
  214. // The length value for the current entry.
  215. //
  216. // Oddly, this must be dynamically allocated. Labels never get new
  217. // values; they only acquire constraints on the value they already
  218. // have, or assert if you assign them something incompatible. So
  219. // each header needs truly fresh Label objects to cite in their
  220. // headers and track their positions. The alternative is explicit
  221. // destructor invocation and a placement new. Ick.
  222. PendingLength *entry_length_;
  223. // True if we are currently emitting an FDE --- that is, we have
  224. // called FDEHeader but have not yet called FinishEntry.
  225. bool in_fde_;
  226. // If in_fde_ is true, this is its starting address. We use this for
  227. // emitting DW_EH_PE_funcrel pointers.
  228. u_int64_t fde_start_address_;
  229. };
  230. } // namespace google_breakpad
  231. #endif // PROCESSOR_CFI_ASSEMBLER_H_