summaryrefslogtreecommitdiffstats
path: root/contrib/elf2dmp/qemu_elf.c
diff options
context:
space:
mode:
authorPeter Maydell2018-10-02 19:27:18 +0200
committerPeter Maydell2018-10-02 19:27:18 +0200
commitdafd95053611aa14dda40266857608d12ddce658 (patch)
treeb414d9e2871c2a701ed3c42a15cfd7d289a9db7e /contrib/elf2dmp/qemu_elf.c
parentMerge remote-tracking branch 'remotes/dgibson/tags/libfdt-20181002' into staging (diff)
parenthw/scsi/mptendian: Avoid taking address of fields in packed structs (diff)
downloadqemu-dafd95053611aa14dda40266857608d12ddce658.tar.gz
qemu-dafd95053611aa14dda40266857608d12ddce658.tar.xz
qemu-dafd95053611aa14dda40266857608d12ddce658.zip
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* configure fix for environment variables (Daniel) * fix memory leaks (Alex) * x86_64 MTTCG fixes (Emilio) * introduce atomic64 (Emilio) * Fix for virtio hang (Fam, myself) * SH serial port fix (Geert) * Deprecate rotation_rate for scsi-block (Fam) * Extend memory-backend-file availability to all POSIX hosts (Hikaru) * Memory API cleanups and fixes (Igor, Li Qiang, Peter, Philippe) * MSI/IOMMU fix (Jan) * Socket reconnection fixes (Marc-André) * icount fixes (Emilio, myself) * QSP fixes for Coverity (myself) * Some record/replay improovements (Pavel) * Packed struct fixes (Peter) * Windows dump fixes and elf2dmp (Viktor) * kbmclock fix (Yongji) # gpg: Signature made Tue 02 Oct 2018 18:13:12 BST # gpg: using RSA key BFFBD25F78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: (80 commits) hw/scsi/mptendian: Avoid taking address of fields in packed structs cpus: fix TCG kick timer leak docs/devel/memory.txt: Document _with_attrs accessors hw/nvram/fw_cfg: Use memberwise copy of MemoryRegionOps struct memory: Remove old_mmio accessors memory: Fix access_with_adjusted_size(small size) on big-endian memory regions memory: Refactor common shifting code from accessors memory: Use MAKE_64BIT_MASK() virtio: do not take address of packed members replay: replay BH for IDE trim operation hostmem-file: make available memory-backend-file on POSIX-based hosts target/i386: fix translation for icount mode hvf: drop unused variable qom/object: add some interface asserts accel/tcg: Remove dead code lsi53c895a: convert to trace-events scsi-block: Deprecate rotation_rate kvmclock: run KVM_KVMCLOCK_CTRL ioctl in vcpu thread MAINTAINERS: add myself as elf2dmp maintainer contrib: add elf2dmp tool ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'contrib/elf2dmp/qemu_elf.c')
-rw-r--r--contrib/elf2dmp/qemu_elf.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/contrib/elf2dmp/qemu_elf.c b/contrib/elf2dmp/qemu_elf.c
new file mode 100644
index 0000000000..e9c0d2534a
--- /dev/null
+++ b/contrib/elf2dmp/qemu_elf.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2018 Virtuozzo International GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "err.h"
+#include "qemu_elf.h"
+
+#define QEMU_NOTE_NAME "QEMU"
+
+#ifndef ROUND_UP
+#define ROUND_UP(n, d) (((n) + (d) - 1) & -(0 ? (n) : (d)))
+#endif
+
+#ifndef DIV_ROUND_UP
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+#endif
+
+#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \
+ ((DIV_ROUND_UP((hdr_size), 4) + \
+ DIV_ROUND_UP((name_size), 4) + \
+ DIV_ROUND_UP((desc_size), 4)) * 4)
+
+int is_system(QEMUCPUState *s)
+{
+ return s->gs.base >> 63;
+}
+
+static char *nhdr_get_name(Elf64_Nhdr *nhdr)
+{
+ return (char *)nhdr + ROUND_UP(sizeof(*nhdr), 4);
+}
+
+static void *nhdr_get_desc(Elf64_Nhdr *nhdr)
+{
+ return nhdr_get_name(nhdr) + ROUND_UP(nhdr->n_namesz, 4);
+}
+
+static Elf64_Nhdr *nhdr_get_next(Elf64_Nhdr *nhdr)
+{
+ return (void *)((uint8_t *)nhdr + ELF_NOTE_SIZE(sizeof(*nhdr),
+ nhdr->n_namesz, nhdr->n_descsz));
+}
+
+Elf64_Phdr *elf64_getphdr(void *map)
+{
+ Elf64_Ehdr *ehdr = map;
+ Elf64_Phdr *phdr = (void *)((uint8_t *)map + ehdr->e_phoff);
+
+ return phdr;
+}
+
+Elf64_Half elf_getphdrnum(void *map)
+{
+ Elf64_Ehdr *ehdr = map;
+
+ return ehdr->e_phnum;
+}
+
+static int init_states(QEMU_Elf *qe)
+{
+ Elf64_Phdr *phdr = elf64_getphdr(qe->map);
+ Elf64_Nhdr *start = (void *)((uint8_t *)qe->map + phdr[0].p_offset);
+ Elf64_Nhdr *end = (void *)((uint8_t *)start + phdr[0].p_memsz);
+ Elf64_Nhdr *nhdr;
+ size_t cpu_nr = 0;
+
+ if (phdr[0].p_type != PT_NOTE) {
+ eprintf("Failed to find PT_NOTE\n");
+ return 1;
+ }
+
+ qe->has_kernel_gs_base = 1;
+
+ for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
+ if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
+ QEMUCPUState *state = nhdr_get_desc(nhdr);
+
+ if (state->size < sizeof(*state)) {
+ eprintf("CPU #%zu: QEMU CPU state size %u doesn't match\n",
+ cpu_nr, state->size);
+ /*
+ * We assume either every QEMU CPU state has KERNEL_GS_BASE or
+ * no one has.
+ */
+ qe->has_kernel_gs_base = 0;
+ }
+ cpu_nr++;
+ }
+ }
+
+ printf("%zu CPU states has been found\n", cpu_nr);
+
+ qe->state = malloc(sizeof(*qe->state) * cpu_nr);
+ if (!qe->state) {
+ return 1;
+ }
+
+ cpu_nr = 0;
+
+ for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
+ if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
+ qe->state[cpu_nr] = nhdr_get_desc(nhdr);
+ cpu_nr++;
+ }
+ }
+
+ qe->state_nr = cpu_nr;
+
+ return 0;
+}
+
+static void exit_states(QEMU_Elf *qe)
+{
+ free(qe->state);
+}
+
+int QEMU_Elf_init(QEMU_Elf *qe, const char *filename)
+{
+ int err = 0;
+ struct stat st;
+
+ qe->fd = open(filename, O_RDONLY, 0);
+ if (qe->fd == -1) {
+ eprintf("Failed to open ELF dump file \'%s\'\n", filename);
+ return 1;
+ }
+
+ fstat(qe->fd, &st);
+ qe->size = st.st_size;
+
+ qe->map = mmap(NULL, qe->size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, qe->fd, 0);
+ if (qe->map == MAP_FAILED) {
+ eprintf("Failed to map ELF file\n");
+ err = 1;
+ goto out_fd;
+ }
+
+ if (init_states(qe)) {
+ eprintf("Failed to extract QEMU CPU states\n");
+ err = 1;
+ goto out_unmap;
+ }
+
+ return 0;
+
+out_unmap:
+ munmap(qe->map, qe->size);
+out_fd:
+ close(qe->fd);
+
+ return err;
+}
+
+void QEMU_Elf_exit(QEMU_Elf *qe)
+{
+ exit_states(qe);
+ munmap(qe->map, qe->size);
+ close(qe->fd);
+}