| 1 | // ehframe.h -- handle exception frame sections for gold -*- C++ -*- |
| 2 | |
| 3 | // Copyright (C) 2006-2014 Free Software Foundation, Inc. |
| 4 | // Written by Ian Lance Taylor <iant@google.com>. |
| 5 | |
| 6 | // This file is part of gold. |
| 7 | |
| 8 | // This program is free software; you can redistribute it and/or modify |
| 9 | // it under the terms of the GNU General Public License as published by |
| 10 | // the Free Software Foundation; either version 3 of the License, or |
| 11 | // (at your option) any later version. |
| 12 | |
| 13 | // This program is distributed in the hope that it will be useful, |
| 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | // GNU General Public License for more details. |
| 17 | |
| 18 | // You should have received a copy of the GNU General Public License |
| 19 | // along with this program; if not, write to the Free Software |
| 20 | // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
| 21 | // MA 02110-1301, USA. |
| 22 | |
| 23 | #ifndef GOLD_EHFRAME_H |
| 24 | #define GOLD_EHFRAME_H |
| 25 | |
| 26 | #include <map> |
| 27 | #include <set> |
| 28 | #include <vector> |
| 29 | |
| 30 | #include "output.h" |
| 31 | #include "merge.h" |
| 32 | |
| 33 | namespace gold |
| 34 | { |
| 35 | |
| 36 | template<int size, bool big_endian> |
| 37 | class Track_relocs; |
| 38 | |
| 39 | class Eh_frame; |
| 40 | |
| 41 | // This class manages the .eh_frame_hdr section, which holds the data |
| 42 | // for the PT_GNU_EH_FRAME segment. gcc's unwind support code uses |
| 43 | // the PT_GNU_EH_FRAME segment to find the list of FDEs. This saves |
| 44 | // the time required to register the exception handlers at startup |
| 45 | // time and when a shared object is loaded, and the time required to |
| 46 | // deregister the exception handlers when a shared object is unloaded. |
| 47 | |
| 48 | class Eh_frame_hdr : public Output_section_data |
| 49 | { |
| 50 | public: |
| 51 | Eh_frame_hdr(Output_section* eh_frame_section, const Eh_frame*); |
| 52 | |
| 53 | // Record that we found an unrecognized .eh_frame section. |
| 54 | void |
| 55 | found_unrecognized_eh_frame_section() |
| 56 | { this->any_unrecognized_eh_frame_sections_ = true; } |
| 57 | |
| 58 | // Record an FDE. |
| 59 | void |
| 60 | record_fde(section_offset_type fde_offset, unsigned char fde_encoding) |
| 61 | { |
| 62 | if (!this->any_unrecognized_eh_frame_sections_) |
| 63 | this->fde_offsets_.push_back(std::make_pair(fde_offset, fde_encoding)); |
| 64 | } |
| 65 | |
| 66 | protected: |
| 67 | // Set the final data size. |
| 68 | void |
| 69 | set_final_data_size(); |
| 70 | |
| 71 | // Write the data to the file. |
| 72 | void |
| 73 | do_write(Output_file*); |
| 74 | |
| 75 | // Write to a map file. |
| 76 | void |
| 77 | do_print_to_mapfile(Mapfile* mapfile) const |
| 78 | { mapfile->print_output_data(this, _("** eh_frame_hdr")); } |
| 79 | |
| 80 | private: |
| 81 | // Write the data to the file with the right endianness. |
| 82 | template<int size, bool big_endian> |
| 83 | void |
| 84 | do_sized_write(Output_file*); |
| 85 | |
| 86 | // The data we record for one FDE: the offset of the FDE within the |
| 87 | // .eh_frame section, and the FDE encoding. |
| 88 | typedef std::pair<section_offset_type, unsigned char> Fde_offset; |
| 89 | |
| 90 | // The list of information we record for an FDE. |
| 91 | typedef std::vector<Fde_offset> Fde_offsets; |
| 92 | |
| 93 | // When writing out the header, we convert the FDE offsets into FDE |
| 94 | // addresses. This is a list of pairs of the offset from the header |
| 95 | // to the FDE PC and to the FDE itself. |
| 96 | template<int size> |
| 97 | class Fde_addresses |
| 98 | { |
| 99 | public: |
| 100 | typedef typename elfcpp::Elf_types<size>::Elf_Addr Address; |
| 101 | typedef typename std::pair<Address, Address> Fde_address; |
| 102 | typedef typename std::vector<Fde_address> Fde_address_list; |
| 103 | typedef typename Fde_address_list::iterator iterator; |
| 104 | |
| 105 | Fde_addresses(unsigned int reserve) |
| 106 | : fde_addresses_() |
| 107 | { this->fde_addresses_.reserve(reserve); } |
| 108 | |
| 109 | void |
| 110 | push_back(Address pc_address, Address fde_address) |
| 111 | { |
| 112 | this->fde_addresses_.push_back(std::make_pair(pc_address, fde_address)); |
| 113 | } |
| 114 | |
| 115 | iterator |
| 116 | begin() |
| 117 | { return this->fde_addresses_.begin(); } |
| 118 | |
| 119 | iterator |
| 120 | end() |
| 121 | { return this->fde_addresses_.end(); } |
| 122 | |
| 123 | private: |
| 124 | Fde_address_list fde_addresses_; |
| 125 | }; |
| 126 | |
| 127 | // Compare Fde_address objects. |
| 128 | template<int size> |
| 129 | struct Fde_address_compare |
| 130 | { |
| 131 | bool |
| 132 | operator()(const typename Fde_addresses<size>::Fde_address& f1, |
| 133 | const typename Fde_addresses<size>::Fde_address& f2) const |
| 134 | { return f1.first < f2.first; } |
| 135 | }; |
| 136 | |
| 137 | // Return the PC to which an FDE refers. |
| 138 | template<int size, bool big_endian> |
| 139 | typename elfcpp::Elf_types<size>::Elf_Addr |
| 140 | get_fde_pc(typename elfcpp::Elf_types<size>::Elf_Addr eh_frame_address, |
| 141 | const unsigned char* eh_frame_contents, |
| 142 | section_offset_type fde_offset, unsigned char fde_encoding); |
| 143 | |
| 144 | // Convert Fde_offsets to Fde_addresses. |
| 145 | template<int size, bool big_endian> |
| 146 | void |
| 147 | get_fde_addresses(Output_file* of, |
| 148 | const Fde_offsets* fde_offsets, |
| 149 | Fde_addresses<size>* fde_addresses); |
| 150 | |
| 151 | // The .eh_frame section. |
| 152 | Output_section* eh_frame_section_; |
| 153 | // The .eh_frame section data. |
| 154 | const Eh_frame* eh_frame_data_; |
| 155 | // Data from the FDEs in the .eh_frame sections. |
| 156 | Fde_offsets fde_offsets_; |
| 157 | // Whether we found any .eh_frame sections which we could not |
| 158 | // process. |
| 159 | bool any_unrecognized_eh_frame_sections_; |
| 160 | }; |
| 161 | |
| 162 | // This class holds an FDE. |
| 163 | |
| 164 | class Fde |
| 165 | { |
| 166 | public: |
| 167 | Fde(Relobj* object, unsigned int shndx, section_offset_type input_offset, |
| 168 | const unsigned char* contents, size_t length) |
| 169 | : object_(object), |
| 170 | contents_(reinterpret_cast<const char*>(contents), length) |
| 171 | { |
| 172 | this->u_.from_object.shndx = shndx; |
| 173 | this->u_.from_object.input_offset = input_offset; |
| 174 | } |
| 175 | |
| 176 | // Create an FDE associated with a PLT. |
| 177 | Fde(Output_data* plt, const unsigned char* contents, size_t length, |
| 178 | bool post_map) |
| 179 | : object_(NULL), |
| 180 | contents_(reinterpret_cast<const char*>(contents), length) |
| 181 | { |
| 182 | this->u_.from_linker.plt = plt; |
| 183 | this->u_.from_linker.post_map = post_map; |
| 184 | } |
| 185 | |
| 186 | // Return the length of this FDE. Add 4 for the length and 4 for |
| 187 | // the offset to the CIE. |
| 188 | size_t |
| 189 | length() const |
| 190 | { return this->contents_.length() + 8; } |
| 191 | |
| 192 | // Add a mapping for this FDE to MERGE_MAP, so that relocations |
| 193 | // against the FDE are applied to right part of the output file. |
| 194 | void |
| 195 | add_mapping(section_offset_type output_offset, Merge_map* merge_map) const |
| 196 | { |
| 197 | if (this->object_ != NULL) |
| 198 | merge_map->add_mapping(this->object_, this->u_.from_object.shndx, |
| 199 | this->u_.from_object.input_offset, this->length(), |
| 200 | output_offset); |
| 201 | } |
| 202 | |
| 203 | // Return whether this FDE was added after merge mapping. |
| 204 | bool |
| 205 | post_map() |
| 206 | { return this->object_ == NULL && this->u_.from_linker.post_map; } |
| 207 | |
| 208 | // Write the FDE to OVIEW starting at OFFSET. FDE_ENCODING is the |
| 209 | // encoding, from the CIE. Round up the bytes to ADDRALIGN if |
| 210 | // necessary. ADDRESS is the virtual address of OVIEW. Record the |
| 211 | // FDE in EH_FRAME_HDR. Return the new offset. |
| 212 | template<int size, bool big_endian> |
| 213 | section_offset_type |
| 214 | write(unsigned char* oview, section_offset_type offset, |
| 215 | uint64_t address, unsigned int addralign, |
| 216 | section_offset_type cie_offset, unsigned char fde_encoding, |
| 217 | Eh_frame_hdr* eh_frame_hdr); |
| 218 | |
| 219 | private: |
| 220 | // The object in which this FDE was seen. This will be NULL for a |
| 221 | // linker generated FDE. |
| 222 | Relobj* object_; |
| 223 | union |
| 224 | { |
| 225 | // These fields are used if the FDE is from an input object (the |
| 226 | // object_ field is not NULL). |
| 227 | struct |
| 228 | { |
| 229 | // Input section index for this FDE. |
| 230 | unsigned int shndx; |
| 231 | // Offset within the input section for this FDE. |
| 232 | section_offset_type input_offset; |
| 233 | } from_object; |
| 234 | // This field is used if the FDE is generated by the linker (the |
| 235 | // object_ field is NULL). |
| 236 | struct |
| 237 | { |
| 238 | // The only linker generated FDEs are for PLT sections, and this |
| 239 | // points to the PLT section. |
| 240 | Output_data* plt; |
| 241 | // Set if the FDE was added after merge mapping. |
| 242 | bool post_map; |
| 243 | } from_linker; |
| 244 | } u_; |
| 245 | // FDE data. |
| 246 | std::string contents_; |
| 247 | }; |
| 248 | |
| 249 | // A FDE plus some info from a CIE to allow later writing of the FDE. |
| 250 | |
| 251 | struct Post_fde |
| 252 | { |
| 253 | Post_fde(Fde* f, section_offset_type cie_off, unsigned char encoding) |
| 254 | : fde(f), cie_offset(cie_off), fde_encoding(encoding) |
| 255 | { } |
| 256 | |
| 257 | Fde* fde; |
| 258 | section_offset_type cie_offset; |
| 259 | unsigned char fde_encoding; |
| 260 | }; |
| 261 | |
| 262 | typedef std::vector<Post_fde> Post_fdes; |
| 263 | |
| 264 | // This class holds a CIE. |
| 265 | |
| 266 | class Cie |
| 267 | { |
| 268 | public: |
| 269 | Cie(Relobj* object, unsigned int shndx, section_offset_type input_offset, |
| 270 | unsigned char fde_encoding, const char* personality_name, |
| 271 | const unsigned char* contents, size_t length) |
| 272 | : object_(object), |
| 273 | shndx_(shndx), |
| 274 | input_offset_(input_offset), |
| 275 | fde_encoding_(fde_encoding), |
| 276 | personality_name_(personality_name), |
| 277 | fdes_(), |
| 278 | contents_(reinterpret_cast<const char*>(contents), length) |
| 279 | { } |
| 280 | |
| 281 | ~Cie(); |
| 282 | |
| 283 | // We permit copying a CIE when there are no FDEs. This is |
| 284 | // convenient in the code which creates them. |
| 285 | Cie(const Cie& cie) |
| 286 | : object_(cie.object_), |
| 287 | shndx_(cie.shndx_), |
| 288 | input_offset_(cie.input_offset_), |
| 289 | fde_encoding_(cie.fde_encoding_), |
| 290 | personality_name_(cie.personality_name_), |
| 291 | fdes_(), |
| 292 | contents_(cie.contents_) |
| 293 | { gold_assert(cie.fdes_.empty()); } |
| 294 | |
| 295 | // Add an FDE associated with this CIE. |
| 296 | void |
| 297 | add_fde(Fde* fde) |
| 298 | { this->fdes_.push_back(fde); } |
| 299 | |
| 300 | // Return the number of FDEs. |
| 301 | unsigned int |
| 302 | fde_count() const |
| 303 | { return this->fdes_.size(); } |
| 304 | |
| 305 | // Set the output offset of this CIE to OUTPUT_OFFSET. It will be |
| 306 | // followed by all its FDEs. ADDRALIGN is the required address |
| 307 | // alignment, typically 4 or 8. This updates MERGE_MAP with the |
| 308 | // mapping. It returns the new output offset. |
| 309 | section_offset_type |
| 310 | set_output_offset(section_offset_type output_offset, unsigned int addralign, |
| 311 | Merge_map*); |
| 312 | |
| 313 | // Write the CIE to OVIEW starting at OFFSET. Round up the bytes to |
| 314 | // ADDRALIGN. ADDRESS is the virtual address of OVIEW. |
| 315 | // EH_FRAME_HDR is the exception frame header for FDE recording. |
| 316 | // POST_FDES stashes FDEs created after mappings were done, for later |
| 317 | // writing. Return the new offset. |
| 318 | template<int size, bool big_endian> |
| 319 | section_offset_type |
| 320 | write(unsigned char* oview, section_offset_type offset, uint64_t address, |
| 321 | unsigned int addralign, Eh_frame_hdr* eh_frame_hdr, |
| 322 | Post_fdes* post_fdes); |
| 323 | |
| 324 | friend bool operator<(const Cie&, const Cie&); |
| 325 | friend bool operator==(const Cie&, const Cie&); |
| 326 | |
| 327 | private: |
| 328 | // The class is not assignable. |
| 329 | Cie& operator=(const Cie&); |
| 330 | |
| 331 | // The object in which this CIE was first seen. This will be NULL |
| 332 | // for a linker generated CIE. |
| 333 | Relobj* object_; |
| 334 | // Input section index for this CIE. This will be 0 for a linker |
| 335 | // generated CIE. |
| 336 | unsigned int shndx_; |
| 337 | // Offset within the input section for this CIE. This will be 0 for |
| 338 | // a linker generated CIE. |
| 339 | section_offset_type input_offset_; |
| 340 | // The encoding of the FDE. This is a DW_EH_PE code. |
| 341 | unsigned char fde_encoding_; |
| 342 | // The name of the personality routine. This will be the name of a |
| 343 | // global symbol, or will be the empty string. |
| 344 | std::string personality_name_; |
| 345 | // List of FDEs. |
| 346 | std::vector<Fde*> fdes_; |
| 347 | // CIE data. |
| 348 | std::string contents_; |
| 349 | }; |
| 350 | |
| 351 | extern bool operator<(const Cie&, const Cie&); |
| 352 | extern bool operator==(const Cie&, const Cie&); |
| 353 | |
| 354 | // This class manages .eh_frame sections. It discards duplicate |
| 355 | // exception information. |
| 356 | |
| 357 | class Eh_frame : public Output_section_data |
| 358 | { |
| 359 | public: |
| 360 | Eh_frame(); |
| 361 | |
| 362 | // Record the associated Eh_frame_hdr, if any. |
| 363 | void |
| 364 | set_eh_frame_hdr(Eh_frame_hdr* hdr) |
| 365 | { this->eh_frame_hdr_ = hdr; } |
| 366 | |
| 367 | // Add the input section SHNDX in OBJECT. SYMBOLS is the contents |
| 368 | // of the symbol table section (size SYMBOLS_SIZE), SYMBOL_NAMES is |
| 369 | // the symbol names section (size SYMBOL_NAMES_SIZE). RELOC_SHNDX |
| 370 | // is the relocation section if any (0 for none, -1U for multiple). |
| 371 | // RELOC_TYPE is the type of the relocation section if any. This |
| 372 | // returns whether the section was incorporated into the .eh_frame |
| 373 | // data. |
| 374 | template<int size, bool big_endian> |
| 375 | bool |
| 376 | add_ehframe_input_section(Sized_relobj_file<size, big_endian>* object, |
| 377 | const unsigned char* symbols, |
| 378 | section_size_type symbols_size, |
| 379 | const unsigned char* symbol_names, |
| 380 | section_size_type symbol_names_size, |
| 381 | unsigned int shndx, unsigned int reloc_shndx, |
| 382 | unsigned int reloc_type); |
| 383 | |
| 384 | // Add a CIE and an FDE for a PLT section, to permit unwinding |
| 385 | // through a PLT. The FDE data should start with 8 bytes of zero, |
| 386 | // which will be replaced by a 4 byte PC relative reference to the |
| 387 | // address of PLT and a 4 byte size of PLT. |
| 388 | void |
| 389 | add_ehframe_for_plt(Output_data* plt, const unsigned char* cie_data, |
| 390 | size_t cie_length, const unsigned char* fde_data, |
| 391 | size_t fde_length); |
| 392 | |
| 393 | // Return the number of FDEs. |
| 394 | unsigned int |
| 395 | fde_count() const; |
| 396 | |
| 397 | protected: |
| 398 | // Set the final data size. |
| 399 | void |
| 400 | set_final_data_size(); |
| 401 | |
| 402 | // Return the output address for an input address. |
| 403 | bool |
| 404 | do_output_offset(const Relobj*, unsigned int shndx, |
| 405 | section_offset_type offset, |
| 406 | section_offset_type* poutput) const; |
| 407 | |
| 408 | // Return whether this is the merge section for an input section. |
| 409 | bool |
| 410 | do_is_merge_section_for(const Relobj*, unsigned int shndx) const; |
| 411 | |
| 412 | // Write the data to the file. |
| 413 | void |
| 414 | do_write(Output_file*); |
| 415 | |
| 416 | // Write to a map file. |
| 417 | void |
| 418 | do_print_to_mapfile(Mapfile* mapfile) const |
| 419 | { mapfile->print_output_data(this, _("** eh_frame")); } |
| 420 | |
| 421 | private: |
| 422 | // The comparison routine for the CIE map. |
| 423 | struct Cie_less |
| 424 | { |
| 425 | bool |
| 426 | operator()(const Cie* cie1, const Cie* cie2) const |
| 427 | { return *cie1 < *cie2; } |
| 428 | }; |
| 429 | |
| 430 | // A set of unique CIEs. |
| 431 | typedef std::set<Cie*, Cie_less> Cie_offsets; |
| 432 | |
| 433 | // A list of unmergeable CIEs. |
| 434 | typedef std::vector<Cie*> Unmergeable_cie_offsets; |
| 435 | |
| 436 | // A mapping from offsets to CIEs. This is used while reading an |
| 437 | // input section. |
| 438 | typedef std::map<uint64_t, Cie*> Offsets_to_cie; |
| 439 | |
| 440 | // A list of CIEs, and a bool indicating whether the CIE is |
| 441 | // mergeable. |
| 442 | typedef std::vector<std::pair<Cie*, bool> > New_cies; |
| 443 | |
| 444 | // Skip an LEB128. |
| 445 | static bool |
| 446 | skip_leb128(const unsigned char**, const unsigned char*); |
| 447 | |
| 448 | // The implementation of add_ehframe_input_section. |
| 449 | template<int size, bool big_endian> |
| 450 | bool |
| 451 | do_add_ehframe_input_section(Sized_relobj_file<size, big_endian>* object, |
| 452 | const unsigned char* symbols, |
| 453 | section_size_type symbols_size, |
| 454 | const unsigned char* symbol_names, |
| 455 | section_size_type symbol_names_size, |
| 456 | unsigned int shndx, |
| 457 | unsigned int reloc_shndx, |
| 458 | unsigned int reloc_type, |
| 459 | const unsigned char* pcontents, |
| 460 | section_size_type contents_len, |
| 461 | New_cies*); |
| 462 | |
| 463 | // Read a CIE. |
| 464 | template<int size, bool big_endian> |
| 465 | bool |
| 466 | read_cie(Sized_relobj_file<size, big_endian>* object, |
| 467 | unsigned int shndx, |
| 468 | const unsigned char* symbols, |
| 469 | section_size_type symbols_size, |
| 470 | const unsigned char* symbol_names, |
| 471 | section_size_type symbol_names_size, |
| 472 | const unsigned char* pcontents, |
| 473 | const unsigned char* pcie, |
| 474 | const unsigned char* pcieend, |
| 475 | Track_relocs<size, big_endian>* relocs, |
| 476 | Offsets_to_cie* cies, |
| 477 | New_cies* new_cies); |
| 478 | |
| 479 | // Read an FDE. |
| 480 | template<int size, bool big_endian> |
| 481 | bool |
| 482 | read_fde(Sized_relobj_file<size, big_endian>* object, |
| 483 | unsigned int shndx, |
| 484 | const unsigned char* symbols, |
| 485 | section_size_type symbols_size, |
| 486 | const unsigned char* pcontents, |
| 487 | unsigned int offset, |
| 488 | const unsigned char* pfde, |
| 489 | const unsigned char* pfdeend, |
| 490 | Track_relocs<size, big_endian>* relocs, |
| 491 | Offsets_to_cie* cies); |
| 492 | |
| 493 | // Template version of write function. |
| 494 | template<int size, bool big_endian> |
| 495 | void |
| 496 | do_sized_write(unsigned char* oview); |
| 497 | |
| 498 | // The exception frame header, if any. |
| 499 | Eh_frame_hdr* eh_frame_hdr_; |
| 500 | // A mapping from all unique CIEs to their offset in the output |
| 501 | // file. |
| 502 | Cie_offsets cie_offsets_; |
| 503 | // A mapping from unmergeable CIEs to their offset in the output |
| 504 | // file. |
| 505 | Unmergeable_cie_offsets unmergeable_cie_offsets_; |
| 506 | // A mapping from input sections to the output section. |
| 507 | Merge_map merge_map_; |
| 508 | // Whether we have created the mappings to the output section. |
| 509 | bool mappings_are_done_; |
| 510 | // The final data size. This is only set if mappings_are_done_ is |
| 511 | // true. |
| 512 | section_size_type final_data_size_; |
| 513 | }; |
| 514 | |
| 515 | } // End namespace gold. |
| 516 | |
| 517 | #endif // !defined(GOLD_EHFRAME_H) |