#include "../libdw/dwarf.h"
#include "../libdw/libdwP.h"
+#include "../libebl/libebl.h"
#include "dwarfstrings.h"
#include "dwarflint.h"
continue;
}
- /* Create an `Elf' descriptor. */
- Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+ /* Create an `Elf' descriptor. We need either
+ READ_MMAP_PRIVATE, or plain READ, so that we can access and
+ modify the data inside. */
+ Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
+ if (elf == NULL)
+ elf = elf_begin (fd, ELF_C_READ, NULL);
+
if (elf == NULL)
wr_error (NULL,
gettext ("cannot generate Elf descriptor: %s\n"),
#define PRI_DIE "DIE 0x%" PRIx64
#define PRI_NOT_ENOUGH ": not enough data for %s.\n"
+struct section_data
+{
+ enum section_id sec;
+ Elf_Data *secdata;
+ Elf_Data *reldata; /* May be NULL if there are no associated
+ relocation data. */
+ size_t reltype; /* SHT_REL or SHT_RELA. */
+};
+
/* Functions and data structures related to bounds-checked
reading. */
/* Functions for checking of structural integrity. */
-static struct cu *check_debug_info_structural (struct read_ctx *ctx,
- struct abbrev_table *abbrev_chain,
- Elf_Data *strings);
+static struct cu *check_debug_info_structural (Dwarf *dwarf,
+ struct section_data *data,
+ struct abbrev_table *abbrev_chain);
static bool check_cu_structural (struct read_ctx *ctx,
struct cu *const cu,
static bool check_aranges_structural (struct read_ctx *ctx,
struct cu *cu_chain);
-static bool check_pub_structural (struct read_ctx *ctx,
- struct cu *cu_chain,
- enum section_id sec);
+static bool check_pub_structural (Dwarf *dwarf,
+ struct section_data *data,
+ struct cu *cu_chain);
static void check_location_expression (struct read_ctx *ctx,
struct where *wh,
bool addr_64);
-static bool check_loc_or_range_structural (struct read_ctx *ctx,
- struct cu *cu_chain,
- enum section_id sec);
+static bool check_loc_or_range_structural (Dwarf *dwarf,
+ struct section_data *data,
+ struct cu *cu_chain);
+
+static bool check_relocation_section_structural (Dwarf *dwarf,
+ struct section_data *data,
+ Ebl *ebl,
+ bool elf_64);
const char *
NULL, NULL, NULL, NULL},
[sec_ranges] = {".debug_ranges", "rangelist", "%#"PRIx64,
- "offset", "%#"PRIx64, NULL, NULL}
+ "offset", "%#"PRIx64, NULL, NULL},
+
+ [sec_rel] = {".rel", "relocation", "%"PRId64, NULL, NULL, NULL, NULL},
+ [sec_rela] = {".rela", "relocation", "%"PRId64, NULL, NULL, NULL, NULL},
};
assert (wh->section < sizeof (section_names) / sizeof (*section_names));
#undef SETUP_ADDR
char *orig = ptr;
+ bool is_reloc = wh->section == sec_rel || wh->section == sec_rela;
if (ptr == NULL)
- ptr = stpcpy (stpcpy (buf, inf->name), addr1s != NULL ? ": " : "");
+ {
+ if (is_reloc)
+ {
+ assert (wh->ref != NULL);
+ ptr = stpcpy (buf, section_names[wh->ref->section].name);
+ }
+ else
+ ptr = buf;
+ ptr = stpcpy (stpcpy (ptr, inf->name), addr1s != NULL ? ": " : "");
+ }
if (addr3s != NULL)
ptr = stpcpy (stpcpy (stpcpy (ptr, inf->addr3n), " "), addr3s);
else if (addr1s != NULL)
ptr = stpcpy (stpcpy (stpcpy (ptr, inf->addr1n), " "), addr1s);
- if (wh->ref != NULL)
+ if (wh->ref != NULL && !is_reloc)
{
ptr = stpcpy (ptr, " (");
ptr = (char *)where_fmt (wh->ref, ptr);
struct read_ctx ctx;
- Elf_Data *abbrev_data = dwarf->sectiondata[IDX_debug_abbrev];
- Elf_Data *info_data = dwarf->sectiondata[IDX_debug_info];
- Elf_Data *aranges_data = dwarf->sectiondata[IDX_debug_aranges];
- Elf_Data *pubnames_data = dwarf->sectiondata[IDX_debug_pubnames];
- Elf_Data *loc_data = dwarf->sectiondata[IDX_debug_loc];
- Elf_Data *ranges_data = dwarf->sectiondata[IDX_debug_ranges];
+#define DEF_SECDATA(VAR, SEC) \
+ struct section_data VAR = {SEC, NULL, NULL, 0}
+
+ DEF_SECDATA (abbrev_data, sec_abbrev);
+ DEF_SECDATA (aranges_data, sec_aranges);
+ DEF_SECDATA (info_data, sec_info);
+ DEF_SECDATA (loc_data, sec_loc);
+ DEF_SECDATA (pubnames_data, sec_pubnames);
+ DEF_SECDATA (pubtypes_data, sec_pubtypes);
+ DEF_SECDATA (ranges_data, sec_ranges);
+
+#undef DEF_SECDATA
+
+ struct secinfo
+ {
+ const char *name;
+ struct section_data *dataptr;
+ };
+ struct secinfo secinfo[] = {
+ {".debug_abbrev", &abbrev_data},
+ {".debug_aranges", &aranges_data},
+ {".debug_info", &info_data},
+ {".debug_loc", &loc_data},
+ {".debug_pubnames", &pubnames_data},
+ {".debug_pubtypes", &pubtypes_data},
+ {".debug_ranges", &ranges_data},
+ };
+
+ Elf_Scn *reloc_symtab = NULL;
+
+ struct section_data *find_secdata (const char *secname)
+ {
+ for (size_t i = 0; i < sizeof (secinfo) / sizeof (*secinfo); ++i)
+ if (strcmp (secinfo[i].name, secname) == 0)
+ return secinfo[i].dataptr;
+ return NULL;
+ }
+
+ /* Now find all necessary debuginfo sections and associated
+ relocation sections. */
- /* Obtaining pubtypes is a bit complicated, because GNU toolchain
- doesn't emit it, and libdw doesn't account for it. */
Elf_Scn *scn = NULL;
GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (dwarf->elf, &ehdr_mem);
- if (ehdr == NULL)
+ Ebl *ebl = ebl_openbackend (dwarf->elf);
+ if (ehdr == NULL || ebl == NULL)
goto invalid_elf;
- Elf_Data *pubtypes_data = NULL;
+ bool elf_64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64;
while ((scn = elf_nextscn (dwarf->elf, scn)) != NULL)
{
GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
if (shdr == NULL)
- goto invalid_elf;
+ {
+ invalid_elf:
+ /* A "can't happen". libdw already managed to parse the Elf
+ file when constructing the Dwarf object. */
+ wr_error (NULL, "Broken ELF.\n");
+ goto skip_rel;
+ }
const char *scnname = elf_strptr (dwarf->elf, ehdr->e_shstrndx,
shdr->sh_name);
if (scnname == NULL)
+ goto invalid_elf;
+
+ struct section_data *secdata = find_secdata (scnname);
+ if (secdata != NULL)
{
- invalid_elf:
- /* A "can't happen". libdw already managed to parse the Elf
- file when constructing the Dwarf object. */
- wr_error (NULL, "broken Elf");
- break;
+ if (secdata->secdata == NULL)
+ {
+ secdata->secdata = elf_getdata (scn, NULL);
+ if (secdata->secdata == NULL)
+ wr_error (NULL, "data-less section %s.\n", scnname);
+ }
+ else
+ wr_error (NULL, "multiple occurrences of section %s.\n", scnname);
}
- if (strcmp (scnname, ".debug_pubtypes") == 0)
+ else if (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL)
{
- pubtypes_data = elf_getdata (scn, NULL);
- break;
+ Elf_Scn *relocated_scn = elf_getscn (dwarf->elf, shdr->sh_info);
+ Elf_Scn *symtab_scn = elf_getscn (dwarf->elf, shdr->sh_link);
+ if (relocated_scn == NULL || symtab_scn == NULL)
+ goto invalid_elf;
+
+ GElf_Shdr relocated_shdr_mem;
+ GElf_Shdr *relocated_shdr = gelf_getshdr (relocated_scn,
+ &relocated_shdr_mem);
+ if (relocated_shdr == NULL)
+ goto invalid_elf;
+
+ const char *relocated_scnname
+ = elf_strptr (dwarf->elf, ehdr->e_shstrndx,
+ relocated_shdr->sh_name);
+
+ struct section_data *relocated_secdata
+ = find_secdata (relocated_scnname);
+
+ if (relocated_secdata != NULL)
+ {
+ if (relocated_secdata->reldata != NULL)
+ wr_error (NULL,
+ "Several relocation sections for debug section %s\n.",
+ relocated_scnname);
+ else
+ {
+ relocated_secdata->reldata = elf_getdata (scn, NULL);
+ if (relocated_secdata->reldata == NULL)
+ wr_error (NULL,
+ "Data-less relocation section %s.\n", scnname);
+ relocated_secdata->reltype = shdr->sh_type;
+ }
+
+ if (reloc_symtab == NULL)
+ reloc_symtab = symtab_scn;
+ else if (reloc_symtab != symtab_scn)
+ wr_error (NULL,
+ "Relocation sections use multiple symbol tables.\n");
+ }
}
}
+ /* Check relocation sections that we've got. */
+ for (size_t i = 0; i < sizeof (secinfo) / sizeof (*secinfo); ++i)
+ if (secinfo[i].dataptr->reldata != NULL)
+ {
+ if (secinfo[i].dataptr->secdata == NULL)
+ {
+ secinfo[i].dataptr->secdata = NULL;
+ wr_error (&WHERE (secinfo[i].dataptr->sec, NULL),
+ ": the ELF contains relocation section for this data-less section.\n");
+ }
+ else if (!check_relocation_section_structural (dwarf,
+ secinfo[i].dataptr,
+ ebl, elf_64))
+ secinfo[i].dataptr->reldata = NULL;
+ }
+
+ skip_rel:;
/* If we got Dwarf pointer, debug_abbrev and debug_info are present
inside the file. But let's be paranoid. */
struct abbrev_table *abbrev_chain = NULL;
- if (likely (abbrev_data != NULL))
+ if (likely (abbrev_data.secdata != NULL))
{
- read_ctx_init (&ctx, dwarf, abbrev_data);
+ read_ctx_init (&ctx, dwarf, abbrev_data.secdata);
abbrev_chain = abbrev_table_load (&ctx);
}
else if (!tolerate_nodebug)
if (abbrev_chain != NULL)
{
- Elf_Data *str_data = dwarf->sectiondata[IDX_debug_str];
/* Same as above... */
- if (info_data != NULL)
- {
- read_ctx_init (&ctx, dwarf, info_data);
- cu_chain = check_debug_info_structural (&ctx, abbrev_chain,
- str_data);
- }
+ if (info_data.secdata != NULL)
+ cu_chain = check_debug_info_structural (dwarf, &info_data,
+ abbrev_chain);
else if (!tolerate_nodebug)
/* Hard error, not a message. We can't debug without this. */
wr_error (NULL, ".debug_info data not found.\n");
}
bool ranges_sound;
- if (ranges_data != NULL && cu_chain != NULL)
- {
- read_ctx_init (&ctx, dwarf, ranges_data);
- ranges_sound = check_loc_or_range_structural (&ctx, cu_chain, sec_ranges);
- }
+ if (ranges_data.secdata != NULL && cu_chain != NULL)
+ ranges_sound = check_loc_or_range_structural (dwarf, &ranges_data, cu_chain);
else
ranges_sound = false;
- if (loc_data != NULL && cu_chain != NULL)
- {
- read_ctx_init (&ctx, dwarf, loc_data);
- check_loc_or_range_structural (&ctx, cu_chain, sec_loc);
- }
+ if (loc_data.secdata != NULL && cu_chain != NULL)
+ check_loc_or_range_structural (dwarf, &loc_data, cu_chain);
- if (aranges_data != NULL)
+ if (aranges_data.secdata != NULL)
{
- read_ctx_init (&ctx, dwarf, aranges_data);
+ read_ctx_init (&ctx, dwarf, aranges_data.secdata);
if (check_aranges_structural (&ctx, cu_chain)
&& ranges_sound)
check_matching_ranges (dwarf);
}
- if (pubnames_data != NULL)
- {
- read_ctx_init (&ctx, dwarf, pubnames_data);
- check_pub_structural (&ctx, cu_chain, sec_pubnames);
- }
+ if (pubnames_data.secdata != NULL)
+ check_pub_structural (dwarf, &pubnames_data, cu_chain);
else
wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf,
&WHERE (sec_pubnames, NULL), ": data not found.\n");
- if (pubtypes_data != NULL)
- {
- read_ctx_init (&ctx, dwarf, pubtypes_data);
- check_pub_structural (&ctx, cu_chain, sec_pubtypes);
- }
+ if (pubtypes_data.secdata != NULL)
+ check_pub_structural (dwarf, &pubtypes_data, cu_chain);
else
wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf | mc_pubtypes,
&WHERE (sec_pubtypes, NULL), ": data not found.\n");
cu_free (cu_chain);
abbrev_table_free (abbrev_chain);
+ if (ebl != NULL)
+ ebl_closebackend (ebl);
}
static void
}
static struct cu *
-check_debug_info_structural (struct read_ctx *ctx,
- struct abbrev_table *abbrev_chain,
- Elf_Data *strings)
+check_debug_info_structural (Dwarf *dwarf,
+ struct section_data *data,
+ struct abbrev_table *abbrev_chain)
{
+ struct read_ctx ctx;
+ read_ctx_init (&ctx, dwarf, data->secdata);
+ Elf_Data *strings = dwarf->sectiondata[IDX_debug_str];
+
struct ref_record die_refs;
memset (&die_refs, 0, sizeof (die_refs));
strings_coverage = &strings_coverage_mem;
}
- while (!read_ctx_eof (ctx))
+ while (!read_ctx_eof (&ctx))
{
- const unsigned char *cu_begin = ctx->ptr;
+ const unsigned char *cu_begin = ctx.ptr;
struct where where = WHERE (sec_info, NULL);
- where_reset_1 (&where, read_ctx_get_offset (ctx));
+ where_reset_1 (&where, read_ctx_get_offset (&ctx));
struct cu *cur = xcalloc (1, sizeof (*cur));
cur->offset = where.addr1;
/* Reading CU header is a bit tricky, because we don't know if
we have run into (superfluous but allowed) zero padding. */
- if (!read_ctx_need_data (ctx, 4)
- && check_zero_padding (ctx, mc_die_other, &where))
+ if (!read_ctx_need_data (&ctx, 4)
+ && check_zero_padding (&ctx, mc_die_other, &where))
break;
/* CU length. */
- if (!read_ctx_read_4ubyte (ctx, &size32))
+ if (!read_ctx_read_4ubyte (&ctx, &size32))
{
wr_error (&where, ": can't read CU length.\n");
success = false;
break;
}
- if (size32 == 0 && check_zero_padding (ctx, mc_die_other, &where))
+ if (size32 == 0 && check_zero_padding (&ctx, mc_die_other, &where))
break;
- if (!read_size_extra (ctx, size32, &size, &dwarf_64, &where))
+ if (!read_size_extra (&ctx, size32, &size, &dwarf_64, &where))
{
success = false;
break;
}
- if (!read_ctx_need_data (ctx, size))
+ if (!read_ctx_need_data (&ctx, size))
{
wr_error (&where,
": section doesn't have enough data"
" to read CU of size %" PRIx64 ".\n", size);
- ctx->ptr = ctx->end;
+ ctx.ptr = ctx.end;
success = false;
break;
}
- const unsigned char *cu_end = ctx->ptr + size;
+ const unsigned char *cu_end = ctx.ptr + size;
cur->length = cu_end - cu_begin; // Length including the length field.
/* version + debug_abbrev_offset + address_size */
/* Make CU context begin just before the CU length, so that DIE
offsets are computed correctly. */
struct read_ctx cu_ctx;
- if (!read_ctx_init_sub (&cu_ctx, ctx, cu_begin, cu_end))
+ if (!read_ctx_init_sub (&cu_ctx, &ctx, cu_begin, cu_end))
{
wr_error (&where, PRI_NOT_ENOUGH, "next CU");
success = false;
break;
}
- cu_ctx.ptr = ctx->ptr;
+ cu_ctx.ptr = ctx.ptr;
if (!check_cu_structural (&cu_ctx, cur, abbrev_chain,
strings,
if (cu_ctx.ptr != cu_ctx.end
&& !check_zero_padding (&cu_ctx, mc_die_other, &where))
wr_message_padding_n0 (mc_die_other, &where,
- read_ctx_get_offset (ctx), size);
+ read_ctx_get_offset (&ctx), size);
}
- ctx->ptr += size;
+ ctx.ptr += size;
}
- // Only check this if above we have been successful.
- if (success && ctx->ptr != ctx->end)
+ /* Only check this if above we have been successful. */
+ if (success && ctx.ptr != ctx.end)
wr_message (mc_die_other | mc_impact_4,
&WHERE (sec_info, NULL),
": CU lengths don't exactly match Elf_Data contents.");
}
static bool
-check_pub_structural (struct read_ctx *ctx, struct cu *cu_chain,
- enum section_id sec)
+check_pub_structural (Dwarf *dwarf,
+ struct section_data *data,
+ struct cu *cu_chain)
{
+ struct read_ctx ctx;
+ read_ctx_init (&ctx, dwarf, data->secdata);
bool retval = true;
- while (!read_ctx_eof (ctx))
+ while (!read_ctx_eof (&ctx))
{
- struct where where = WHERE (sec, NULL);
- where_reset_1 (&where, read_ctx_get_offset (ctx));
- const unsigned char *set_begin = ctx->ptr;
+ struct where where = WHERE (data->sec, NULL);
+ where_reset_1 (&where, read_ctx_get_offset (&ctx));
+ const unsigned char *set_begin = ctx.ptr;
/* Size. */
uint32_t size32;
uint64_t size;
bool dwarf_64;
- if (!read_ctx_read_4ubyte (ctx, &size32))
+ if (!read_ctx_read_4ubyte (&ctx, &size32))
{
wr_error (&where, ": can't read table length.\n");
return false;
}
- if (!read_size_extra (ctx, size32, &size, &dwarf_64, &where))
+ if (!read_size_extra (&ctx, size32, &size, &dwarf_64, &where))
return false;
struct read_ctx sub_ctx;
- const unsigned char *set_end = ctx->ptr + size;
- if (!read_ctx_init_sub (&sub_ctx, ctx, set_begin, set_end))
+ const unsigned char *set_end = ctx.ptr + size;
+ if (!read_ctx_init_sub (&sub_ctx, &ctx, set_begin, set_end))
{
wr_error (&where, PRI_NOT_ENOUGH, "next set");
return false;
}
- sub_ctx.ptr = ctx->ptr;
+ sub_ctx.ptr = ctx.ptr;
/* Version. */
uint16_t version;
if (cu != NULL)
{
where.ref = &cu->where;
- bool *has = sec == sec_pubnames
+ bool *has = data->sec == sec_pubnames
? &cu->has_pubnames : &cu->has_pubtypes;
if (*has)
wr_message (mc_impact_2 | mc_pubtables, &where,
}
if (sub_ctx.ptr != sub_ctx.end
- && !check_zero_padding (&sub_ctx, mc_pubtables, &WHERE (sec, NULL)))
+ && !check_zero_padding (&sub_ctx, mc_pubtables,
+ &WHERE (data->sec, NULL)))
{
- wr_message_padding_n0 (mc_pubtables | mc_error, &WHERE (sec, NULL),
+ wr_message_padding_n0 (mc_pubtables | mc_error,
+ &WHERE (data->sec, NULL),
read_ctx_get_offset (&sub_ctx), size);
retval = false;
}
next:
- ctx->ptr += size;
+ ctx.ptr += size;
}
return retval;
}
static bool
-check_loc_or_range_structural (struct read_ctx *ctx,
- struct cu *cu_chain,
- enum section_id sec)
+check_loc_or_range_structural (Dwarf *dwarf,
+ struct section_data *data,
+ struct cu *cu_chain)
{
- assert (sec == sec_loc || sec == sec_ranges);
+ assert (data->sec == sec_loc || data->sec == sec_ranges);
assert (cu_chain != NULL);
- assert (ctx != NULL);
+
+ struct read_ctx ctx;
+ read_ctx_init (&ctx, dwarf, data->secdata);
bool retval = true;
struct coverage_map *coverage_map;
- if ((coverage_map = coverage_map_alloc_XA (ctx->dbg->elf,
- sec == sec_loc)) == NULL)
+ if ((coverage_map = coverage_map_alloc_XA (ctx.dbg->elf,
+ data->sec == sec_loc)) == NULL)
{
- wr_error (&WHERE (sec, NULL),
+ wr_error (&WHERE (data->sec, NULL),
": couldn't read ELF, skipping coverage analysis.\n");
retval = false;
}
struct coverage coverage;
- coverage_init (&coverage, ctx->data->d_size);
+ coverage_init (&coverage, ctx.data->d_size);
struct addr_record addrs;
memset (&addrs, 0, sizeof (addrs));
- enum message_category cat = sec == sec_loc ? mc_loc : mc_ranges;
+ enum message_category cat = data->sec == sec_loc ? mc_loc : mc_ranges;
for (struct cu *cu = cu_chain; cu != NULL; cu = cu->next)
{
struct ref_record *rec
- = sec == sec_loc ? &cu->loc_refs : &cu->range_refs;
+ = data->sec == sec_loc ? &cu->loc_refs : &cu->range_refs;
for (size_t i = 0; i < rec->size; ++i)
{
struct ref *ref = rec->refs + i;
struct read_ctx sub_ctx;
- read_ctx_init (&sub_ctx, ctx->dbg, ctx->data);
+ read_ctx_init (&sub_ctx, ctx.dbg, ctx.data);
if (!check_loc_or_range_ref (&sub_ctx, cu,
&coverage, coverage_map, &addrs,
ref->addr, cu->address_size == 8,
- &ref->who, cat, sec))
+ &ref->who, cat, data->sec))
retval = false;
}
}
chain. */
coverage_find_holes (&coverage, found_hole,
&((struct hole_info)
- {sec, cat, cu_chain->address_size,
- ctx->data->d_buf}));
+ {data->sec, cat, cu_chain->address_size,
+ ctx.data->d_buf}));
#ifdef FIND_SECTION_HOLES
coverage_map_find_holes (coverage_map, &coverage_map_found_hole,
&(struct coverage_map_hole_info)
- {{sec, cat, 0, NULL},
+ {{data->sec, cat, 0, NULL},
coverage_map->elf});
#endif
}
return retval;
}
+
+
+bool
+check_relocation_section_structural (Dwarf *dwarf,
+ struct section_data *data,
+ Ebl *ebl,
+ bool elf_64)
+{
+ assert (data->reltype == SHT_REL || data->reltype == SHT_RELA);
+ bool retval = true;
+
+ struct read_ctx ctx;
+ read_ctx_init (&ctx, dwarf, data->secdata);
+
+ bool is_rela = data->reltype == SHT_RELA;
+ size_t entrysize
+ = elf_64
+ ? (is_rela ? sizeof (Elf64_Rela) : sizeof (Elf64_Rel))
+ : (is_rela ? sizeof (Elf32_Rela) : sizeof (Elf32_Rel));
+ unsigned entries = data->reldata->d_size / entrysize;
+
+ struct where parent = WHERE (data->sec, NULL);
+ struct where where = WHERE (is_rela ? sec_rela : sec_rel, NULL);
+ where.ref = &parent;
+
+ for (unsigned i = 0; i < entries; ++i)
+ {
+ where_reset_1 (&where, i);
+
+ GElf_Rela rela_mem = {0, 0, 0};
+ GElf_Rela *rela = is_rela
+ ? gelf_getrela (data->reldata, i, &rela_mem)
+ : (GElf_Rela *)gelf_getrel (data->reldata, i, (GElf_Rel *)(&rela_mem));
+ if (rela == NULL)
+ {
+ wr_error (&where, ": couldn't read relocation.\n");
+ return false;
+ }
+ if (!is_rela)
+ assert (rela->r_addend == 0);
+
+ int rtype = GELF_R_TYPE (rela->r_info);
+ Elf_Type type = ebl_reloc_simple_type (ebl, rtype);
+
+ switch (type)
+ {
+ case ELF_T_BYTE:
+ case ELF_T_HALF:
+ case ELF_T_WORD:
+ case ELF_T_SWORD:
+ case ELF_T_XWORD:
+ case ELF_T_SXWORD:
+ break;
+
+ default:
+ wr_error (&where, ": invalid relocation type %d.\n", type);
+ retval = false;
+ };
+ }
+
+ if (retval)
+ {
+ /* Sort the reloc section so that the applicable addresses of
+ relocation entries are monotonously increasing. */
+#define COMPAR(BITS) \
+ int compar##BITS (const void *a, const void *b) \
+ { \
+ typedef Elf##BITS##_Rela rel_t; \
+ return ((rel_t *)b)->r_offset - ((rel_t *)a)->r_offset; \
+ }
+ COMPAR (32);
+ COMPAR (64);
+#undef COMPAR
+
+ qsort (data->reldata->d_buf, entries, entrysize,
+ elf_64 ? &compar64 : &compar32);
+ }
+
+ return retval;
+}