Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
gen_facilities
gen_opcode_table
relocs
+32
View File
@@ -0,0 +1,32 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for s390 specific build tools
#
kapi := arch/$(ARCH)/include/generated/asm
kapi-hdrs-y := $(kapi)/facility-defs.h $(kapi)/dis-defs.h
PHONY += kapi
kapi: $(kapi-hdrs-y)
hostprogs += gen_facilities
hostprogs += gen_opcode_table
HOSTCFLAGS_gen_facilities.o += $(LINUXINCLUDE)
filechk_facility-defs.h = $(obj)/gen_facilities
filechk_dis-defs.h = \
$(obj)/gen_opcode_table < $(srctree)/arch/$(ARCH)/tools/opcodes.txt
$(kapi)/facility-defs.h: $(obj)/gen_facilities FORCE
$(call filechk,facility-defs.h)
$(kapi)/dis-defs.h: $(obj)/gen_opcode_table FORCE
$(call filechk,dis-defs.h)
hostprogs += relocs
PHONY += relocs
relocs: $(obj)/relocs
@:
+24
View File
@@ -0,0 +1,24 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Borrowed from gcc: gcc/testsuite/gcc.target/s390/nobp-section-type-conflict.c
# Checks that we don't get error: section type conflict with ‘put_page’.
cat << "END" | $@ -x c - -fno-PIE -march=z10 -mindirect-branch=thunk-extern -mfunction-return=thunk-extern -mindirect-branch-table -O2 -c -o /dev/null
int a;
int b (void);
void c (int);
static void
put_page (void)
{
if (b ())
c (a);
}
__attribute__ ((__section__ (".init.text"), __cold__)) void
d (void)
{
put_page ();
put_page ();
}
END
@@ -0,0 +1,175 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Simple program to generate defines out of facility lists that use the bit
* numbering scheme from the Princples of Operations: most significant bit
* has bit number 0.
*
* Copyright IBM Corp. 2015, 2018
*
*/
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
struct facility_def {
char *name;
int *bits;
};
static struct facility_def facility_defs[] = {
{
/*
* FACILITIES_ALS contains the list of facilities that are
* required to run a kernel that is compiled e.g. with
* -march=<machine>.
*/
.name = "FACILITIES_ALS",
.bits = (int[]){
0, /* N3 instructions */
1, /* z/Arch mode installed */
3, /* dat-enhancement 1 */
18, /* long displacement facility */
21, /* extended-immediate facility */
25, /* store clock fast */
27, /* mvcos */
32, /* compare and swap and store */
33, /* compare and swap and store 2 */
34, /* general instructions extension */
35, /* execute extensions */
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
45, /* fast-BCR, etc. */
#endif
#ifdef CONFIG_HAVE_MARCH_ZEC12_FEATURES
49, /* misc-instruction-extensions */
52, /* interlocked facility 2 */
#endif
#ifdef CONFIG_HAVE_MARCH_Z13_FEATURES
53, /* load-and-zero-rightmost-byte, etc. */
129, /* vector */
#endif
#ifdef CONFIG_HAVE_MARCH_Z14_FEATURES
58, /* miscellaneous-instruction-extension 2 */
#endif
#ifdef CONFIG_HAVE_MARCH_Z15_FEATURES
61, /* miscellaneous-instruction-extension 3 */
#endif
#ifdef CONFIG_HAVE_MARCH_Z17_FEATURES
84, /* miscellaneous-instruction-extension 4 */
#endif
-1 /* END */
}
},
{
/*
* FACILITIES_KVM contains the list of facilities that are part
* of the default facility mask and list that are passed to the
* initial CPU model. If no CPU model is used, this, together
* with the non-hypervisor managed bits, is the maximum list of
* guest facilities supported by KVM.
*/
.name = "FACILITIES_KVM",
.bits = (int[]){
0, /* N3 instructions */
1, /* z/Arch mode installed */
2, /* z/Arch mode active */
3, /* DAT-enhancement */
4, /* idte segment table */
5, /* idte region table */
6, /* ASN-and-LX reuse */
7, /* stfle */
8, /* enhanced-DAT 1 */
9, /* sense-running-status */
10, /* conditional sske */
13, /* ipte-range */
14, /* nonquiescing key-setting */
73, /* transactional execution */
75, /* access-exception-fetch/store indication */
76, /* msa extension 3 */
77, /* msa extension 4 */
78, /* enhanced-DAT 2 */
130, /* instruction-execution-protection */
131, /* enhanced-SOP 2 and side-effect */
139, /* multiple epoch facility */
146, /* msa extension 8 */
150, /* enhanced sort */
151, /* deflate conversion */
155, /* msa extension 9 */
-1 /* END */
}
},
{
/*
* FACILITIES_KVM_CPUMODEL contains the list of facilities
* that can be enabled by CPU model code if the host supports
* it. These facilities are not passed to the guest without
* CPU model support.
*/
.name = "FACILITIES_KVM_CPUMODEL",
.bits = (int[]){
12, /* AP Query Configuration Information */
15, /* AP Facilities Test */
156, /* etoken facility */
165, /* nnpa facility */
170, /* ineffective-nonconstrained-transaction facility */
193, /* bear enhancement facility */
194, /* rdp enhancement facility */
196, /* processor activity instrumentation facility */
197, /* processor activity instrumentation extension 1 */
201, /* concurrent-functions facility */
-1 /* END */
}
},
};
static void print_facility_list(struct facility_def *def)
{
unsigned int high, bit, dword, i;
unsigned long long *array;
array = calloc(1, 8);
if (!array)
exit(EXIT_FAILURE);
high = 0;
for (i = 0; def->bits[i] != -1; i++) {
bit = 63 - (def->bits[i] & 63);
dword = def->bits[i] / 64;
if (dword > high) {
array = realloc(array, (dword + 1) * 8);
if (!array)
exit(EXIT_FAILURE);
memset(array + high + 1, 0, (dword - high) * 8);
high = dword;
}
array[dword] |= 1ULL << bit;
}
printf("#define %s ", def->name);
for (i = 0; i <= high; i++)
printf("_AC(0x%016llx,UL)%c", array[i], i < high ? ',' : '\n');
free(array);
}
static void print_facility_lists(void)
{
unsigned int i;
for (i = 0; i < sizeof(facility_defs) / sizeof(facility_defs[0]); i++)
print_facility_list(&facility_defs[i]);
}
int main(int argc, char **argv)
{
printf("#ifndef __ASM_S390_FACILITY_DEFS__\n");
printf("#define __ASM_S390_FACILITY_DEFS__\n");
printf("/*\n");
printf(" * DO NOT MODIFY.\n");
printf(" *\n");
printf(" * This file was generated by %s\n", __FILE__);
printf(" */\n\n");
printf("#include <linux/const.h>\n\n");
print_facility_lists();
printf("\n#endif\n");
return 0;
}
@@ -0,0 +1,352 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Generate opcode table initializers for the in-kernel disassembler.
*
* Copyright IBM Corp. 2017
*
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#define STRING_SIZE_MAX 20
struct insn_type {
unsigned char byte;
unsigned char mask;
char **format;
};
struct insn {
struct insn_type *type;
char opcode[STRING_SIZE_MAX];
char name[STRING_SIZE_MAX];
char upper[STRING_SIZE_MAX];
char format[STRING_SIZE_MAX];
unsigned int name_len;
};
struct insn_group {
struct insn_type *type;
int offset;
int count;
char opcode[2];
};
struct insn_format {
char *format;
int type;
};
struct gen_opcode {
struct insn *insn;
int nr;
struct insn_group *group;
int nr_groups;
};
/*
* Table of instruction format types. Each opcode is defined with at
* least one byte (two nibbles), three nibbles, or two bytes (four
* nibbles).
* The byte member of each instruction format type entry defines
* within which byte of an instruction the third (and fourth) nibble
* of an opcode can be found. The mask member is the and-mask that
* needs to be applied on this byte in order to get the third (and
* fourth) nibble of the opcode.
* The format array defines all instruction formats (as defined in the
* Principles of Operation) which have the same position of the opcode
* nibbles.
* A special case are instruction formats with 1-byte opcodes. In this
* case the byte member always is zero, so that the mask is applied on
* the (only) byte that contains the opcode.
*/
static struct insn_type insn_type_table[] = {
{
.byte = 0,
.mask = 0xff,
.format = (char *[]) {
"MII",
"RR",
"RS",
"RSI",
"RX",
"SI",
"SMI",
"SS",
NULL,
},
},
{
.byte = 1,
.mask = 0x0f,
.format = (char *[]) {
"RI",
"RIL",
"SSF",
NULL,
},
},
{
.byte = 1,
.mask = 0xff,
.format = (char *[]) {
"E",
"IE",
"RRE",
"RRF",
"RRR",
"S",
"SIL",
"SSE",
NULL,
},
},
{
.byte = 5,
.mask = 0xff,
.format = (char *[]) {
"RIE",
"RIS",
"RRS",
"RSE",
"RSL",
"RSY",
"RXE",
"RXF",
"RXY",
"SIY",
"VRI",
"VRR",
"VRS",
"VRV",
"VRX",
"VSI",
NULL,
},
},
};
static struct insn_type *insn_format_to_type(char *format)
{
char tmp[STRING_SIZE_MAX];
char *base_format, **ptr;
int i;
strcpy(tmp, format);
base_format = tmp;
base_format = strsep(&base_format, "_");
for (i = 0; i < sizeof(insn_type_table) / sizeof(insn_type_table[0]); i++) {
ptr = insn_type_table[i].format;
while (*ptr) {
if (!strcmp(base_format, *ptr))
return &insn_type_table[i];
ptr++;
}
}
exit(EXIT_FAILURE);
}
static void read_instructions(struct gen_opcode *desc)
{
struct insn insn;
int rc, i;
while (1) {
rc = scanf("%s %s %s", insn.opcode, insn.name, insn.format);
if (rc == EOF)
break;
if (rc != 3)
exit(EXIT_FAILURE);
insn.type = insn_format_to_type(insn.format);
insn.name_len = strlen(insn.name);
for (i = 0; i <= insn.name_len; i++)
insn.upper[i] = toupper((unsigned char)insn.name[i]);
desc->nr++;
desc->insn = realloc(desc->insn, desc->nr * sizeof(*desc->insn));
if (!desc->insn)
exit(EXIT_FAILURE);
desc->insn[desc->nr - 1] = insn;
}
}
static int cmpformat(const void *a, const void *b)
{
return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format);
}
static void print_formats(struct gen_opcode *desc)
{
char *format;
int i, count;
qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpformat);
format = "";
count = 0;
printf("enum {\n");
for (i = 0; i < desc->nr; i++) {
if (!strcmp(format, desc->insn[i].format))
continue;
count++;
format = desc->insn[i].format;
printf("\tINSTR_%s,\n", format);
}
printf("}; /* %d */\n\n", count);
}
static int cmp_long_insn(const void *a, const void *b)
{
return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name);
}
static void print_insn_name(const char *name)
{
size_t i, len;
len = strlen(name);
printf("{");
for (i = 0; i < len; i++)
printf(" \'%c\',", name[i]);
printf(" }");
}
static void print_long_insn(struct gen_opcode *desc)
{
struct insn *insn;
int i, count;
qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmp_long_insn);
count = 0;
printf("enum {\n");
for (i = 0; i < desc->nr; i++) {
insn = &desc->insn[i];
if (insn->name_len < 6)
continue;
printf("\tLONG_INSN_%s,\n", insn->upper);
count++;
}
printf("}; /* %d */\n\n", count);
printf("#define LONG_INSN_INITIALIZER { \\\n");
for (i = 0; i < desc->nr; i++) {
insn = &desc->insn[i];
if (insn->name_len < 6)
continue;
printf("\t[LONG_INSN_%s] = ", insn->upper);
print_insn_name(insn->name);
printf(", \\\n");
}
printf("}\n\n");
}
static void print_opcode(struct insn *insn, int nr)
{
char *opcode;
opcode = insn->opcode;
if (insn->type->byte != 0)
opcode += 2;
printf("\t[%4d] = { .opfrag = 0x%s, .format = INSTR_%s, ", nr, opcode, insn->format);
if (insn->name_len < 6) {
printf(".name = ");
print_insn_name(insn->name);
} else {
printf(".offset = LONG_INSN_%s", insn->upper);
}
printf(" }, \\\n");
}
static void add_to_group(struct gen_opcode *desc, struct insn *insn, int offset)
{
struct insn_group *group;
group = desc->group ? &desc->group[desc->nr_groups - 1] : NULL;
if (group && (!strncmp(group->opcode, insn->opcode, 2) || group->type->byte == 0)) {
group->count++;
return;
}
desc->nr_groups++;
desc->group = realloc(desc->group, desc->nr_groups * sizeof(*desc->group));
if (!desc->group)
exit(EXIT_FAILURE);
group = &desc->group[desc->nr_groups - 1];
memcpy(group->opcode, insn->opcode, 2);
group->type = insn->type;
group->offset = offset;
group->count = 1;
}
static int cmpopcode(const void *a, const void *b)
{
return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode);
}
static void print_opcode_table(struct gen_opcode *desc)
{
char opcode[2] = "";
struct insn *insn;
int i, offset;
qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpopcode);
printf("#define OPCODE_TABLE_INITIALIZER { \\\n");
offset = 0;
for (i = 0; i < desc->nr; i++) {
insn = &desc->insn[i];
if (insn->type->byte == 0)
continue;
add_to_group(desc, insn, offset);
if (strncmp(opcode, insn->opcode, 2)) {
memcpy(opcode, insn->opcode, 2);
printf("\t/* %.2s */ \\\n", opcode);
}
print_opcode(insn, offset);
offset++;
}
printf("\t/* 1-byte opcode instructions */ \\\n");
for (i = 0; i < desc->nr; i++) {
insn = &desc->insn[i];
if (insn->type->byte != 0)
continue;
add_to_group(desc, insn, offset);
print_opcode(insn, offset);
offset++;
}
printf("}\n\n");
}
static void print_opcode_table_offsets(struct gen_opcode *desc)
{
struct insn_group *group;
int i;
printf("#define OPCODE_OFFSET_INITIALIZER { \\\n");
for (i = 0; i < desc->nr_groups; i++) {
group = &desc->group[i];
printf("\t{ .opcode = 0x%.2s, .mask = 0x%02x, .byte = %d, .offset = %d, .count = %d }, \\\n",
group->opcode, group->type->mask, group->type->byte, group->offset, group->count);
}
printf("}\n\n");
}
int main(int argc, char **argv)
{
struct gen_opcode _desc = { 0 };
struct gen_opcode *desc = &_desc;
read_instructions(desc);
printf("#ifndef __S390_GENERATED_DIS_DEFS_H__\n");
printf("#define __S390_GENERATED_DIS_DEFS_H__\n");
printf("/*\n");
printf(" * DO NOT MODIFY.\n");
printf(" *\n");
printf(" * This file was generated by %s\n", __FILE__);
printf(" */\n\n");
print_formats(desc);
print_long_insn(desc);
print_opcode_table(desc);
print_opcode_table_offsets(desc);
printf("#endif\n");
exit(EXIT_SUCCESS);
}
File diff suppressed because it is too large Load Diff
+387
View File
@@ -0,0 +1,387 @@
// SPDX-License-Identifier: GPL-2.0
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <elf.h>
#include <byteswap.h>
#define USE_BSD
#include <endian.h>
#define ELF_BITS 64
#define ELF_MACHINE EM_S390
#define ELF_MACHINE_NAME "IBM S/390"
#define SHT_REL_TYPE SHT_RELA
#define Elf_Rel Elf64_Rela
#define ELF_CLASS ELFCLASS64
#define ELF_ENDIAN ELFDATA2MSB
#define ELF_R_SYM(val) ELF64_R_SYM(val)
#define ELF_R_TYPE(val) ELF64_R_TYPE(val)
#define ELF_ST_TYPE(o) ELF64_ST_TYPE(o)
#define ELF_ST_BIND(o) ELF64_ST_BIND(o)
#define ELF_ST_VISIBILITY(o) ELF64_ST_VISIBILITY(o)
#define ElfW(type) _ElfW(ELF_BITS, type)
#define _ElfW(bits, type) __ElfW(bits, type)
#define __ElfW(bits, type) Elf##bits##_##type
#define Elf_Addr ElfW(Addr)
#define Elf_Ehdr ElfW(Ehdr)
#define Elf_Phdr ElfW(Phdr)
#define Elf_Shdr ElfW(Shdr)
#define Elf_Sym ElfW(Sym)
static Elf_Ehdr ehdr;
static unsigned long shnum;
static unsigned int shstrndx;
struct relocs {
uint32_t *offset;
unsigned long count;
unsigned long size;
};
static struct relocs relocs64;
#define FMT PRIu64
struct section {
Elf_Shdr shdr;
struct section *link;
Elf_Rel *reltab;
};
static struct section *secs;
#if BYTE_ORDER == LITTLE_ENDIAN
#define le16_to_cpu(val) (val)
#define le32_to_cpu(val) (val)
#define le64_to_cpu(val) (val)
#define be16_to_cpu(val) bswap_16(val)
#define be32_to_cpu(val) bswap_32(val)
#define be64_to_cpu(val) bswap_64(val)
#endif
#if BYTE_ORDER == BIG_ENDIAN
#define le16_to_cpu(val) bswap_16(val)
#define le32_to_cpu(val) bswap_32(val)
#define le64_to_cpu(val) bswap_64(val)
#define be16_to_cpu(val) (val)
#define be32_to_cpu(val) (val)
#define be64_to_cpu(val) (val)
#endif
static uint16_t elf16_to_cpu(uint16_t val)
{
if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
return le16_to_cpu(val);
else
return be16_to_cpu(val);
}
static uint32_t elf32_to_cpu(uint32_t val)
{
if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
return le32_to_cpu(val);
else
return be32_to_cpu(val);
}
#define elf_half_to_cpu(x) elf16_to_cpu(x)
#define elf_word_to_cpu(x) elf32_to_cpu(x)
static uint64_t elf64_to_cpu(uint64_t val)
{
return be64_to_cpu(val);
}
#define elf_addr_to_cpu(x) elf64_to_cpu(x)
#define elf_off_to_cpu(x) elf64_to_cpu(x)
#define elf_xword_to_cpu(x) elf64_to_cpu(x)
static void die(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(1);
}
static void read_ehdr(FILE *fp)
{
if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
die("Cannot read ELF header: %s\n", strerror(errno));
if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0)
die("No ELF magic\n");
if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
die("Not a %d bit executable\n", ELF_BITS);
if (ehdr.e_ident[EI_DATA] != ELF_ENDIAN)
die("ELF endian mismatch\n");
if (ehdr.e_ident[EI_VERSION] != EV_CURRENT)
die("Unknown ELF version\n");
/* Convert the fields to native endian */
ehdr.e_type = elf_half_to_cpu(ehdr.e_type);
ehdr.e_machine = elf_half_to_cpu(ehdr.e_machine);
ehdr.e_version = elf_word_to_cpu(ehdr.e_version);
ehdr.e_entry = elf_addr_to_cpu(ehdr.e_entry);
ehdr.e_phoff = elf_off_to_cpu(ehdr.e_phoff);
ehdr.e_shoff = elf_off_to_cpu(ehdr.e_shoff);
ehdr.e_flags = elf_word_to_cpu(ehdr.e_flags);
ehdr.e_ehsize = elf_half_to_cpu(ehdr.e_ehsize);
ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize);
ehdr.e_phnum = elf_half_to_cpu(ehdr.e_phnum);
ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize);
ehdr.e_shnum = elf_half_to_cpu(ehdr.e_shnum);
ehdr.e_shstrndx = elf_half_to_cpu(ehdr.e_shstrndx);
shnum = ehdr.e_shnum;
shstrndx = ehdr.e_shstrndx;
if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN))
die("Unsupported ELF header type\n");
if (ehdr.e_machine != ELF_MACHINE)
die("Not for %s\n", ELF_MACHINE_NAME);
if (ehdr.e_version != EV_CURRENT)
die("Unknown ELF version\n");
if (ehdr.e_ehsize != sizeof(Elf_Ehdr))
die("Bad Elf header size\n");
if (ehdr.e_phentsize != sizeof(Elf_Phdr))
die("Bad program header entry\n");
if (ehdr.e_shentsize != sizeof(Elf_Shdr))
die("Bad section header entry\n");
if (shnum == SHN_UNDEF || shstrndx == SHN_XINDEX) {
Elf_Shdr shdr;
if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0)
die("Seek to %" FMT " failed: %s\n", ehdr.e_shoff, strerror(errno));
if (fread(&shdr, sizeof(shdr), 1, fp) != 1)
die("Cannot read initial ELF section header: %s\n", strerror(errno));
if (shnum == SHN_UNDEF)
shnum = elf_xword_to_cpu(shdr.sh_size);
if (shstrndx == SHN_XINDEX)
shstrndx = elf_word_to_cpu(shdr.sh_link);
}
if (shstrndx >= shnum)
die("String table index out of bounds\n");
}
static void read_shdrs(FILE *fp)
{
Elf_Shdr shdr;
int i;
secs = calloc(shnum, sizeof(struct section));
if (!secs)
die("Unable to allocate %ld section headers\n", shnum);
if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0)
die("Seek to %" FMT " failed: %s\n", ehdr.e_shoff, strerror(errno));
for (i = 0; i < shnum; i++) {
struct section *sec = &secs[i];
if (fread(&shdr, sizeof(shdr), 1, fp) != 1) {
die("Cannot read ELF section headers %d/%ld: %s\n",
i, shnum, strerror(errno));
}
sec->shdr.sh_name = elf_word_to_cpu(shdr.sh_name);
sec->shdr.sh_type = elf_word_to_cpu(shdr.sh_type);
sec->shdr.sh_flags = elf_xword_to_cpu(shdr.sh_flags);
sec->shdr.sh_addr = elf_addr_to_cpu(shdr.sh_addr);
sec->shdr.sh_offset = elf_off_to_cpu(shdr.sh_offset);
sec->shdr.sh_size = elf_xword_to_cpu(shdr.sh_size);
sec->shdr.sh_link = elf_word_to_cpu(shdr.sh_link);
sec->shdr.sh_info = elf_word_to_cpu(shdr.sh_info);
sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign);
sec->shdr.sh_entsize = elf_xword_to_cpu(shdr.sh_entsize);
if (sec->shdr.sh_link < shnum)
sec->link = &secs[sec->shdr.sh_link];
}
}
static void read_relocs(FILE *fp)
{
int i, j;
for (i = 0; i < shnum; i++) {
struct section *sec = &secs[i];
if (sec->shdr.sh_type != SHT_REL_TYPE)
continue;
sec->reltab = malloc(sec->shdr.sh_size);
if (!sec->reltab)
die("malloc of %" FMT " bytes for relocs failed\n", sec->shdr.sh_size);
if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0)
die("Seek to %" FMT " failed: %s\n", sec->shdr.sh_offset, strerror(errno));
if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) != sec->shdr.sh_size)
die("Cannot read symbol table: %s\n", strerror(errno));
for (j = 0; j < sec->shdr.sh_size / sizeof(Elf_Rel); j++) {
Elf_Rel *rel = &sec->reltab[j];
rel->r_offset = elf_addr_to_cpu(rel->r_offset);
rel->r_info = elf_xword_to_cpu(rel->r_info);
#if (SHT_REL_TYPE == SHT_RELA)
rel->r_addend = elf_xword_to_cpu(rel->r_addend);
#endif
}
}
}
static void add_reloc(struct relocs *r, uint32_t offset)
{
if (r->count == r->size) {
unsigned long newsize = r->size + 50000;
void *mem = realloc(r->offset, newsize * sizeof(r->offset[0]));
if (!mem)
die("realloc of %ld entries for relocs failed\n", newsize);
r->offset = mem;
r->size = newsize;
}
r->offset[r->count++] = offset;
}
static int do_reloc(struct section *sec, Elf_Rel *rel)
{
unsigned int r_type = ELF64_R_TYPE(rel->r_info);
ElfW(Addr) offset = rel->r_offset;
switch (r_type) {
case R_390_NONE:
case R_390_PC32:
case R_390_PC64:
case R_390_PC16DBL:
case R_390_PC32DBL:
case R_390_PLT32DBL:
case R_390_GOTENT:
case R_390_GOTPCDBL:
case R_390_GOTOFF64:
break;
case R_390_64:
add_reloc(&relocs64, offset);
break;
default:
die("Unsupported relocation type: %d\n", r_type);
break;
}
return 0;
}
static void walk_relocs(void)
{
int i;
/* Walk through the relocations */
for (i = 0; i < shnum; i++) {
struct section *sec_applies;
int j;
struct section *sec = &secs[i];
if (sec->shdr.sh_type != SHT_REL_TYPE)
continue;
sec_applies = &secs[sec->shdr.sh_info];
if (!(sec_applies->shdr.sh_flags & SHF_ALLOC))
continue;
for (j = 0; j < sec->shdr.sh_size / sizeof(Elf_Rel); j++) {
Elf_Rel *rel = &sec->reltab[j];
do_reloc(sec, rel);
}
}
}
static int cmp_relocs(const void *va, const void *vb)
{
const uint32_t *a, *b;
a = va; b = vb;
return (*a == *b) ? 0 : (*a > *b) ? 1 : -1;
}
static void sort_relocs(struct relocs *r)
{
qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
}
static int print_reloc(uint32_t v)
{
return fprintf(stdout, "\t.long 0x%08"PRIx32"\n", v) > 0 ? 0 : -1;
}
static void emit_relocs(void)
{
int i;
walk_relocs();
sort_relocs(&relocs64);
printf(".section \".vmlinux.relocs_64\",\"a\"\n");
for (i = 0; i < relocs64.count; i++)
print_reloc(relocs64.offset[i]);
}
static void process(FILE *fp)
{
read_ehdr(fp);
read_shdrs(fp);
read_relocs(fp);
emit_relocs();
}
static void usage(void)
{
die("relocs vmlinux\n");
}
int main(int argc, char **argv)
{
unsigned char e_ident[EI_NIDENT];
const char *fname;
FILE *fp;
fname = NULL;
if (argc != 2)
usage();
fname = argv[1];
fp = fopen(fname, "r");
if (!fp)
die("Cannot open %s: %s\n", fname, strerror(errno));
if (fread(&e_ident, 1, EI_NIDENT, fp) != EI_NIDENT)
die("Cannot read %s: %s", fname, strerror(errno));
rewind(fp);
process(fp);
fclose(fp);
return 0;
}