#include "elf/s390.h"
#include "elf-s390.h"
#include "dwarf2.h"
+#include "sframe.h"
+#include "sframe-api.h"
#include <stdarg.h>
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
DW_CFA_nop, DW_CFA_nop, DW_CFA_nop
};
+/* .sframe covering the .plt section. */
+
+/* This must be the same as sframe_get_hdr_size (sfh). For s390x, this value
+ is the same as sizeof (sframe_header) because there is no SFrame auxilliary
+ header. */
+#define PLT_SFRAME_FDE_START_OFFSET sizeof (sframe_header)
+
+#define SFRAME_PLT0_MAX_NUM_FRES 1
+#define SFRAME_PLTN_MAX_NUM_FRES 1
+
+struct elf_s390x_sframe_plt
+{
+ unsigned int plt0_entry_size;
+ unsigned int plt0_num_fres;
+ const sframe_frame_row_entry *plt0_fres[SFRAME_PLT0_MAX_NUM_FRES];
+
+ unsigned int pltn_entry_size;
+ unsigned int pltn_num_fres;
+ const sframe_frame_row_entry *pltn_fres[SFRAME_PLTN_MAX_NUM_FRES];
+};
+
+/* .sframe FRE covering the PLT0/PLTn .plt section entry. */
+static const sframe_frame_row_entry elf_s390x_sframe_plt_fre =
+{
+ 0, /* SFrame FRE start address. */
+ {0, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 12 bytes. */
+ SFRAME_V1_FRE_INFO (SFRAME_BASE_REG_SP, 1, SFRAME_FRE_OFFSET_2B) /* FRE info. */
+};
+
+/* SFrame helper object for PLT. */
+static const struct elf_s390x_sframe_plt elf_s390x_sframe_plt =
+{
+ PLT_FIRST_ENTRY_SIZE,
+ 1, /* Number of FREs for PLT0. */
+ /* Array of SFrame FREs for PLT0. */
+ { &elf_s390x_sframe_plt_fre },
+
+ PLT_ENTRY_SIZE,
+ 1, /* Number of FREs for PLTn. */
+ /* Array of SFrame FREs for PLTn. */
+ { &elf_s390x_sframe_plt_fre },
+};
+
/* s390 ELF linker hash entry. */
asection *irelifunc;
asection *plt_eh_frame;
+ sframe_encoder_ctx *plt_cfe_ctx;
+ asection *plt_sframe;
+ /* The .sframe helper object for .plt section. */
+ const struct elf_s390x_sframe_plt *sframe_plt;
+
union {
bfd_signed_vma refcount;
bfd_vma offset;
return _bfd_elf_adjust_dynamic_copy (info, h, s);
}
+/* Create SFrame stack trace info for the PLT entries in the .plt section. */
+
+static bool
+_bfd_s390_elf_create_sframe_plt (struct bfd_link_info *info)
+{
+ struct elf_s390_link_hash_table *htab;
+
+ unsigned int plt0_entry_size;
+ unsigned char func_info;
+ uint32_t fre_type;
+ /* The dynamic plt section for which .sframe stack trace information is being
+ created. */
+ asection *dpltsec;
+
+ int err = 0;
+
+ sframe_encoder_ctx **ectx = NULL;
+ unsigned plt_entry_size = 0;
+ unsigned int num_pltn_fres = 0;
+ unsigned int num_pltn_entries = 0;
+ const sframe_frame_row_entry * const *pltn_fres;
+
+ htab = elf_s390_hash_table (info);
+ ectx = &htab->plt_cfe_ctx;
+ dpltsec = htab->elf.splt;
+
+ plt0_entry_size = htab->sframe_plt->plt0_entry_size;
+ plt_entry_size = htab->sframe_plt->pltn_entry_size;
+ pltn_fres = htab->sframe_plt->pltn_fres;
+ num_pltn_fres = htab->sframe_plt->pltn_num_fres;
+ num_pltn_entries = (dpltsec->size - plt0_entry_size) / plt_entry_size;
+
+ *ectx = sframe_encode (SFRAME_VERSION_2,
+ SFRAME_F_FDE_FUNC_START_PCREL,
+ SFRAME_ABI_S390X_ENDIAN_BIG,
+ SFRAME_CFA_FIXED_FP_INVALID,
+ SFRAME_CFA_FIXED_RA_INVALID,
+ &err);
+
+ /* FRE type is dependent on the size of the function. */
+ fre_type = sframe_calc_fre_type (dpltsec->size);
+ func_info = sframe_fde_create_func_info (fre_type, SFRAME_FDE_TYPE_PCINC);
+
+ /* Add SFrame FDE and the associated FREs for PLT0 if PLT0 has been
+ generated. */
+ if (plt0_entry_size)
+ {
+ /* Add SFrame FDE for PLT0, the function start address is updated later
+ at _bfd_elf_merge_section_sframe time. */
+ sframe_encoder_add_funcdesc_v2 (*ectx,
+ 0, /* func start addr. */
+ plt0_entry_size,
+ func_info,
+ 0, /* Rep block size. */
+ 0 /* Num FREs. */);
+ sframe_frame_row_entry plt0_fre;
+ unsigned int num_plt0_fres = htab->sframe_plt->plt0_num_fres;
+ for (unsigned int j = 0; j < num_plt0_fres; j++)
+ {
+ plt0_fre = *(htab->sframe_plt->plt0_fres[j]);
+ sframe_encoder_add_fre (*ectx, 0, &plt0_fre);
+ }
+ }
+
+ if (num_pltn_entries)
+ {
+ /* PLTn entries use an SFrame FDE of type
+ SFRAME_FDE_TYPE_PCMASK to exploit the repetitive
+ pattern of the instructions in these entries. Using this SFrame FDE
+ type helps in keeping the SFrame stack trace info for PLTn entries
+ compact. */
+ func_info = sframe_fde_create_func_info (fre_type,
+ SFRAME_FDE_TYPE_PCMASK);
+ /* Add the SFrame FDE for all PCs starting at the first PLTn entry (hence,
+ function start address = plt0_entry_size. As usual, this will be
+ updated later at _bfd_elf_merge_section_sframe, by when the
+ sections are relocated. */
+ sframe_encoder_add_funcdesc_v2 (*ectx,
+ plt0_entry_size, /* func start addr. */
+ dpltsec->size - plt0_entry_size,
+ func_info,
+ plt_entry_size,
+ 0 /* Num FREs. */);
+
+ sframe_frame_row_entry pltn_fre;
+ /* Now add the FREs for PLTn. Simply adding the FREs suffices due
+ to the usage of SFRAME_FDE_TYPE_PCMASK above. */
+ for (unsigned int j = 0; j < num_pltn_fres; j++)
+ {
+ unsigned int func_idx = plt0_entry_size ? 1 : 0;
+ pltn_fre = *(pltn_fres[j]);
+ sframe_encoder_add_fre (*ectx, func_idx, &pltn_fre);
+ }
+ }
+
+ return true;
+}
+
+/* Write contents of the .sframe section. */
+
+static bool
+_bfd_s390_elf_write_sframe_plt (struct bfd_link_info *info)
+{
+ struct elf_s390_link_hash_table *htab;
+ sframe_encoder_ctx *ectx;
+ size_t sec_size;
+ asection *sec;
+ bfd *dynobj;
+
+ int err = 0;
+
+ htab = elf_s390_hash_table (info);
+ dynobj = htab->elf.dynobj;
+
+ ectx = htab->plt_cfe_ctx;
+ sec = htab->plt_sframe;
+
+ BFD_ASSERT (ectx);
+
+ void *contents = sframe_encoder_write (ectx, &sec_size, &err);
+
+ sec->size = (bfd_size_type) sec_size;
+ sec->contents = (unsigned char *) bfd_zalloc (dynobj, sec->size);
+ sec->alloced = 1;
+ memcpy (sec->contents, contents, sec_size);
+
+ sframe_encoder_free (&ectx);
+
+ return true;
+}
+
/* Allocate space in .plt, .got and associated reloc sections for
dynamic relocs. */
htab->plt_eh_frame->size = sizeof (elf_s390x_eh_frame_plt);
}
+ /* No need to size the .sframe section explicitly because the write-out
+ mechanism is different. Simply prep up the FDE/FRE for the
+ .plt section. */
+ if (_bfd_elf_sframe_present (info))
+ {
+ if (htab->plt_sframe != NULL
+ && htab->elf.splt != NULL
+ && htab->elf.splt->size != 0
+ && !bfd_is_abs_section (htab->elf.splt->output_section))
+ {
+ _bfd_s390_elf_create_sframe_plt (info);
+ /* FIXME - Dirty Hack. Set the size to something non-zero for now,
+ so that the section does not get stripped out below. The precise
+ size of this section is known only when the contents are
+ serialized in _bfd_s390x_elf_write_sframe_plt. */
+ htab->plt_sframe->size = sizeof (sframe_header) + 1;
+ }
+ }
+
/* We now have determined the sizes of the various dynamic sections.
Allocate memory for them. */
relocs = false;
|| s == htab->elf.sgot
|| s == htab->elf.sgotplt
|| s == htab->plt_eh_frame
+ || s == htab->plt_sframe
|| s == htab->elf.sdynbss
|| s == htab->elf.sdynrelro
|| s == htab->elf.iplt
if ((s->flags & SEC_HAS_CONTENTS) == 0)
continue;
+ /* Skip allocating contents for .sframe section as it is written
+ out differently. See below. */
+ if (s == htab->plt_sframe)
+ continue;
+
/* Allocate memory for the section contents. We use bfd_zalloc
here in case unused entries are not reclaimed before the
section's contents are written out. This should not happen,
htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET);
}
+ if (_bfd_elf_sframe_present (info))
+ {
+ if (htab->plt_sframe != NULL
+ && htab->elf.splt != NULL
+ && htab->elf.splt->size != 0
+ && htab->plt_sframe->contents == NULL)
+ _bfd_s390_elf_write_sframe_plt (info);
+ }
+
return _bfd_elf_add_dynamic_tags (output_bfd, info, relocs);
}
}
}
+ /* Make any adjustment if necessary and merge .sframe section to
+ create the final .sframe section for output_bfd. */
+ if (htab->plt_sframe != NULL
+ && htab->plt_sframe->contents != NULL)
+ {
+ if (htab->elf.splt != NULL
+ && htab->elf.splt->size != 0
+ && (htab->elf.splt->flags & SEC_EXCLUDE) == 0
+ && htab->elf.splt->output_section != NULL
+ && htab->plt_sframe->output_section != NULL)
+ {
+ bfd_vma plt_start = htab->elf.splt->output_section->vma;
+ bfd_vma sframe_start = htab->plt_sframe->output_section->vma
+ + htab->plt_sframe->output_offset
+ + PLT_SFRAME_FDE_START_OFFSET;
+ bfd_put_signed_32 (dynobj, plt_start - sframe_start,
+ htab->plt_sframe->contents
+ + PLT_SFRAME_FDE_START_OFFSET);
+ }
+ if (htab->plt_sframe->sec_info_type == SEC_INFO_TYPE_SFRAME)
+ {
+ if (! _bfd_elf_merge_section_sframe (output_bfd, info,
+ htab->plt_sframe,
+ htab->plt_sframe->contents))
+ return false;
+ }
+ }
+
return true;
}
\f
if (htab == NULL)
return false;
+ htab->sframe_plt = &elf_s390x_sframe_plt;
+
if (htab->elf.splt != NULL)
{
/* Create .eh_frame section for .plt section. */
return false;
}
}
+
+ /* Create .sframe section for .plt section. */
+ if (!info->no_ld_generated_unwind_info)
+ {
+ flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+ | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED);
+
+ htab->plt_sframe = bfd_make_section_anyway_with_flags (dynobj,
+ ".sframe",
+ flags);
+ if (htab->plt_sframe == NULL)
+ return false;
+ }
}
return true;