Index: gdb/testsuite/gdb.arch/s390-multiarch.c |
diff --git a/gdb/testsuite/gdb.arch/s390-multiarch.c b/gdb/testsuite/gdb.arch/s390-multiarch.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f464fac4972ca85003881abd6e9ec0c9699900e7 |
--- /dev/null |
+++ b/gdb/testsuite/gdb.arch/s390-multiarch.c |
@@ -0,0 +1,314 @@ |
+/* Copyright 2013 Free Software Foundation, Inc. |
+ |
+ This file is part of GDB. |
+ |
+ This program is free software; you can redistribute it and/or modify |
+ it under the terms of the GNU General Public License as published by |
+ the Free Software Foundation; either version 3 of the License, or |
+ (at your option) any later version. |
+ |
+ This program is distributed in the hope that it will be useful, |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+ GNU General Public License for more details. |
+ |
+ You should have received a copy of the GNU General Public License |
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
+ |
+#include <errno.h> |
+#include <stdarg.h> |
+#include <stdint.h> |
+#include <stdio.h> |
+#include <stdlib.h> |
+ |
+typedef struct |
+{ |
+ unsigned char e_ident[16]; |
+ uint16_t e_type; |
+ uint16_t e_machine; |
+ uint32_t e_version; |
+ uint32_t e_entry; |
+ uint32_t e_phoff; |
+ uint32_t e_shoff; |
+ uint32_t e_flags; |
+ uint16_t e_ehsize; |
+ uint16_t e_phentsize; |
+ uint16_t e_phnum; |
+ uint16_t e_shentsize; |
+ uint16_t e_shnum; |
+ uint16_t e_shstrndx; |
+} Elf32_Ehdr; |
+ |
+typedef struct |
+{ |
+ unsigned char e_ident[16]; |
+ uint16_t e_type; |
+ uint16_t e_machine; |
+ uint32_t e_version; |
+ uint64_t e_entry; |
+ uint64_t e_phoff; |
+ uint64_t e_shoff; |
+ uint32_t e_flags; |
+ uint16_t e_ehsize; |
+ uint16_t e_phentsize; |
+ uint16_t e_phnum; |
+ uint16_t e_shentsize; |
+ uint16_t e_shnum; |
+ uint16_t e_shstrndx; |
+} Elf64_Ehdr; |
+ |
+typedef struct |
+{ |
+ uint32_t p_type; |
+ uint32_t p_offset; |
+ uint32_t p_vaddr; |
+ uint32_t p_paddr; |
+ uint32_t p_filesz; |
+ uint32_t p_memsz; |
+ uint32_t p_flags; |
+ uint32_t p_align; |
+} Elf32_Phdr; |
+ |
+typedef struct |
+{ |
+ uint32_t p_type; |
+ uint32_t p_flags; |
+ uint64_t p_offset; |
+ uint64_t p_vaddr; |
+ uint64_t p_paddr; |
+ uint64_t p_filesz; |
+ uint64_t p_memsz; |
+ uint64_t p_align; |
+} Elf64_Phdr; |
+ |
+struct elfbuf |
+{ |
+ const char *path; |
+ unsigned char *buf; |
+ size_t len; |
+ enum { ELFCLASS32 = 1, |
+ ELFCLASS64 = 2 } ei_class; |
+}; |
+ |
+#define ELFBUF_EHDR_LEN(elf) \ |
+ ((elf)->ei_class == ELFCLASS32 ? sizeof (Elf32_Ehdr) : \ |
+ sizeof (Elf64_Ehdr)) |
+ |
+#define ELFBUF_EHDR(elf, memb) \ |
+ ((elf)->ei_class == ELFCLASS32 ? \ |
+ ((Elf32_Ehdr *) (elf)->buf)->memb \ |
+ : ((Elf64_Ehdr *) (elf)->buf)->memb) |
+ |
+#define ELFBUF_PHDR_LEN(elf) \ |
+ ((elf)->ei_class == ELFCLASS32 ? sizeof (Elf32_Phdr) : \ |
+ sizeof (Elf64_Phdr)) |
+ |
+#define ELFBUF_PHDR(elf, idx, memb) \ |
+ ((elf)->ei_class == ELFCLASS32 ? \ |
+ ((Elf32_Phdr *) &(elf)->buf[((Elf32_Ehdr *)(elf)->buf) \ |
+ ->e_phoff])[idx].memb \ |
+ : ((Elf64_Phdr *) &(elf)->buf[((Elf64_Ehdr *)(elf)->buf) \ |
+ ->e_phoff])[idx].memb) |
+ |
+static void |
+exit_with_msg(const char *fmt, ...) |
+{ |
+ va_list ap; |
+ |
+ fflush (stdout); |
+ va_start (ap, fmt); |
+ vfprintf (stderr, fmt, ap); |
+ va_end (ap); |
+ |
+ if (errno) |
+ { |
+ fputs (": ", stderr); |
+ perror (NULL); |
+ } |
+ else |
+ fputc ('\n', stderr); |
+ exit (1); |
+} |
+ |
+static void |
+read_file (unsigned char **buf_ptr, size_t *len_ptr, FILE *fp) |
+{ |
+ size_t len = 0; |
+ size_t size = 1024; |
+ size_t chunk; |
+ unsigned char *buf = malloc (size); |
+ |
+ while ((chunk = fread (buf + len, 1, size - len, fp)) == size - len) |
+ { |
+ len = size; |
+ size *= 2; |
+ buf = realloc (buf, size); |
+ } |
+ len += chunk; |
+ *buf_ptr = buf; |
+ *len_ptr = len; |
+} |
+ |
+static void |
+write_file (unsigned char *buf, size_t len, FILE *fp) |
+{ |
+ fwrite (buf, 1, len, fp); |
+} |
+ |
+static void |
+elfbuf_init_from_file (struct elfbuf *elf, const char *path) |
+{ |
+ FILE *fp = fopen (path, "rb"); |
+ unsigned char *buf; |
+ size_t len; |
+ |
+ if (fp == NULL) |
+ exit_with_msg ("%s", path); |
+ |
+ read_file (&buf, &len, fp); |
+ fclose (fp); |
+ |
+ /* Validate ELF identification. */ |
+ if (len < 16 |
+ || buf[0] != 0x7f || buf[1] != 0x45 || buf[2] != 0x4c || buf[3] != 0x46 |
+ || buf[4] < 1 || buf[4] > 2 || buf[5] < 1 || buf[5] > 2) |
+ exit_with_msg ("%s: unsupported or invalid ELF file", path); |
+ |
+ elf->path = path; |
+ elf->buf = buf; |
+ elf->len = len; |
+ elf->ei_class = buf[4]; |
+ |
+ if (ELFBUF_EHDR_LEN (elf) > len |
+ || ELFBUF_EHDR (elf, e_phoff) > len |
+ || ELFBUF_EHDR (elf, e_phnum) > ((len - ELFBUF_EHDR (elf, e_phoff)) |
+ / ELFBUF_PHDR_LEN (elf)) ) |
+ exit_with_msg ("%s: unexpected end of data", path); |
+ |
+ if (ELFBUF_EHDR (elf, e_phentsize) != ELFBUF_PHDR_LEN (elf)) |
+ exit_with_msg ("%s: inconsistent ELF header", path); |
+} |
+ |
+static void |
+elfbuf_write_to_file (struct elfbuf *elf, const char *path) |
+{ |
+ FILE *fp = fopen (path, "wb"); |
+ |
+ if (fp == NULL) |
+ exit_with_msg ("%s", path); |
+ |
+ write_file (elf->buf, elf->len, fp); |
+ fclose (fp); |
+} |
+ |
+/* In the auxv note starting at OFFSET with size LEN, mask the hwcap |
+ field using the HWCAP_MASK. */ |
+ |
+static void |
+elfbuf_handle_auxv (struct elfbuf *elf, size_t offset, size_t len, |
+ unsigned long hwcap_mask) |
+{ |
+ size_t i; |
+ uint32_t *auxv32 = (uint32_t *) (elf->buf + offset); |
+ uint64_t *auxv64 = (uint64_t *) auxv32; |
+ size_t entry_size = elf->ei_class == ELFCLASS32 ? |
+ sizeof (auxv32[0]) : sizeof (auxv64[0]); |
+ |
+ for (i = 0; i < len / entry_size; i++) |
+ { |
+ uint64_t auxv_type = elf->ei_class == ELFCLASS32 ? |
+ auxv32[2 * i] : auxv64[2 * i]; |
+ |
+ if (auxv_type == 0) |
+ break; |
+ if (auxv_type != 16) |
+ continue; |
+ |
+ if (elf->ei_class == ELFCLASS32) |
+ auxv32[2 * i + 1] &= (uint32_t) hwcap_mask; |
+ else |
+ auxv64[2 * i + 1] &= (uint64_t) hwcap_mask; |
+ } |
+} |
+ |
+/* In the note segment starting at OFFSET with size LEN, make notes |
+ with type NOTE_TYPE unrecognizable by GDB. Also, mask the hwcap |
+ field of any auxv notes using the HWCAP_MASK. */ |
+ |
+static void |
+elfbuf_handle_note_segment (struct elfbuf *elf, size_t offset, size_t len, |
+ unsigned note_type, unsigned long hwcap_mask) |
+{ |
+ size_t pos = 0; |
+ |
+ while (pos + 12 < len) |
+ { |
+ uint32_t *note = (uint32_t *) (elf->buf + offset + pos); |
+ size_t desc_pos = pos + 12 + ((note[0] + 3) & ~3); |
+ size_t next_pos = desc_pos + ((note[1] + 3) & ~3); |
+ |
+ if (desc_pos > len || next_pos > len) |
+ exit_with_msg ("%s: corrupt notes data", elf->path); |
+ |
+ if (note[2] == note_type) |
+ note[2] |= 0xff000000; |
+ else if (note[2] == 6 && hwcap_mask != 0) |
+ elfbuf_handle_auxv (elf, offset + desc_pos, note[1], |
+ hwcap_mask); |
+ pos = next_pos; |
+ } |
+} |
+ |
+static void |
+elfbuf_handle_core_notes (struct elfbuf *elf, unsigned note_type, |
+ unsigned long hwcap_mask) |
+{ |
+ unsigned ph_idx; |
+ |
+ if (ELFBUF_EHDR (elf, e_type) != 4) |
+ exit_with_msg ("%s: not a core file", elf->path); |
+ |
+ /* Iterate over program headers. */ |
+ for (ph_idx = 0; ph_idx != ELFBUF_EHDR (elf, e_phnum); ph_idx++) |
+ { |
+ size_t offset = ELFBUF_PHDR (elf, ph_idx, p_offset); |
+ size_t filesz = ELFBUF_PHDR (elf, ph_idx, p_filesz); |
+ |
+ if (offset > elf->len || filesz > elf->len - offset) |
+ exit_with_msg ("%s: unexpected end of data", elf->path); |
+ |
+ /* Deal with NOTE segments only. */ |
+ if (ELFBUF_PHDR (elf, ph_idx, p_type) != 4) |
+ continue; |
+ elfbuf_handle_note_segment (elf, offset, filesz, note_type, |
+ hwcap_mask); |
+ } |
+} |
+ |
+int |
+main (int argc, char *argv[]) |
+{ |
+ unsigned note_type; |
+ unsigned long hwcap_mask = 0; |
+ struct elfbuf elf; |
+ |
+ if (argc < 4) |
+ { |
+ abort (); |
+ } |
+ |
+ if (sscanf (argv[3], "%u", ¬e_type) != 1) |
+ exit_with_msg ("%s: bad command line arguments\n", argv[0]); |
+ |
+ if (argc >= 5) |
+ { |
+ if (sscanf (argv[4], "%lu", &hwcap_mask) != 1) |
+ exit_with_msg ("%s: bad command line arguments\n", argv[0]); |
+ } |
+ |
+ elfbuf_init_from_file (&elf, argv[1]); |
+ elfbuf_handle_core_notes (&elf, note_type, hwcap_mask); |
+ elfbuf_write_to_file (&elf, argv[2]); |
+ |
+ return 0; |
+} |