1 // -*- mode: C++ -*- 2 3 // Copyright 2010 Google LLC 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 LLC 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 31 // Original author: Jim Blandy <[email protected]> <[email protected]> 32 33 // cfi_assembler.h: Define CFISection, a class for creating properly 34 // (and improperly) formatted DWARF CFI data for unit tests. 35 36 #ifndef PROCESSOR_CFI_ASSEMBLER_H_ 37 #define PROCESSOR_CFI_ASSEMBLER_H_ 38 39 #include <string> 40 41 #include "common/dwarf/dwarf2enums.h" 42 #include "common/test_assembler.h" 43 #include "common/using_std_string.h" 44 #include "google_breakpad/common/breakpad_types.h" 45 46 namespace google_breakpad { 47 48 using google_breakpad::test_assembler::Label; 49 using google_breakpad::test_assembler::Section; 50 51 class CFISection: public Section { 52 public: 53 54 // CFI augmentation strings beginning with 'z', defined by the 55 // Linux/IA-64 C++ ABI, can specify interesting encodings for 56 // addresses appearing in FDE headers and call frame instructions (and 57 // for additional fields whose presence the augmentation string 58 // specifies). In particular, pointers can be specified to be relative 59 // to various base address: the start of the .text section, the 60 // location holding the address itself, and so on. These allow the 61 // frame data to be position-independent even when they live in 62 // write-protected pages. These variants are specified at the 63 // following two URLs: 64 // 65 // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html 66 // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html 67 // 68 // CFISection leaves the production of well-formed 'z'-augmented CIEs and 69 // FDEs to the user, but does provide EncodedPointer, to emit 70 // properly-encoded addresses for a given pointer encoding. 71 // EncodedPointer uses an instance of this structure to find the base 72 // addresses it should use; you can establish a default for all encoded 73 // pointers appended to this section with SetEncodedPointerBases. 74 struct EncodedPointerBases { EncodedPointerBasesEncodedPointerBases75 EncodedPointerBases() : cfi(), text(), data() { } 76 77 // The starting address of this CFI section in memory, for 78 // DW_EH_PE_pcrel. DW_EH_PE_pcrel pointers may only be used in data 79 // that has is loaded into the program's address space. 80 uint64_t cfi; 81 82 // The starting address of this file's .text section, for DW_EH_PE_textrel. 83 uint64_t text; 84 85 // The starting address of this file's .got or .eh_frame_hdr section, 86 // for DW_EH_PE_datarel. 87 uint64_t data; 88 }; 89 90 // Create a CFISection whose endianness is ENDIANNESS, and where 91 // machine addresses are ADDRESS_SIZE bytes long. If EH_FRAME is 92 // true, use the .eh_frame format, as described by the Linux 93 // Standards Base Core Specification, instead of the DWARF CFI 94 // format. 95 CFISection(google_breakpad::test_assembler::Endianness endianness, size_t address_size, 96 bool eh_frame = false) Section(endianness)97 : Section(endianness), address_size_(address_size), eh_frame_(eh_frame), 98 pointer_encoding_(DW_EH_PE_absptr), 99 encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) { 100 // The 'start', 'Here', and 'Mark' members of a CFISection all refer 101 // to section offsets. 102 start() = 0; 103 } 104 105 // Return this CFISection's address size. AddressSize()106 size_t AddressSize() const { return address_size_; } 107 108 // Return true if this CFISection uses the .eh_frame format, or 109 // false if it contains ordinary DWARF CFI data. ContainsEHFrame()110 bool ContainsEHFrame() const { return eh_frame_; } 111 112 // Use ENCODING for pointers in calls to FDEHeader and EncodedPointer. SetPointerEncoding(DwarfPointerEncoding encoding)113 void SetPointerEncoding(DwarfPointerEncoding encoding) { 114 pointer_encoding_ = encoding; 115 } 116 117 // Use the addresses in BASES as the base addresses for encoded 118 // pointers in subsequent calls to FDEHeader or EncodedPointer. 119 // This function makes a copy of BASES. SetEncodedPointerBases(const EncodedPointerBases & bases)120 void SetEncodedPointerBases(const EncodedPointerBases& bases) { 121 encoded_pointer_bases_ = bases; 122 } 123 124 // Append a Common Information Entry header to this section with the 125 // given values. If dwarf64 is true, use the 64-bit DWARF initial 126 // length format for the CIE's initial length. Return a reference to 127 // this section. You should call FinishEntry after writing the last 128 // instruction for the CIE. 129 // 130 // Before calling this function, you will typically want to use Mark 131 // or Here to make a label to pass to FDEHeader that refers to this 132 // CIE's position in the section. 133 CFISection& CIEHeader(uint64_t code_alignment_factor, 134 int data_alignment_factor, 135 unsigned return_address_register, 136 uint8_t version = 3, 137 const string& augmentation = "", 138 bool dwarf64 = false, 139 uint8_t address_size = 8, 140 uint8_t segment_size = 0); 141 142 // Append a Frame Description Entry header to this section with the 143 // given values. If dwarf64 is true, use the 64-bit DWARF initial 144 // length format for the CIE's initial length. Return a reference to 145 // this section. You should call FinishEntry after writing the last 146 // instruction for the CIE. 147 // 148 // This function doesn't support entries that are longer than 149 // 0xffffff00 bytes. (The "initial length" is always a 32-bit 150 // value.) Nor does it support .debug_frame sections longer than 151 // 0xffffff00 bytes. 152 CFISection& FDEHeader(Label cie_pointer, 153 uint64_t initial_location, 154 uint64_t address_range, 155 bool dwarf64 = false); 156 157 // Note the current position as the end of the last CIE or FDE we 158 // started, after padding with DW_CFA_nops for alignment. This 159 // defines the label representing the entry's length, cited in the 160 // entry's header. Return a reference to this section. 161 CFISection& FinishEntry(); 162 163 // Append the contents of BLOCK as a DW_FORM_block value: an 164 // unsigned LEB128 length, followed by that many bytes of data. Block(const string & block)165 CFISection& Block(const string& block) { 166 ULEB128(block.size()); 167 Append(block); 168 return *this; 169 } 170 171 // Append ADDRESS to this section, in the appropriate size and 172 // endianness. Return a reference to this section. Address(uint64_t address)173 CFISection& Address(uint64_t address) { 174 Section::Append(endianness(), address_size_, address); 175 return *this; 176 } Address(Label address)177 CFISection& Address(Label address) { 178 Section::Append(endianness(), address_size_, address); 179 return *this; 180 } 181 182 // Append ADDRESS to this section, using ENCODING and BASES. ENCODING 183 // defaults to this section's default encoding, established by 184 // SetPointerEncoding. BASES defaults to this section's bases, set by 185 // SetEncodedPointerBases. If the DW_EH_PE_indirect bit is set in the 186 // encoding, assume that ADDRESS is where the true address is stored. 187 // Return a reference to this section. 188 // 189 // (C++ doesn't let me use default arguments here, because I want to 190 // refer to members of *this in the default argument expression.) EncodedPointer(uint64_t address)191 CFISection& EncodedPointer(uint64_t address) { 192 return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_); 193 } EncodedPointer(uint64_t address,DwarfPointerEncoding encoding)194 CFISection& EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) { 195 return EncodedPointer(address, encoding, encoded_pointer_bases_); 196 } 197 CFISection& EncodedPointer(uint64_t address, DwarfPointerEncoding encoding, 198 const EncodedPointerBases& bases); 199 200 // Restate some member functions, to keep chaining working nicely. Mark(Label * label)201 CFISection& Mark(Label* label) { Section::Mark(label); return *this; } D8(uint8_t v)202 CFISection& D8(uint8_t v) { Section::D8(v); return *this; } D16(uint16_t v)203 CFISection& D16(uint16_t v) { Section::D16(v); return *this; } D16(Label v)204 CFISection& D16(Label v) { Section::D16(v); return *this; } D32(uint32_t v)205 CFISection& D32(uint32_t v) { Section::D32(v); return *this; } D32(const Label & v)206 CFISection& D32(const Label& v) { Section::D32(v); return *this; } D64(uint64_t v)207 CFISection& D64(uint64_t v) { Section::D64(v); return *this; } D64(const Label & v)208 CFISection& D64(const Label& v) { Section::D64(v); return *this; } LEB128(long long v)209 CFISection& LEB128(long long v) { Section::LEB128(v); return *this; } ULEB128(uint64_t v)210 CFISection& ULEB128(uint64_t v) { Section::ULEB128(v); return *this; } 211 212 private: 213 // A length value that we've appended to the section, but is not yet 214 // known. LENGTH is the appended value; START is a label referring 215 // to the start of the data whose length was cited. 216 struct PendingLength { 217 Label length; 218 Label start; 219 }; 220 221 // Constants used in CFI/.eh_frame data: 222 223 // If the first four bytes of an "initial length" are this constant, then 224 // the data uses the 64-bit DWARF format, and the length itself is the 225 // subsequent eight bytes. 226 static const uint32_t kDwarf64InitialLengthMarker = 0xffffffffU; 227 228 // The CIE identifier for 32- and 64-bit DWARF CFI and .eh_frame data. 229 static const uint32_t kDwarf32CIEIdentifier = ~(uint32_t)0; 230 static const uint64_t kDwarf64CIEIdentifier = ~(uint64_t)0; 231 static const uint32_t kEHFrame32CIEIdentifier = 0; 232 static const uint64_t kEHFrame64CIEIdentifier = 0; 233 234 // The size of a machine address for the data in this section. 235 size_t address_size_; 236 237 // If true, we are generating a Linux .eh_frame section, instead of 238 // a standard DWARF .debug_frame section. 239 bool eh_frame_; 240 241 // The encoding to use for FDE pointers. 242 DwarfPointerEncoding pointer_encoding_; 243 244 // The base addresses to use when emitting encoded pointers. 245 EncodedPointerBases encoded_pointer_bases_; 246 247 // The length value for the current entry. 248 // 249 // Oddly, this must be dynamically allocated. Labels never get new 250 // values; they only acquire constraints on the value they already 251 // have, or assert if you assign them something incompatible. So 252 // each header needs truly fresh Label objects to cite in their 253 // headers and track their positions. The alternative is explicit 254 // destructor invocation and a placement new. Ick. 255 PendingLength *entry_length_; 256 257 // True if we are currently emitting an FDE --- that is, we have 258 // called FDEHeader but have not yet called FinishEntry. 259 bool in_fde_; 260 261 // If in_fde_ is true, this is its starting address. We use this for 262 // emitting DW_EH_PE_funcrel pointers. 263 uint64_t fde_start_address_; 264 }; 265 266 } // namespace google_breakpad 267 268 #endif // PROCESSOR_CFI_ASSEMBLER_H_ 269