Mark Mentovai | 4febb34 | 2022-09-07 10:34:05 -0400 | [diff] [blame^] | 1 | // Copyright 2010 Google LLC |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 2 | // |
| 3 | // Redistribution and use in source and binary forms, with or without |
| 4 | // modification, are permitted provided that the following conditions are |
| 5 | // met: |
| 6 | // |
| 7 | // * Redistributions of source code must retain the above copyright |
| 8 | // notice, this list of conditions and the following disclaimer. |
| 9 | // * Redistributions in binary form must reproduce the above |
| 10 | // copyright notice, this list of conditions and the following disclaimer |
| 11 | // in the documentation and/or other materials provided with the |
| 12 | // distribution. |
Mark Mentovai | 4febb34 | 2022-09-07 10:34:05 -0400 | [diff] [blame^] | 13 | // * Neither the name of Google LLC nor the names of its |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 14 | // contributors may be used to endorse or promote products derived from |
| 15 | // this software without specific prior written permission. |
| 16 | // |
| 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | |
| 29 | // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
| 30 | |
| 31 | // cfi_assembler.cc: Implementation of google_breakpad::CFISection class. |
| 32 | // See cfi_assembler.h for details. |
| 33 | |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 34 | #include "common/dwarf/cfi_assembler.h" |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 35 | |
ted.mielczarek | e193098 | 2010-06-25 16:57:07 +0000 | [diff] [blame] | 36 | #include <assert.h> |
| 37 | #include <stdlib.h> |
| 38 | |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 39 | namespace google_breakpad { |
| 40 | |
Mike Frysinger | 09b0569 | 2020-06-23 18:55:43 -0400 | [diff] [blame] | 41 | CFISection& CFISection::CIEHeader(uint64_t code_alignment_factor, |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 42 | int data_alignment_factor, |
| 43 | unsigned return_address_register, |
ted.mielczarek@gmail.com | aeffe10 | 2013-03-06 14:04:42 +0000 | [diff] [blame] | 44 | uint8_t version, |
Mike Frysinger | 09b0569 | 2020-06-23 18:55:43 -0400 | [diff] [blame] | 45 | const string& augmentation, |
Scott Graham | 1f574b5 | 2016-11-01 15:05:10 -0700 | [diff] [blame] | 46 | bool dwarf64, |
| 47 | uint8_t address_size, |
| 48 | uint8_t segment_size) { |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 49 | assert(!entry_length_); |
| 50 | entry_length_ = new PendingLength(); |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 51 | in_fde_ = false; |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 52 | |
| 53 | if (dwarf64) { |
ted.mielczarek | 4f456b8 | 2010-06-25 16:57:02 +0000 | [diff] [blame] | 54 | D32(kDwarf64InitialLengthMarker); |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 55 | D64(entry_length_->length); |
| 56 | entry_length_->start = Here(); |
ted.mielczarek | 4f456b8 | 2010-06-25 16:57:02 +0000 | [diff] [blame] | 57 | D64(eh_frame_ ? kEHFrame64CIEIdentifier : kDwarf64CIEIdentifier); |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 58 | } else { |
| 59 | D32(entry_length_->length); |
| 60 | entry_length_->start = Here(); |
ted.mielczarek | 4f456b8 | 2010-06-25 16:57:02 +0000 | [diff] [blame] | 61 | D32(eh_frame_ ? kEHFrame32CIEIdentifier : kDwarf32CIEIdentifier); |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 62 | } |
| 63 | D8(version); |
| 64 | AppendCString(augmentation); |
Scott Graham | 1f574b5 | 2016-11-01 15:05:10 -0700 | [diff] [blame] | 65 | if (version >= 4) { |
| 66 | D8(address_size); |
| 67 | D8(segment_size); |
| 68 | } |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 69 | ULEB128(code_alignment_factor); |
| 70 | LEB128(data_alignment_factor); |
| 71 | if (version == 1) |
| 72 | D8(return_address_register); |
| 73 | else |
| 74 | ULEB128(return_address_register); |
| 75 | return *this; |
| 76 | } |
| 77 | |
Mike Frysinger | 09b0569 | 2020-06-23 18:55:43 -0400 | [diff] [blame] | 78 | CFISection& CFISection::FDEHeader(Label cie_pointer, |
ted.mielczarek@gmail.com | aeffe10 | 2013-03-06 14:04:42 +0000 | [diff] [blame] | 79 | uint64_t initial_location, |
| 80 | uint64_t address_range, |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 81 | bool dwarf64) { |
| 82 | assert(!entry_length_); |
| 83 | entry_length_ = new PendingLength(); |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 84 | in_fde_ = true; |
| 85 | fde_start_address_ = initial_location; |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 86 | |
| 87 | if (dwarf64) { |
| 88 | D32(0xffffffff); |
| 89 | D64(entry_length_->length); |
| 90 | entry_length_->start = Here(); |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 91 | if (eh_frame_) |
| 92 | D64(Here() - cie_pointer); |
| 93 | else |
| 94 | D64(cie_pointer); |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 95 | } else { |
| 96 | D32(entry_length_->length); |
| 97 | entry_length_->start = Here(); |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 98 | if (eh_frame_) |
| 99 | D32(Here() - cie_pointer); |
| 100 | else |
| 101 | D32(cie_pointer); |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 102 | } |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 103 | EncodedPointer(initial_location); |
| 104 | // The FDE length in an .eh_frame section uses the same encoding as the |
| 105 | // initial location, but ignores the base address (selected by the upper |
| 106 | // nybble of the encoding), as it's a length, not an address that can be |
| 107 | // made relative. |
| 108 | EncodedPointer(address_range, |
| 109 | DwarfPointerEncoding(pointer_encoding_ & 0x0f)); |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 110 | return *this; |
| 111 | } |
| 112 | |
Mike Frysinger | 09b0569 | 2020-06-23 18:55:43 -0400 | [diff] [blame] | 113 | CFISection& CFISection::FinishEntry() { |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 114 | assert(entry_length_); |
Tyrel Russell | 0622f68 | 2021-05-26 08:35:33 -0400 | [diff] [blame] | 115 | Align(address_size_, DW_CFA_nop); |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 116 | entry_length_->length = Here() - entry_length_->start; |
| 117 | delete entry_length_; |
| 118 | entry_length_ = NULL; |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 119 | in_fde_ = false; |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 120 | return *this; |
| 121 | } |
| 122 | |
Mike Frysinger | 09b0569 | 2020-06-23 18:55:43 -0400 | [diff] [blame] | 123 | CFISection& CFISection::EncodedPointer(uint64_t address, |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 124 | DwarfPointerEncoding encoding, |
Mike Frysinger | 09b0569 | 2020-06-23 18:55:43 -0400 | [diff] [blame] | 125 | const EncodedPointerBases& bases) { |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 126 | // Omitted data is extremely easy to emit. |
Tyrel Russell | 0622f68 | 2021-05-26 08:35:33 -0400 | [diff] [blame] | 127 | if (encoding == DW_EH_PE_omit) |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 128 | return *this; |
| 129 | |
Tyrel Russell | 0622f68 | 2021-05-26 08:35:33 -0400 | [diff] [blame] | 130 | // If (encoding & DW_EH_PE_indirect) != 0, then we assume |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 131 | // that ADDRESS is the address at which the pointer is stored --- in |
| 132 | // other words, that bit has no effect on how we write the pointer. |
Tyrel Russell | 0622f68 | 2021-05-26 08:35:33 -0400 | [diff] [blame] | 133 | encoding = DwarfPointerEncoding(encoding & ~DW_EH_PE_indirect); |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 134 | |
| 135 | // Find the base address to which this pointer is relative. The upper |
| 136 | // nybble of the encoding specifies this. |
ted.mielczarek@gmail.com | aeffe10 | 2013-03-06 14:04:42 +0000 | [diff] [blame] | 137 | uint64_t base; |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 138 | switch (encoding & 0xf0) { |
Tyrel Russell | 0622f68 | 2021-05-26 08:35:33 -0400 | [diff] [blame] | 139 | case DW_EH_PE_absptr: base = 0; break; |
| 140 | case DW_EH_PE_pcrel: base = bases.cfi + Size(); break; |
| 141 | case DW_EH_PE_textrel: base = bases.text; break; |
| 142 | case DW_EH_PE_datarel: base = bases.data; break; |
| 143 | case DW_EH_PE_funcrel: base = fde_start_address_; break; |
| 144 | case DW_EH_PE_aligned: base = 0; break; |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 145 | default: abort(); |
| 146 | }; |
| 147 | |
| 148 | // Make ADDRESS relative. Yes, this is appropriate even for "absptr" |
| 149 | // values; see gcc/unwind-pe.h. |
| 150 | address -= base; |
| 151 | |
| 152 | // Align the pointer, if required. |
Tyrel Russell | 0622f68 | 2021-05-26 08:35:33 -0400 | [diff] [blame] | 153 | if ((encoding & 0xf0) == DW_EH_PE_aligned) |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 154 | Align(AddressSize()); |
| 155 | |
| 156 | // Append ADDRESS to this section in the appropriate form. For the |
| 157 | // fixed-width forms, we don't need to differentiate between signed and |
| 158 | // unsigned encodings, because ADDRESS has already been extended to 64 |
| 159 | // bits before it was passed to us. |
| 160 | switch (encoding & 0x0f) { |
Tyrel Russell | 0622f68 | 2021-05-26 08:35:33 -0400 | [diff] [blame] | 161 | case DW_EH_PE_absptr: |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 162 | Address(address); |
| 163 | break; |
| 164 | |
Tyrel Russell | 0622f68 | 2021-05-26 08:35:33 -0400 | [diff] [blame] | 165 | case DW_EH_PE_uleb128: |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 166 | ULEB128(address); |
| 167 | break; |
| 168 | |
Tyrel Russell | 0622f68 | 2021-05-26 08:35:33 -0400 | [diff] [blame] | 169 | case DW_EH_PE_sleb128: |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 170 | LEB128(address); |
| 171 | break; |
| 172 | |
Tyrel Russell | 0622f68 | 2021-05-26 08:35:33 -0400 | [diff] [blame] | 173 | case DW_EH_PE_udata2: |
| 174 | case DW_EH_PE_sdata2: |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 175 | D16(address); |
| 176 | break; |
| 177 | |
Tyrel Russell | 0622f68 | 2021-05-26 08:35:33 -0400 | [diff] [blame] | 178 | case DW_EH_PE_udata4: |
| 179 | case DW_EH_PE_sdata4: |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 180 | D32(address); |
| 181 | break; |
| 182 | |
Tyrel Russell | 0622f68 | 2021-05-26 08:35:33 -0400 | [diff] [blame] | 183 | case DW_EH_PE_udata8: |
| 184 | case DW_EH_PE_sdata8: |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 185 | D64(address); |
| 186 | break; |
| 187 | |
| 188 | default: |
| 189 | abort(); |
| 190 | } |
| 191 | |
| 192 | return *this; |
jimblandy | 3e768ed | 2010-03-16 16:31:49 +0000 | [diff] [blame] | 193 | }; |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 194 | |
ted.mielczarek@gmail.com | aeffe10 | 2013-03-06 14:04:42 +0000 | [diff] [blame] | 195 | const uint32_t CFISection::kDwarf64InitialLengthMarker; |
| 196 | const uint32_t CFISection::kDwarf32CIEIdentifier; |
| 197 | const uint64_t CFISection::kDwarf64CIEIdentifier; |
| 198 | const uint32_t CFISection::kEHFrame32CIEIdentifier; |
| 199 | const uint64_t CFISection::kEHFrame64CIEIdentifier; |
ted.mielczarek | 4f456b8 | 2010-06-25 16:57:02 +0000 | [diff] [blame] | 200 | |
jimblandy | a76aaa1 | 2010-03-16 16:37:50 +0000 | [diff] [blame] | 201 | } // namespace google_breakpad |