+// During safe icf (--icf=safe), only fold functions that are ctors or dtors.
+// This function returns true if the section name is that of a ctor or a dtor.
+
+static bool
+is_function_ctor_or_dtor(const std::string& section_name)
+{
+ const char* mangled_func_name = strrchr(section_name.c_str(), '.');
+ gold_assert(mangled_func_name != NULL);
+ if ((is_prefix_of("._ZN", mangled_func_name)
+ || is_prefix_of("._ZZ", mangled_func_name))
+ && (is_gnu_v3_mangled_ctor(mangled_func_name + 1)
+ || is_gnu_v3_mangled_dtor(mangled_func_name + 1)))
+ {
+ return true;
+ }
+ return false;
+}
+
+// Iterate through the .eh_frame section that has index
+// `ehframe_shndx` in `object`, adding entries to extra_identity_list_
+// that will cause the contents of each FDE and its CIE to be included
+// in the logical ICF identity of the function that the FDE refers to.
+
+bool
+Icf::add_ehframe_links(Relobj* object, unsigned int ehframe_shndx,
+ Reloc_info& relocs)
+{
+ section_size_type contents_len;
+ const unsigned char* pcontents = object->section_contents(ehframe_shndx,
+ &contents_len,
+ false);
+ const unsigned char* p = pcontents;
+ const unsigned char* pend = pcontents + contents_len;
+
+ Sections_reachable_info::iterator it_target = relocs.section_info.begin();
+ Sections_reachable_info::iterator it_target_end = relocs.section_info.end();
+ Offset_info::iterator it_offset = relocs.offset_info.begin();
+ Offset_info::iterator it_offset_end = relocs.offset_info.end();
+
+ // Maps section offset to the length of the CIE defined at that offset.
+ typedef Unordered_map<section_offset_type, section_size_type> Cie_map;
+ Cie_map cies;
+
+ uint32_t (*read_swap_32)(const unsigned char*);
+ if (object->is_big_endian())
+ read_swap_32 = &elfcpp::Swap<32, true>::readval;
+ else
+ read_swap_32 = &elfcpp::Swap<32, false>::readval;
+
+ // TODO: The logic for parsing the CIE/FDE framing is copied from
+ // Eh_frame::do_add_ehframe_input_section() and might want to be
+ // factored into a shared helper function.
+ while (p < pend)
+ {
+ if (pend - p < 4)
+ return false;
+
+ unsigned int len = read_swap_32(p);
+ p += 4;
+ if (len == 0)
+ {
+ // We should only find a zero-length entry at the end of the
+ // section.
+ if (p < pend)
+ return false;
+ break;
+ }
+ // We don't support a 64-bit .eh_frame.
+ if (len == 0xffffffff)
+ return false;
+ if (static_cast<unsigned int>(pend - p) < len)
+ return false;
+
+ const unsigned char* const pentend = p + len;
+
+ if (pend - p < 4)
+ return false;
+
+ unsigned int id = read_swap_32(p);
+ p += 4;
+
+ if (id == 0)
+ {
+ // CIE.
+ cies.insert(std::make_pair(p - pcontents, len - 4));
+ }
+ else
+ {
+ // FDE.
+ Cie_map::const_iterator it;
+ it = cies.find((p - pcontents) - (id - 4));
+ if (it == cies.end())
+ return false;
+
+ // Figure out which section this FDE refers into. The word at `p`
+ // is an address, and we expect to see a relocation there. If not,
+ // this FDE isn't ICF-relevant.
+ while (it_offset != it_offset_end
+ && it_target != it_target_end
+ && static_cast<ptrdiff_t>(*it_offset) < (p - pcontents))
+ {
+ ++it_offset;
+ ++it_target;
+ }
+ if (it_offset != it_offset_end
+ && it_target != it_target_end
+ && static_cast<ptrdiff_t>(*it_offset) == (p - pcontents))
+ {
+ // Found a reloc. Add this FDE and its CIE as extra identity
+ // info for the section it refers to.
+ Extra_identity_info rec_fde = {Section_id(object, ehframe_shndx),
+ p - pcontents, len - 4};
+ Extra_identity_info rec_cie = {Section_id(object, ehframe_shndx),
+ it->first, it->second};
+ extra_identity_list_.insert(std::make_pair(*it_target, rec_fde));
+ extra_identity_list_.insert(std::make_pair(*it_target, rec_cie));
+ }
+ }
+
+ p = pentend;
+ }
+
+ return true;
+}