17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
55aefb655Srie * Common Development and Distribution License (the "License").
65aefb655Srie * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
215aefb655Srie
227c478bd9Sstevel@tonic-gate /*
231007fd6fSAli Bahrami * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24cffcfaeeSAlexander Eremin * Copyright 2014 Nexenta Systems, Inc.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #include <string.h>
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sgs.h>
317c478bd9Sstevel@tonic-gate #include <debug.h>
327c478bd9Sstevel@tonic-gate #include <_libld.h>
337c478bd9Sstevel@tonic-gate #include <dwarf.h>
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate * A EH_FRAME_HDR consists of the following:
387c478bd9Sstevel@tonic-gate *
397c478bd9Sstevel@tonic-gate * Encoding Field
407c478bd9Sstevel@tonic-gate * --------------------------------
417c478bd9Sstevel@tonic-gate * unsigned byte version
427c478bd9Sstevel@tonic-gate * unsigned byte eh_frame_ptr_enc
437c478bd9Sstevel@tonic-gate * unsigned byte fde_count_enc
447c478bd9Sstevel@tonic-gate * unsigned byte table_enc
457c478bd9Sstevel@tonic-gate * encoded eh_frame_ptr
467c478bd9Sstevel@tonic-gate * encoded fde_count
477c478bd9Sstevel@tonic-gate * [ binary search table ]
487c478bd9Sstevel@tonic-gate *
497c478bd9Sstevel@tonic-gate * The binary search table entries each consists of:
507c478bd9Sstevel@tonic-gate *
517c478bd9Sstevel@tonic-gate * encoded initial_func_loc
527c478bd9Sstevel@tonic-gate * encoded FDE_address
537c478bd9Sstevel@tonic-gate *
547c478bd9Sstevel@tonic-gate * The entries in the binary search table are sorted
557c478bd9Sstevel@tonic-gate * in a increasing order by the initial location.
567c478bd9Sstevel@tonic-gate *
577c478bd9Sstevel@tonic-gate *
587c478bd9Sstevel@tonic-gate * version
597c478bd9Sstevel@tonic-gate *
607c478bd9Sstevel@tonic-gate * Version of the .eh_frame_hdr format. This value shall be 1.
617c478bd9Sstevel@tonic-gate *
627c478bd9Sstevel@tonic-gate * eh_frame_ptr_enc
637c478bd9Sstevel@tonic-gate *
647c478bd9Sstevel@tonic-gate * The encoding format of the eh_frame_ptr field. For shared
657c478bd9Sstevel@tonic-gate * libraries the encoding must be
667c478bd9Sstevel@tonic-gate * DW_EH_PE_sdata4|DW_EH_PE_pcrel or
677c478bd9Sstevel@tonic-gate * DW_EH_PE_sdata4|DW_EH_PE_datarel.
687c478bd9Sstevel@tonic-gate *
697c478bd9Sstevel@tonic-gate *
707c478bd9Sstevel@tonic-gate * fde_count_enc
717c478bd9Sstevel@tonic-gate *
727c478bd9Sstevel@tonic-gate * The encoding format of the fde_count field. A value of
737c478bd9Sstevel@tonic-gate * DW_EH_PE_omit indicates the binary search table is not
747c478bd9Sstevel@tonic-gate * present.
757c478bd9Sstevel@tonic-gate *
767c478bd9Sstevel@tonic-gate * table_enc
777c478bd9Sstevel@tonic-gate *
787c478bd9Sstevel@tonic-gate * The encoding format of the entries in the binary search
797c478bd9Sstevel@tonic-gate * table. A value of DW_EH_PE_omit indicates the binary search
807c478bd9Sstevel@tonic-gate * table is not present. For shared libraries the encoding
817c478bd9Sstevel@tonic-gate * must be DW_EH_PE_sdata4|DW_EH_PE_pcrel or
827c478bd9Sstevel@tonic-gate * DW_EH_PE_sdata4|DW_EH_PE_datarel.
837c478bd9Sstevel@tonic-gate *
847c478bd9Sstevel@tonic-gate *
857c478bd9Sstevel@tonic-gate * eh_frame_ptr
867c478bd9Sstevel@tonic-gate *
877c478bd9Sstevel@tonic-gate * The encoded value of the pointer to the start of the
887c478bd9Sstevel@tonic-gate * .eh_frame section.
897c478bd9Sstevel@tonic-gate *
907c478bd9Sstevel@tonic-gate * fde_count
917c478bd9Sstevel@tonic-gate *
927c478bd9Sstevel@tonic-gate * The encoded value of the count of entries in the binary
937c478bd9Sstevel@tonic-gate * search table.
947c478bd9Sstevel@tonic-gate *
957c478bd9Sstevel@tonic-gate * binary search table
967c478bd9Sstevel@tonic-gate *
977c478bd9Sstevel@tonic-gate * A binary search table containing fde_count entries. Each
987c478bd9Sstevel@tonic-gate * entry of the table consist of two encoded values, the
997c478bd9Sstevel@tonic-gate * initial location of the function to which an FDE applies,
1007c478bd9Sstevel@tonic-gate * and the address of the FDE. The entries are sorted in an
1017c478bd9Sstevel@tonic-gate * increasing order by the initial location value.
1027c478bd9Sstevel@tonic-gate *
1037c478bd9Sstevel@tonic-gate */
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate * EH_FRAME sections
1087c478bd9Sstevel@tonic-gate * =================
1097c478bd9Sstevel@tonic-gate *
1107c478bd9Sstevel@tonic-gate * The call frame information needed for unwinding the stack is output in
1117e16fca0SAli Bahrami * an ELF section(s) of type SHT_AMD64_UNWIND (amd64) or SHT_PROGBITS (other).
1127e16fca0SAli Bahrami * In the simplest case there will be one such section per object file and it
1137e16fca0SAli Bahrami * will be named ".eh_frame". An .eh_frame section consists of one or more
1147c478bd9Sstevel@tonic-gate * subsections. Each subsection contains a CIE (Common Information Entry)
1157c478bd9Sstevel@tonic-gate * followed by varying number of FDEs (Frame Descriptor Entry). A FDE
1167c478bd9Sstevel@tonic-gate * corresponds to an explicit or compiler generated function in a
1177c478bd9Sstevel@tonic-gate * compilation unit, all FDEs can access the CIE that begins their
1187c478bd9Sstevel@tonic-gate * subsection for data.
1197c478bd9Sstevel@tonic-gate *
1207e16fca0SAli Bahrami * If an object file contains C++ template instantiations, there shall be
1217c478bd9Sstevel@tonic-gate * a separate CIE immediately preceding each FDE corresponding to an
1227c478bd9Sstevel@tonic-gate * instantiation.
1237c478bd9Sstevel@tonic-gate *
1247c478bd9Sstevel@tonic-gate * Using the preferred encoding specified below, the .eh_frame section can
1257c478bd9Sstevel@tonic-gate * be entirely resolved at link time and thus can become part of the
1267c478bd9Sstevel@tonic-gate * text segment.
1277c478bd9Sstevel@tonic-gate *
1287c478bd9Sstevel@tonic-gate * .eh_frame Section Layout
1297c478bd9Sstevel@tonic-gate * ------------------------
1307c478bd9Sstevel@tonic-gate *
1317c478bd9Sstevel@tonic-gate * EH_PE encoding below refers to the pointer encoding as specified in the
1327c478bd9Sstevel@tonic-gate * enhanced LSB Chapter 7 for Eh_Frame_Hdr.
1337c478bd9Sstevel@tonic-gate *
1347c478bd9Sstevel@tonic-gate * Common Information Entry (CIE)
1357c478bd9Sstevel@tonic-gate * ------------------------------
1367c478bd9Sstevel@tonic-gate * CIE has the following format:
1377c478bd9Sstevel@tonic-gate *
1387c478bd9Sstevel@tonic-gate * Length
1397c478bd9Sstevel@tonic-gate * in
1407c478bd9Sstevel@tonic-gate * Field Byte Description
1417c478bd9Sstevel@tonic-gate * ----- ------ -----------
1427c478bd9Sstevel@tonic-gate * 1. Length 4 Length of CIE (not including
1437c478bd9Sstevel@tonic-gate * this 4-byte field).
1447c478bd9Sstevel@tonic-gate *
1457c478bd9Sstevel@tonic-gate * 2. CIE id 4 Value Zero (0) for .eh_frame
1467c478bd9Sstevel@tonic-gate * (used to distinguish CIEs and
1477c478bd9Sstevel@tonic-gate * FDEs when scanning the section)
1487c478bd9Sstevel@tonic-gate *
1497c478bd9Sstevel@tonic-gate * 3. Version 1 Value One (1)
1507c478bd9Sstevel@tonic-gate *
1517c478bd9Sstevel@tonic-gate * 4. CIE Augmentation string Null-terminated string with legal
1527c478bd9Sstevel@tonic-gate * values being "" or 'z' optionally
15357ef7aa9SRod Evans * followed by single occurrences of
1547c478bd9Sstevel@tonic-gate * 'P', 'L', or 'R' in any order.
1557c478bd9Sstevel@tonic-gate * String The presence of character(s) in the
1567c478bd9Sstevel@tonic-gate * string dictates the content of
1577c478bd9Sstevel@tonic-gate * field 8, the Augmentation Section.
1587c478bd9Sstevel@tonic-gate * Each character has one or two
1597c478bd9Sstevel@tonic-gate * associated operands in the AS.
1607c478bd9Sstevel@tonic-gate * Operand order depends on
1617c478bd9Sstevel@tonic-gate * position in the string ('z' must
1627c478bd9Sstevel@tonic-gate * be first).
1637c478bd9Sstevel@tonic-gate *
1647c478bd9Sstevel@tonic-gate * 5. Code Align Factor uleb128 To be multiplied with the
1657c478bd9Sstevel@tonic-gate * "Advance Location" instructions in
1667c478bd9Sstevel@tonic-gate * the Call Frame Instructions
1677c478bd9Sstevel@tonic-gate *
1687c478bd9Sstevel@tonic-gate * 6. Data Align Factor sleb128 To be multiplied with all offset
1697c478bd9Sstevel@tonic-gate * in the Call Frame Instructions
1707c478bd9Sstevel@tonic-gate *
171ba2be530Sab * 7. Ret Address Reg 1 A "virtual" register representation
1727c478bd9Sstevel@tonic-gate * of the return address. In Dwarf V2,
1737c478bd9Sstevel@tonic-gate * this is a byte, otherwise it is
1747c478bd9Sstevel@tonic-gate * uleb128. It is a byte in gcc 3.3.x
1757c478bd9Sstevel@tonic-gate *
1767c478bd9Sstevel@tonic-gate * 8. Optional CIE varying Present if Augmentation String in
1777c478bd9Sstevel@tonic-gate * Augmentation Section field 4 is not 0.
1787c478bd9Sstevel@tonic-gate *
1797c478bd9Sstevel@tonic-gate * z:
1808b891ae8SRichard Lowe * size uleb128 Length of the remainder of the
1818b891ae8SRichard Lowe * Augmentation Section
1827c478bd9Sstevel@tonic-gate *
1837c478bd9Sstevel@tonic-gate * P:
1848b891ae8SRichard Lowe * personality_enc 1 Encoding specifier - preferred
1857c478bd9Sstevel@tonic-gate * value is a pc-relative, signed
1867c478bd9Sstevel@tonic-gate * 4-byte
1877c478bd9Sstevel@tonic-gate *
1887c478bd9Sstevel@tonic-gate *
1897c478bd9Sstevel@tonic-gate * personality routine (encoded) Encoded pointer to personality
1907c478bd9Sstevel@tonic-gate * routine (actually to the PLT
1917c478bd9Sstevel@tonic-gate * entry for the personality
1927c478bd9Sstevel@tonic-gate * routine)
1937c478bd9Sstevel@tonic-gate * R:
1948b891ae8SRichard Lowe * code_enc 1 Non-default encoding for the
1957c478bd9Sstevel@tonic-gate * code-pointers (FDE members
1967c478bd9Sstevel@tonic-gate * "initial_location" and "address_range"
1977c478bd9Sstevel@tonic-gate * and the operand for DW_CFA_set_loc)
1987c478bd9Sstevel@tonic-gate * - preferred value is pc-relative,
1997c478bd9Sstevel@tonic-gate * signed 4-byte.
2007c478bd9Sstevel@tonic-gate * L:
2018b891ae8SRichard Lowe * lsda_enc 1 FDE augmentation bodies may contain
2027c478bd9Sstevel@tonic-gate * LSDA pointers. If so they are
2037c478bd9Sstevel@tonic-gate * encoded as specified here -
2047c478bd9Sstevel@tonic-gate * preferred value is pc-relative,
2057c478bd9Sstevel@tonic-gate * signed 4-byte possibly indirect
2067c478bd9Sstevel@tonic-gate * thru a GOT entry.
2077c478bd9Sstevel@tonic-gate *
2087c478bd9Sstevel@tonic-gate *
2097c478bd9Sstevel@tonic-gate * 9. Optional Call Frame varying
2107c478bd9Sstevel@tonic-gate * Instructions
2117c478bd9Sstevel@tonic-gate *
2127c478bd9Sstevel@tonic-gate * The size of the optional call frame instruction area must be computed
2137c478bd9Sstevel@tonic-gate * based on the overall size and the offset reached while scanning the
2147c478bd9Sstevel@tonic-gate * preceding fields of the CIE.
2157c478bd9Sstevel@tonic-gate *
2167c478bd9Sstevel@tonic-gate *
2177c478bd9Sstevel@tonic-gate * Frame Descriptor Entry (FDE)
2187c478bd9Sstevel@tonic-gate * ----------------------------
2197c478bd9Sstevel@tonic-gate * FDE has the following format:
2207c478bd9Sstevel@tonic-gate *
2217c478bd9Sstevel@tonic-gate * Length
2227c478bd9Sstevel@tonic-gate * in
2237c478bd9Sstevel@tonic-gate * Field Byte Description
2247c478bd9Sstevel@tonic-gate * ----- ------ -----------
2257c478bd9Sstevel@tonic-gate * 1. Length 4 Length of remainder of this FDE
2267c478bd9Sstevel@tonic-gate *
2277c478bd9Sstevel@tonic-gate * 2. CIE Pointer 4 Distance from this field to the
2287c478bd9Sstevel@tonic-gate * nearest preceding CIE
2297c478bd9Sstevel@tonic-gate * (uthe value is subtracted from the
2307c478bd9Sstevel@tonic-gate * current address). This value
2317c478bd9Sstevel@tonic-gate * can never be zero and thus can
2327c478bd9Sstevel@tonic-gate * be used to distinguish CIE's and
2337c478bd9Sstevel@tonic-gate * FDE's when scanning the
2347c478bd9Sstevel@tonic-gate * .eh_frame section
2357c478bd9Sstevel@tonic-gate *
2367c478bd9Sstevel@tonic-gate * 3. Initial Location varying Reference to the function code
2377c478bd9Sstevel@tonic-gate * corresponding to this FDE.
2387c478bd9Sstevel@tonic-gate * If 'R' is missing from the CIE
2397c478bd9Sstevel@tonic-gate * Augmentation String, the field is an
2407c478bd9Sstevel@tonic-gate * 8-byte absolute pointer. Otherwise,
2417c478bd9Sstevel@tonic-gate * the corresponding EH_PE encoding in the
2427c478bd9Sstevel@tonic-gate * CIE Augmentation Section is used to
2437c478bd9Sstevel@tonic-gate * interpret the reference.
2447c478bd9Sstevel@tonic-gate *
2457c478bd9Sstevel@tonic-gate * 4. Address Range varying Size of the function code corresponding
2467c478bd9Sstevel@tonic-gate * to this FDE.
2477c478bd9Sstevel@tonic-gate * If 'R' is missing from the CIE
2487c478bd9Sstevel@tonic-gate * Augmentation String, the field is an
2497c478bd9Sstevel@tonic-gate * 8-byte unsigned number. Otherwise,
2507c478bd9Sstevel@tonic-gate * the size is determined by the
2517c478bd9Sstevel@tonic-gate * corresponding EH_PE encoding in the
2527c478bd9Sstevel@tonic-gate * CIE Augmentation Section (the
2537c478bd9Sstevel@tonic-gate * value is always absolute).
2547c478bd9Sstevel@tonic-gate *
2557c478bd9Sstevel@tonic-gate * 5. Optional FDE varying present if CIE augmentation
2567c478bd9Sstevel@tonic-gate * Augmentation Section string is non-empty.
2577c478bd9Sstevel@tonic-gate *
2587c478bd9Sstevel@tonic-gate *
2597c478bd9Sstevel@tonic-gate * 'z':
2608b891ae8SRichard Lowe * length uleb128 length of the remainder of the
2617c478bd9Sstevel@tonic-gate * FDE augmentation section
2627c478bd9Sstevel@tonic-gate *
2637c478bd9Sstevel@tonic-gate *
2647c478bd9Sstevel@tonic-gate * 'L' (and length > 0):
2657c478bd9Sstevel@tonic-gate * LSDA varying LSDA pointer, encoded in the
2667c478bd9Sstevel@tonic-gate * format specified by the
2677c478bd9Sstevel@tonic-gate * corresponding operand in the CIE's
2687c478bd9Sstevel@tonic-gate * augmentation body.
2697c478bd9Sstevel@tonic-gate *
2707c478bd9Sstevel@tonic-gate * 6. Optional Call varying
2717c478bd9Sstevel@tonic-gate * Frame Instructions
2727c478bd9Sstevel@tonic-gate *
2737c478bd9Sstevel@tonic-gate * The size of the optional call frame instruction area must be computed
2747c478bd9Sstevel@tonic-gate * based on the overall size and the offset reached while scanning the
2757c478bd9Sstevel@tonic-gate * preceding fields of the FDE.
2767c478bd9Sstevel@tonic-gate *
2777c478bd9Sstevel@tonic-gate * The overall size of a .eh_frame section is given in the ELF section
2787c478bd9Sstevel@tonic-gate * header. The only way to determine the number of entries is to scan
2797c478bd9Sstevel@tonic-gate * the section till the end and count.
2807c478bd9Sstevel@tonic-gate *
2817c478bd9Sstevel@tonic-gate */
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate
2867e16fca0SAli Bahrami static uint_t
extract_uint(const uchar_t * data,uint64_t * ndx,int do_swap)2877e16fca0SAli Bahrami extract_uint(const uchar_t *data, uint64_t *ndx, int do_swap)
2887e16fca0SAli Bahrami {
2897e16fca0SAli Bahrami uint_t r;
2907e16fca0SAli Bahrami uchar_t *p = (uchar_t *)&r;
2917e16fca0SAli Bahrami
2927e16fca0SAli Bahrami data += *ndx;
2937e16fca0SAli Bahrami if (do_swap)
2947e16fca0SAli Bahrami UL_ASSIGN_BSWAP_WORD(p, data);
2957e16fca0SAli Bahrami else
2967e16fca0SAli Bahrami UL_ASSIGN_WORD(p, data);
2977e16fca0SAli Bahrami
2987e16fca0SAli Bahrami (*ndx) += 4;
2997e16fca0SAli Bahrami return (r);
3007e16fca0SAli Bahrami }
3017e16fca0SAli Bahrami
3027c478bd9Sstevel@tonic-gate /*
3037e16fca0SAli Bahrami * Create an unwind header (.eh_frame_hdr) output section.
3047e16fca0SAli Bahrami * The section is created and space reserved, but the data
3057e16fca0SAli Bahrami * is not copied into place. That is done by a later call
3067e16fca0SAli Bahrami * to ld_unwind_populate(), after active relocations have been
3077e16fca0SAli Bahrami * processed.
30840e53e87SAli Bahrami *
30940e53e87SAli Bahrami * When GNU linkonce processing is in effect, we can end up in a situation
31040e53e87SAli Bahrami * where the FDEs related to discarded sections remain in the eh_frame
31140e53e87SAli Bahrami * section. Ideally, we would remove these dead entries from eh_frame.
31240e53e87SAli Bahrami * However, that optimization has not yet been implemented. In the current
31340e53e87SAli Bahrami * implementation, the number of dead FDEs cannot be determined until
31440e53e87SAli Bahrami * active relocations are processed, and that processing follows the
31540e53e87SAli Bahrami * call to this function. This means that we are unable to detect dead FDEs
31640e53e87SAli Bahrami * here, and the section created by this routine is sized for maximum case
31740e53e87SAli Bahrami * where all FDEs are valid.
3187c478bd9Sstevel@tonic-gate */
3197c478bd9Sstevel@tonic-gate uintptr_t
ld_unwind_make_hdr(Ofl_desc * ofl)3207e16fca0SAli Bahrami ld_unwind_make_hdr(Ofl_desc *ofl)
3217c478bd9Sstevel@tonic-gate {
3227e16fca0SAli Bahrami int bswap = (ofl->ofl_flags1 & FLG_OF1_ENCDIFF) != 0;
32374a8d72aSrie Shdr *shdr;
32474a8d72aSrie Elf_Data *elfdata;
32574a8d72aSrie Is_desc *isp;
32674a8d72aSrie size_t size;
32774a8d72aSrie Xword fde_cnt;
32857ef7aa9SRod Evans Aliste idx1;
32974a8d72aSrie Os_desc *osp;
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate /*
3327c478bd9Sstevel@tonic-gate * we only build a unwind header if we have
33340e53e87SAli Bahrami * some unwind information in the file.
3347c478bd9Sstevel@tonic-gate */
3358b891ae8SRichard Lowe if (aplist_nitems(ofl->ofl_unwind) == 0)
3367c478bd9Sstevel@tonic-gate return (1);
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate /*
3397c478bd9Sstevel@tonic-gate * Allocate and initialize the Elf_Data structure.
3407c478bd9Sstevel@tonic-gate */
341*fb12490aSRichard Lowe if ((elfdata = libld_calloc(1, sizeof (Elf_Data))) == NULL)
3427c478bd9Sstevel@tonic-gate return (S_ERROR);
3437c478bd9Sstevel@tonic-gate elfdata->d_type = ELF_T_BYTE;
3447e16fca0SAli Bahrami elfdata->d_align = ld_targ.t_m.m_word_align;
3455aefb655Srie elfdata->d_version = ofl->ofl_dehdr->e_version;
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate /*
3487c478bd9Sstevel@tonic-gate * Allocate and initialize the Shdr structure.
3497c478bd9Sstevel@tonic-gate */
350*fb12490aSRichard Lowe if ((shdr = libld_calloc(1, sizeof (Shdr))) == NULL)
3517c478bd9Sstevel@tonic-gate return (S_ERROR);
3527e16fca0SAli Bahrami shdr->sh_type = ld_targ.t_m.m_sht_unwind;
3537c478bd9Sstevel@tonic-gate shdr->sh_flags = SHF_ALLOC;
3547e16fca0SAli Bahrami shdr->sh_addralign = ld_targ.t_m.m_word_align;
3557c478bd9Sstevel@tonic-gate shdr->sh_entsize = 0;
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate * Allocate and initialize the Is_desc structure.
3597c478bd9Sstevel@tonic-gate */
360635216b6SRod Evans if ((isp = libld_calloc(1, sizeof (Is_desc))) == NULL)
3617c478bd9Sstevel@tonic-gate return (S_ERROR);
36274a8d72aSrie isp->is_name = MSG_ORIG(MSG_SCN_UNWINDHDR);
36374a8d72aSrie isp->is_shdr = shdr;
36474a8d72aSrie isp->is_indata = elfdata;
3657c478bd9Sstevel@tonic-gate
36669112eddSAli Bahrami if ((ofl->ofl_unwindhdr = ld_place_section(ofl, isp, NULL,
3671dd9d86fSAli Bahrami ld_targ.t_id.id_unwindhdr, NULL)) == (Os_desc *)S_ERROR)
3687c478bd9Sstevel@tonic-gate return (S_ERROR);
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate /*
37174a8d72aSrie * Scan through all of the input Frame information, counting each FDE
37274a8d72aSrie * that requires an index. Each fde_entry gets a corresponding entry
37374a8d72aSrie * in the binary search table.
3747c478bd9Sstevel@tonic-gate */
3757c478bd9Sstevel@tonic-gate fde_cnt = 0;
37657ef7aa9SRod Evans for (APLIST_TRAVERSE(ofl->ofl_unwind, idx1, osp)) {
3771dd9d86fSAli Bahrami Aliste idx2;
3781dd9d86fSAli Bahrami int os_isdescs_idx;
37985213095Srie
3801dd9d86fSAli Bahrami OS_ISDESCS_TRAVERSE(os_isdescs_idx, osp, idx2, isp) {
38185213095Srie uchar_t *data;
38274a8d72aSrie uint64_t off = 0;
3837c478bd9Sstevel@tonic-gate
38474a8d72aSrie data = isp->is_indata->d_buf;
38574a8d72aSrie size = isp->is_indata->d_size;
38674a8d72aSrie
38774a8d72aSrie while (off < size) {
38874a8d72aSrie uint_t length, id;
3897e16fca0SAli Bahrami uint64_t ndx = 0;
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate /*
39285213095Srie * Extract length in lsb format. A zero length
39385213095Srie * indicates that this CIE is a terminator and
39474a8d72aSrie * that processing for unwind information is
39574a8d72aSrie * complete.
3967c478bd9Sstevel@tonic-gate */
3977e16fca0SAli Bahrami length = extract_uint(data + off, &ndx, bswap);
3987e16fca0SAli Bahrami if (length == 0)
39985213095Srie break;
40085213095Srie
4017c478bd9Sstevel@tonic-gate /*
40274a8d72aSrie * Extract CIE id in lsb format.
4037c478bd9Sstevel@tonic-gate */
4047e16fca0SAli Bahrami id = extract_uint(data + off, &ndx, bswap);
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate /*
4077c478bd9Sstevel@tonic-gate * A CIE record has a id of '0', otherwise
4087c478bd9Sstevel@tonic-gate * this is a FDE entry and the 'id' is the
40974a8d72aSrie * CIE pointer.
4107c478bd9Sstevel@tonic-gate */
4117c478bd9Sstevel@tonic-gate if (id == 0) {
4127c478bd9Sstevel@tonic-gate uint_t cieversion;
4137c478bd9Sstevel@tonic-gate cieversion = data[off + ndx];
4147c478bd9Sstevel@tonic-gate ndx += 1;
415ba2be530Sab /* BEGIN CSTYLED */
416cffcfaeeSAlexander Eremin if (cieversion != 1 && cieversion != 3) {
4171007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL,
4187c478bd9Sstevel@tonic-gate MSG_INTL(MSG_UNW_BADCIEVERS),
4197c478bd9Sstevel@tonic-gate isp->is_file->ifl_name,
4205aefb655Srie isp->is_name, off);
4217c478bd9Sstevel@tonic-gate return (S_ERROR);
4227c478bd9Sstevel@tonic-gate }
423ba2be530Sab /* END CSTYLED */
424ba2be530Sab } else {
4257c478bd9Sstevel@tonic-gate fde_cnt++;
426ba2be530Sab }
4277c478bd9Sstevel@tonic-gate off += length + 4;
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate /*
4337c478bd9Sstevel@tonic-gate * section size:
4347c478bd9Sstevel@tonic-gate * byte version +1
4357c478bd9Sstevel@tonic-gate * byte eh_frame_ptr_enc +1
4367c478bd9Sstevel@tonic-gate * byte fde_count_enc +1
4377c478bd9Sstevel@tonic-gate * byte table_enc +1
4387c478bd9Sstevel@tonic-gate * 4 bytes eh_frame_ptr +4
4397c478bd9Sstevel@tonic-gate * 4 bytes fde_count +4
4407c478bd9Sstevel@tonic-gate * [4 bytes] [4bytes] * fde_count ...
4417c478bd9Sstevel@tonic-gate */
4427c478bd9Sstevel@tonic-gate size = 12 + (8 * fde_cnt);
4437c478bd9Sstevel@tonic-gate
444635216b6SRod Evans if ((elfdata->d_buf = libld_calloc(size, 1)) == NULL)
4457c478bd9Sstevel@tonic-gate return (S_ERROR);
4467c478bd9Sstevel@tonic-gate elfdata->d_size = size;
4477c478bd9Sstevel@tonic-gate shdr->sh_size = (Xword)size;
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate return (1);
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate /*
4537c478bd9Sstevel@tonic-gate * the comparator function needs to calculate
4547c478bd9Sstevel@tonic-gate * the actual 'initloc' of a bintab entry - to
4557c478bd9Sstevel@tonic-gate * do this we initialize the following global to point
4567c478bd9Sstevel@tonic-gate * to it.
4577c478bd9Sstevel@tonic-gate */
4587c478bd9Sstevel@tonic-gate static Addr framehdr_addr;
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate static int
bintabcompare(const void * p1,const void * p2)4617c478bd9Sstevel@tonic-gate bintabcompare(const void *p1, const void *p2)
4627c478bd9Sstevel@tonic-gate {
4637c478bd9Sstevel@tonic-gate uint_t *bintab1, *bintab2;
4647c478bd9Sstevel@tonic-gate uint_t ent1, ent2;
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate bintab1 = (uint_t *)p1;
4677c478bd9Sstevel@tonic-gate bintab2 = (uint_t *)p2;
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate assert(bintab1 != 0);
4707c478bd9Sstevel@tonic-gate assert(bintab2 != 0);
4717c478bd9Sstevel@tonic-gate
4727c478bd9Sstevel@tonic-gate ent1 = *bintab1 + framehdr_addr;
4737c478bd9Sstevel@tonic-gate ent2 = *bintab2 + framehdr_addr;
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate if (ent1 > ent2)
4767c478bd9Sstevel@tonic-gate return (1);
4777c478bd9Sstevel@tonic-gate if (ent1 < ent2)
4787c478bd9Sstevel@tonic-gate return (-1);
4797c478bd9Sstevel@tonic-gate return (0);
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate uintptr_t
ld_unwind_populate_hdr(Ofl_desc * ofl)4837e16fca0SAli Bahrami ld_unwind_populate_hdr(Ofl_desc *ofl)
4847c478bd9Sstevel@tonic-gate {
48585213095Srie uchar_t *hdrdata;
486ba2be530Sab uint_t *binarytable;
487ba2be530Sab uint_t hdroff;
4887e16fca0SAli Bahrami Aliste idx;
489ba2be530Sab Addr hdraddr;
490ba2be530Sab Os_desc *hdrosp;
491ba2be530Sab Os_desc *osp;
492ba2be530Sab Os_desc *first_unwind;
493ba2be530Sab uint_t fde_count;
494ba2be530Sab uint_t *uint_ptr;
495ba2be530Sab int bswap = (ofl->ofl_flags1 & FLG_OF1_ENCDIFF) != 0;
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate /*
4987c478bd9Sstevel@tonic-gate * Are we building the unwind hdr?
4997c478bd9Sstevel@tonic-gate */
5007c478bd9Sstevel@tonic-gate if ((hdrosp = ofl->ofl_unwindhdr) == 0)
5017c478bd9Sstevel@tonic-gate return (1);
5027c478bd9Sstevel@tonic-gate
5037c478bd9Sstevel@tonic-gate hdrdata = hdrosp->os_outdata->d_buf;
5047c478bd9Sstevel@tonic-gate hdraddr = hdrosp->os_shdr->sh_addr;
5057c478bd9Sstevel@tonic-gate hdroff = 0;
5067c478bd9Sstevel@tonic-gate
5077c478bd9Sstevel@tonic-gate /*
5087c478bd9Sstevel@tonic-gate * version == 1
5097c478bd9Sstevel@tonic-gate */
5107c478bd9Sstevel@tonic-gate hdrdata[hdroff++] = 1;
5117c478bd9Sstevel@tonic-gate /*
5127c478bd9Sstevel@tonic-gate * The encodings are:
5137c478bd9Sstevel@tonic-gate *
5147c478bd9Sstevel@tonic-gate * eh_frameptr_enc sdata4 | pcrel
5157c478bd9Sstevel@tonic-gate * fde_count_enc udata4
5167c478bd9Sstevel@tonic-gate * table_enc sdata4 | datarel
5177c478bd9Sstevel@tonic-gate */
5187c478bd9Sstevel@tonic-gate hdrdata[hdroff++] = DW_EH_PE_sdata4 | DW_EH_PE_pcrel;
5197c478bd9Sstevel@tonic-gate hdrdata[hdroff++] = DW_EH_PE_udata4;
5207c478bd9Sstevel@tonic-gate hdrdata[hdroff++] = DW_EH_PE_sdata4 | DW_EH_PE_datarel;
5217c478bd9Sstevel@tonic-gate
5227c478bd9Sstevel@tonic-gate /*
5237c478bd9Sstevel@tonic-gate * Header Offsets
5247c478bd9Sstevel@tonic-gate * -----------------------------------
5257c478bd9Sstevel@tonic-gate * byte version +1
5267c478bd9Sstevel@tonic-gate * byte eh_frame_ptr_enc +1
5277c478bd9Sstevel@tonic-gate * byte fde_count_enc +1
5287c478bd9Sstevel@tonic-gate * byte table_enc +1
5297c478bd9Sstevel@tonic-gate * 4 bytes eh_frame_ptr +4
5307c478bd9Sstevel@tonic-gate * 4 bytes fde_count +4
5317c478bd9Sstevel@tonic-gate */
5327c478bd9Sstevel@tonic-gate /* LINTED */
5337c478bd9Sstevel@tonic-gate binarytable = (uint_t *)(hdrdata + 12);
5347c478bd9Sstevel@tonic-gate first_unwind = 0;
5357c478bd9Sstevel@tonic-gate fde_count = 0;
5367c478bd9Sstevel@tonic-gate
5377e16fca0SAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_unwind, idx, osp)) {
53874a8d72aSrie uchar_t *data;
53974a8d72aSrie size_t size;
54037915d86SRichard Lowe uint64_t off = 0, ujunk;
54137915d86SRichard Lowe int64_t sjunk;
54274a8d72aSrie uint_t cieRflag = 0, ciePflag = 0;
5437c478bd9Sstevel@tonic-gate Shdr *shdr;
5447c478bd9Sstevel@tonic-gate
5457c478bd9Sstevel@tonic-gate /*
5467c478bd9Sstevel@tonic-gate * remember first UNWIND section to
5477c478bd9Sstevel@tonic-gate * point to in the frame_ptr entry.
5487c478bd9Sstevel@tonic-gate */
5497c478bd9Sstevel@tonic-gate if (first_unwind == 0)
5507c478bd9Sstevel@tonic-gate first_unwind = osp;
5517c478bd9Sstevel@tonic-gate
55274a8d72aSrie data = osp->os_outdata->d_buf;
5537c478bd9Sstevel@tonic-gate shdr = osp->os_shdr;
55474a8d72aSrie size = shdr->sh_size;
55574a8d72aSrie
55674a8d72aSrie while (off < size) {
55774a8d72aSrie uint_t length, id;
5587e16fca0SAli Bahrami uint64_t ndx = 0;
55974a8d72aSrie
5607c478bd9Sstevel@tonic-gate /*
56174a8d72aSrie * Extract length in lsb format. A zero length
56274a8d72aSrie * indicates that this CIE is a terminator and that
56374a8d72aSrie * processing of unwind information is complete.
5647c478bd9Sstevel@tonic-gate */
5657e16fca0SAli Bahrami length = extract_uint(data + off, &ndx, bswap);
5667e16fca0SAli Bahrami if (length == 0)
56774a8d72aSrie goto done;
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate /*
57074a8d72aSrie * Extract CIE id in lsb format.
5717c478bd9Sstevel@tonic-gate */
5727e16fca0SAli Bahrami id = extract_uint(data + off, &ndx, bswap);
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate /*
5757c478bd9Sstevel@tonic-gate * A CIE record has a id of '0'; otherwise
5767c478bd9Sstevel@tonic-gate * this is a FDE entry and the 'id' is the
5777c478bd9Sstevel@tonic-gate * CIE pointer.
5787c478bd9Sstevel@tonic-gate */
5797c478bd9Sstevel@tonic-gate if (id == 0) {
5807c478bd9Sstevel@tonic-gate char *cieaugstr;
5817c478bd9Sstevel@tonic-gate uint_t cieaugndx;
582cffcfaeeSAlexander Eremin uint_t cieversion;
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate ciePflag = 0;
5857c478bd9Sstevel@tonic-gate cieRflag = 0;
5867c478bd9Sstevel@tonic-gate /*
5877c478bd9Sstevel@tonic-gate * We need to drill through the CIE
5887c478bd9Sstevel@tonic-gate * to find the Rflag. It's the Rflag
5897c478bd9Sstevel@tonic-gate * which describes how the FDE code-pointers
5907c478bd9Sstevel@tonic-gate * are encoded.
5917c478bd9Sstevel@tonic-gate */
5927c478bd9Sstevel@tonic-gate
593cffcfaeeSAlexander Eremin cieversion = data[off + ndx];
594cffcfaeeSAlexander Eremin ndx += 1;
59574a8d72aSrie
5967c478bd9Sstevel@tonic-gate /*
5977c478bd9Sstevel@tonic-gate * augstr
5987c478bd9Sstevel@tonic-gate */
59974a8d72aSrie cieaugstr = (char *)(&data[off + ndx]);
60074a8d72aSrie ndx += strlen(cieaugstr) + 1;
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate /*
6037c478bd9Sstevel@tonic-gate * calign & dalign
6047c478bd9Sstevel@tonic-gate */
60537915d86SRichard Lowe if (uleb_extract(&data[off], &ndx,
60637915d86SRichard Lowe size - off, &ujunk) == DW_OVERFLOW) {
60737915d86SRichard Lowe ld_eprintf(ofl, ERR_FATAL,
60837915d86SRichard Lowe MSG_INTL(MSG_SCN_DWFOVRFLW),
60937915d86SRichard Lowe ofl->ofl_name,
61037915d86SRichard Lowe osp->os_name);
61137915d86SRichard Lowe return (S_ERROR);
61237915d86SRichard Lowe }
61337915d86SRichard Lowe
61437915d86SRichard Lowe if (sleb_extract(&data[off], &ndx,
61537915d86SRichard Lowe size - off, &sjunk) == DW_OVERFLOW) {
61637915d86SRichard Lowe ld_eprintf(ofl, ERR_FATAL,
61737915d86SRichard Lowe MSG_INTL(MSG_SCN_DWFOVRFLW),
61837915d86SRichard Lowe ofl->ofl_name,
61937915d86SRichard Lowe osp->os_name);
62037915d86SRichard Lowe return (S_ERROR);
62137915d86SRichard Lowe }
62274a8d72aSrie
6237c478bd9Sstevel@tonic-gate /*
6247c478bd9Sstevel@tonic-gate * retreg
6257c478bd9Sstevel@tonic-gate */
62637915d86SRichard Lowe if (cieversion == 1) {
627cffcfaeeSAlexander Eremin ndx++;
62837915d86SRichard Lowe } else {
62937915d86SRichard Lowe if (uleb_extract(&data[off], &ndx,
63037915d86SRichard Lowe size - off, &ujunk) ==
63137915d86SRichard Lowe DW_OVERFLOW) {
63237915d86SRichard Lowe ld_eprintf(ofl, ERR_FATAL,
63337915d86SRichard Lowe MSG_INTL(MSG_SCN_DWFOVRFLW),
63437915d86SRichard Lowe ofl->ofl_name,
63537915d86SRichard Lowe osp->os_name);
63637915d86SRichard Lowe return (S_ERROR);
63737915d86SRichard Lowe }
63837915d86SRichard Lowe }
6397c478bd9Sstevel@tonic-gate /*
6407c478bd9Sstevel@tonic-gate * we walk through the augmentation
6417c478bd9Sstevel@tonic-gate * section now looking for the Rflag
6427c478bd9Sstevel@tonic-gate */
6437c478bd9Sstevel@tonic-gate for (cieaugndx = 0; cieaugstr[cieaugndx];
6447c478bd9Sstevel@tonic-gate cieaugndx++) {
645ba2be530Sab /* BEGIN CSTYLED */
6467c478bd9Sstevel@tonic-gate switch (cieaugstr[cieaugndx]) {
6477c478bd9Sstevel@tonic-gate case 'z':
6487c478bd9Sstevel@tonic-gate /* size */
64937915d86SRichard Lowe if (uleb_extract(&data[off],
65037915d86SRichard Lowe &ndx, size - off, &ujunk) ==
65137915d86SRichard Lowe DW_OVERFLOW) {
65237915d86SRichard Lowe ld_eprintf(ofl, ERR_FATAL,
65337915d86SRichard Lowe MSG_INTL(MSG_SCN_DWFOVRFLW),
65437915d86SRichard Lowe ofl->ofl_name,
65537915d86SRichard Lowe osp->os_name);
65637915d86SRichard Lowe return (S_ERROR);
65737915d86SRichard Lowe }
6587c478bd9Sstevel@tonic-gate break;
6597c478bd9Sstevel@tonic-gate case 'P':
6607c478bd9Sstevel@tonic-gate /* personality */
66174a8d72aSrie ciePflag = data[off + ndx];
66274a8d72aSrie ndx++;
6637c478bd9Sstevel@tonic-gate /*
6647c478bd9Sstevel@tonic-gate * Just need to extract the
6657c478bd9Sstevel@tonic-gate * value to move on to the next
6667c478bd9Sstevel@tonic-gate * field.
6677c478bd9Sstevel@tonic-gate */
66837915d86SRichard Lowe switch (dwarf_ehe_extract(
66937915d86SRichard Lowe &data[off], size - off,
67037915d86SRichard Lowe &ndx, &ujunk, ciePflag,
671965630c1SRichard Lowe ofl->ofl_dehdr->e_ident, B_FALSE,
67237915d86SRichard Lowe shdr->sh_addr, off + ndx, 0)) {
67337915d86SRichard Lowe case DW_OVERFLOW:
67437915d86SRichard Lowe ld_eprintf(ofl, ERR_FATAL,
67537915d86SRichard Lowe MSG_INTL(MSG_SCN_DWFOVRFLW),
67637915d86SRichard Lowe ofl->ofl_name,
67737915d86SRichard Lowe osp->os_name);
67837915d86SRichard Lowe return (S_ERROR);
67937915d86SRichard Lowe case DW_BAD_ENCODING:
68037915d86SRichard Lowe ld_eprintf(ofl, ERR_FATAL,
68137915d86SRichard Lowe MSG_INTL(MSG_SCN_DWFBADENC),
68237915d86SRichard Lowe ofl->ofl_name,
68337915d86SRichard Lowe osp->os_name, ciePflag);
68437915d86SRichard Lowe return (S_ERROR);
68537915d86SRichard Lowe case DW_SUCCESS:
68637915d86SRichard Lowe break;
68737915d86SRichard Lowe }
6887c478bd9Sstevel@tonic-gate break;
6897c478bd9Sstevel@tonic-gate case 'R':
6907c478bd9Sstevel@tonic-gate /* code encoding */
69174a8d72aSrie cieRflag = data[off + ndx];
69274a8d72aSrie ndx++;
6937c478bd9Sstevel@tonic-gate break;
6947c478bd9Sstevel@tonic-gate case 'L':
6957c478bd9Sstevel@tonic-gate /* lsda encoding */
69674a8d72aSrie ndx++;
6977c478bd9Sstevel@tonic-gate break;
6987c478bd9Sstevel@tonic-gate }
699ba2be530Sab /* END CSTYLED */
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate } else {
7027c478bd9Sstevel@tonic-gate uint_t bintabndx;
7037c478bd9Sstevel@tonic-gate uint64_t initloc;
7047c478bd9Sstevel@tonic-gate uint64_t fdeaddr;
705965630c1SRichard Lowe uint64_t gotaddr = 0;
706965630c1SRichard Lowe
707965630c1SRichard Lowe if (ofl->ofl_osgot != NULL)
708965630c1SRichard Lowe gotaddr =
709965630c1SRichard Lowe ofl->ofl_osgot->os_shdr->sh_addr;
7107c478bd9Sstevel@tonic-gate
71137915d86SRichard Lowe switch (dwarf_ehe_extract(&data[off],
71237915d86SRichard Lowe size - off, &ndx, &initloc, cieRflag,
71337915d86SRichard Lowe ofl->ofl_dehdr->e_ident, B_FALSE,
71437915d86SRichard Lowe shdr->sh_addr, off + ndx, gotaddr)) {
71537915d86SRichard Lowe case DW_OVERFLOW:
71637915d86SRichard Lowe ld_eprintf(ofl, ERR_FATAL,
71737915d86SRichard Lowe MSG_INTL(MSG_SCN_DWFOVRFLW),
71837915d86SRichard Lowe ofl->ofl_name,
71937915d86SRichard Lowe osp->os_name);
72037915d86SRichard Lowe return (S_ERROR);
72137915d86SRichard Lowe case DW_BAD_ENCODING:
72237915d86SRichard Lowe ld_eprintf(ofl, ERR_FATAL,
72337915d86SRichard Lowe MSG_INTL(MSG_SCN_DWFBADENC),
72437915d86SRichard Lowe ofl->ofl_name,
72537915d86SRichard Lowe osp->os_name, cieRflag);
72637915d86SRichard Lowe return (S_ERROR);
72737915d86SRichard Lowe case DW_SUCCESS:
72837915d86SRichard Lowe break;
72937915d86SRichard Lowe }
7307c478bd9Sstevel@tonic-gate
7317c478bd9Sstevel@tonic-gate /*
73240e53e87SAli Bahrami * Ignore FDEs with initloc set to 0.
73340e53e87SAli Bahrami * initloc will not be 0 unless this FDE was
73440e53e87SAli Bahrami * abandoned due to GNU linkonce processing.
73540e53e87SAli Bahrami * The 0 value occurs because we don't resolve
73640e53e87SAli Bahrami * sloppy relocations for unwind header target
73740e53e87SAli Bahrami * sections.
7387c478bd9Sstevel@tonic-gate */
73940e53e87SAli Bahrami if (initloc != 0) {
74040e53e87SAli Bahrami bintabndx = fde_count * 2;
74140e53e87SAli Bahrami fde_count++;
7427c478bd9Sstevel@tonic-gate
74340e53e87SAli Bahrami /*
74440e53e87SAli Bahrami * FDEaddr is adjusted
74540e53e87SAli Bahrami * to account for the length & id which
74640e53e87SAli Bahrami * have already been consumed.
74740e53e87SAli Bahrami */
74840e53e87SAli Bahrami fdeaddr = shdr->sh_addr + off;
74940e53e87SAli Bahrami
75040e53e87SAli Bahrami binarytable[bintabndx] =
75140e53e87SAli Bahrami (uint_t)(initloc - hdraddr);
75240e53e87SAli Bahrami binarytable[bintabndx + 1] =
75340e53e87SAli Bahrami (uint_t)(fdeaddr - hdraddr);
75440e53e87SAli Bahrami }
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate /*
7587c478bd9Sstevel@tonic-gate * the length does not include the length
7597c478bd9Sstevel@tonic-gate * itself - so account for that too.
7607c478bd9Sstevel@tonic-gate */
76174a8d72aSrie off += length + 4;
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate }
7647c478bd9Sstevel@tonic-gate
76574a8d72aSrie done:
7667c478bd9Sstevel@tonic-gate /*
7677e16fca0SAli Bahrami * Do a quicksort on the binary table. If this is a cross
768ba2be530Sab * link from a system with the opposite byte order, xlate
769ba2be530Sab * the resulting values into LSB order.
7707c478bd9Sstevel@tonic-gate */
7717c478bd9Sstevel@tonic-gate framehdr_addr = hdraddr;
7727c478bd9Sstevel@tonic-gate qsort((void *)binarytable, (size_t)fde_count,
773ba2be530Sab (size_t)(sizeof (uint_t) * 2), bintabcompare);
774ba2be530Sab if (bswap) {
775ba2be530Sab uint_t *btable = binarytable;
776ba2be530Sab uint_t cnt;
777ba2be530Sab
778ba2be530Sab for (cnt = fde_count * 2; cnt-- > 0; btable++)
779ba2be530Sab *btable = ld_bswap_Word(*btable);
780ba2be530Sab }
781ba2be530Sab
7827c478bd9Sstevel@tonic-gate /*
7837c478bd9Sstevel@tonic-gate * Fill in:
7847c478bd9Sstevel@tonic-gate * first_frame_ptr
7857c478bd9Sstevel@tonic-gate * fde_count
7867c478bd9Sstevel@tonic-gate */
7877c478bd9Sstevel@tonic-gate hdroff = 4;
7887c478bd9Sstevel@tonic-gate /* LINTED */
7897c478bd9Sstevel@tonic-gate uint_ptr = (uint_t *)(&hdrdata[hdroff]);
7907c478bd9Sstevel@tonic-gate *uint_ptr = first_unwind->os_shdr->sh_addr -
7917e16fca0SAli Bahrami (hdrosp->os_shdr->sh_addr + hdroff);
792ba2be530Sab if (bswap)
793ba2be530Sab *uint_ptr = ld_bswap_Word(*uint_ptr);
7947c478bd9Sstevel@tonic-gate
7957c478bd9Sstevel@tonic-gate hdroff += 4;
7967c478bd9Sstevel@tonic-gate /* LINTED */
7977c478bd9Sstevel@tonic-gate uint_ptr = (uint_t *)&hdrdata[hdroff];
7987c478bd9Sstevel@tonic-gate *uint_ptr = fde_count;
799ba2be530Sab if (bswap)
800ba2be530Sab *uint_ptr = ld_bswap_Word(*uint_ptr);
8017c478bd9Sstevel@tonic-gate
80240e53e87SAli Bahrami /*
80340e53e87SAli Bahrami * If relaxed relocations are active, then there is a chance
80440e53e87SAli Bahrami * that we didn't use all the space reserved for this section.
8057e16fca0SAli Bahrami * For details, see the note at head of ld_unwind_make_hdr() above.
80640e53e87SAli Bahrami *
80740e53e87SAli Bahrami * Find the PT_SUNW_UNWIND program header, and change the size values
80840e53e87SAli Bahrami * to the size of the subset of the section that was actually used.
80940e53e87SAli Bahrami */
81040e53e87SAli Bahrami if (ofl->ofl_flags1 & FLG_OF1_RLXREL) {
81140e53e87SAli Bahrami Word phnum = ofl->ofl_nehdr->e_phnum;
81240e53e87SAli Bahrami Phdr *phdr = ofl->ofl_phdr;
81340e53e87SAli Bahrami
81440e53e87SAli Bahrami for (; phnum-- > 0; phdr++) {
81540e53e87SAli Bahrami if (phdr->p_type == PT_SUNW_UNWIND) {
81640e53e87SAli Bahrami phdr->p_memsz = 12 + (8 * fde_count);
81740e53e87SAli Bahrami phdr->p_filesz = phdr->p_memsz;
81840e53e87SAli Bahrami break;
81940e53e87SAli Bahrami }
82040e53e87SAli Bahrami }
82140e53e87SAli Bahrami }
82240e53e87SAli Bahrami
8237c478bd9Sstevel@tonic-gate return (1);
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate
8267e16fca0SAli Bahrami /*
8277e16fca0SAli Bahrami * Append an .eh_frame section to our output list if not already present.
8287e16fca0SAli Bahrami *
8297e16fca0SAli Bahrami * Usually, there is a single .eh_frame output section. However, there can
8307e16fca0SAli Bahrami * be more if there are incompatible section flags on incoming sections.
8317e16fca0SAli Bahrami * If this does happen, the frame_ptr field of the eh_frame_hdr section
8327e16fca0SAli Bahrami * will point at the base of the first output section, and the other
8337e16fca0SAli Bahrami * sections will not be accessible via frame_ptr. However, the .eh_frame_hdr
8347e16fca0SAli Bahrami * will be able to access all the data in the different .eh_frame sections,
8357e16fca0SAli Bahrami * because the entries in sorted table are all encoded as DW_EH_PE_datarel.
8367e16fca0SAli Bahrami */
8377c478bd9Sstevel@tonic-gate uintptr_t
ld_unwind_register(Os_desc * osp,Ofl_desc * ofl)8387e16fca0SAli Bahrami ld_unwind_register(Os_desc *osp, Ofl_desc * ofl)
8397c478bd9Sstevel@tonic-gate {
8407e16fca0SAli Bahrami Aliste idx;
8417e16fca0SAli Bahrami Os_desc *_osp;
8427c478bd9Sstevel@tonic-gate /*
8437c478bd9Sstevel@tonic-gate * Check to see if this output section is already
8447c478bd9Sstevel@tonic-gate * on the list.
8457c478bd9Sstevel@tonic-gate */
8467e16fca0SAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_unwind, idx, _osp))
8477c478bd9Sstevel@tonic-gate if (osp == _osp)
848ba2be530Sab return (1);
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate /*
8517c478bd9Sstevel@tonic-gate * Append output section to unwind list
8527c478bd9Sstevel@tonic-gate */
85357ef7aa9SRod Evans if (aplist_append(&ofl->ofl_unwind, osp, AL_CNT_OFL_UNWIND) == NULL)
854ba2be530Sab return (S_ERROR);
85557ef7aa9SRod Evans
8567c478bd9Sstevel@tonic-gate return (1);
8577c478bd9Sstevel@tonic-gate }
858