qemu/target/riscv/arch_dump.c
<<
>>
Prefs
   1/* Support for writing ELF notes for RISC-V architectures
   2 *
   3 * Copyright (C) 2021 Huawei Technologies Co., Ltd
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2 or later, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program.  If not, see <http://www.gnu.org/licenses/>.
  16 */
  17
  18#include "qemu/osdep.h"
  19#include "cpu.h"
  20#include "elf.h"
  21#include "sysemu/dump.h"
  22
  23/* struct user_regs_struct from arch/riscv/include/uapi/asm/ptrace.h */
  24struct riscv64_user_regs {
  25    uint64_t pc;
  26    uint64_t regs[31];
  27} QEMU_PACKED;
  28
  29QEMU_BUILD_BUG_ON(sizeof(struct riscv64_user_regs) != 256);
  30
  31/* struct elf_prstatus from include/linux/elfcore.h */
  32struct riscv64_elf_prstatus {
  33    char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */
  34    uint32_t pr_pid;
  35    char pad2[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) -
  36                            offsetof(struct elf_prstatus, pr_ppid) */
  37    struct riscv64_user_regs pr_reg;
  38    char pad3[8];
  39} QEMU_PACKED;
  40
  41QEMU_BUILD_BUG_ON(sizeof(struct riscv64_elf_prstatus) != 376);
  42
  43struct riscv64_note {
  44    Elf64_Nhdr hdr;
  45    char name[8]; /* align_up(sizeof("CORE"), 4) */
  46    struct riscv64_elf_prstatus prstatus;
  47} QEMU_PACKED;
  48
  49#define RISCV64_NOTE_HEADER_SIZE offsetof(struct riscv64_note, prstatus)
  50#define RISCV64_PRSTATUS_NOTE_SIZE \
  51            (RISCV64_NOTE_HEADER_SIZE + sizeof(struct riscv64_elf_prstatus))
  52
  53static void riscv64_note_init(struct riscv64_note *note, DumpState *s,
  54                              const char *name, Elf64_Word namesz,
  55                              Elf64_Word type, Elf64_Word descsz)
  56{
  57    memset(note, 0, sizeof(*note));
  58
  59    note->hdr.n_namesz = cpu_to_dump32(s, namesz);
  60    note->hdr.n_descsz = cpu_to_dump32(s, descsz);
  61    note->hdr.n_type = cpu_to_dump32(s, type);
  62
  63    memcpy(note->name, name, namesz);
  64}
  65
  66int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
  67                               int cpuid, void *opaque)
  68{
  69    struct riscv64_note note;
  70    RISCVCPU *cpu = RISCV_CPU(cs);
  71    CPURISCVState *env = &cpu->env;
  72    DumpState *s = opaque;
  73    int ret, i = 0;
  74    const char name[] = "CORE";
  75
  76    riscv64_note_init(&note, s, name, sizeof(name),
  77                      NT_PRSTATUS, sizeof(note.prstatus));
  78
  79    note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
  80
  81    note.prstatus.pr_reg.pc = cpu_to_dump64(s, env->pc);
  82
  83    for (i = 0; i < 31; i++) {
  84        note.prstatus.pr_reg.regs[i] = cpu_to_dump64(s, env->gpr[i + 1]);
  85    }
  86
  87    ret = f(&note, RISCV64_PRSTATUS_NOTE_SIZE, s);
  88    if (ret < 0) {
  89        return -1;
  90    }
  91
  92    return ret;
  93}
  94
  95struct riscv32_user_regs {
  96    uint32_t pc;
  97    uint32_t regs[31];
  98} QEMU_PACKED;
  99
 100QEMU_BUILD_BUG_ON(sizeof(struct riscv32_user_regs) != 128);
 101
 102struct riscv32_elf_prstatus {
 103    char pad1[24]; /* 24 == offsetof(struct elf_prstatus, pr_pid) */
 104    uint32_t pr_pid;
 105    char pad2[44]; /* 44 == offsetof(struct elf_prstatus, pr_reg) -
 106                            offsetof(struct elf_prstatus, pr_ppid) */
 107    struct riscv32_user_regs pr_reg;
 108    char pad3[4];
 109} QEMU_PACKED;
 110
 111QEMU_BUILD_BUG_ON(sizeof(struct riscv32_elf_prstatus) != 204);
 112
 113struct riscv32_note {
 114    Elf32_Nhdr hdr;
 115    char name[8]; /* align_up(sizeof("CORE"), 4) */
 116    struct riscv32_elf_prstatus prstatus;
 117} QEMU_PACKED;
 118
 119#define RISCV32_NOTE_HEADER_SIZE offsetof(struct riscv32_note, prstatus)
 120#define RISCV32_PRSTATUS_NOTE_SIZE \
 121            (RISCV32_NOTE_HEADER_SIZE + sizeof(struct riscv32_elf_prstatus))
 122
 123static void riscv32_note_init(struct riscv32_note *note, DumpState *s,
 124                              const char *name, Elf32_Word namesz,
 125                              Elf32_Word type, Elf32_Word descsz)
 126{
 127    memset(note, 0, sizeof(*note));
 128
 129    note->hdr.n_namesz = cpu_to_dump32(s, namesz);
 130    note->hdr.n_descsz = cpu_to_dump32(s, descsz);
 131    note->hdr.n_type = cpu_to_dump32(s, type);
 132
 133    memcpy(note->name, name, namesz);
 134}
 135
 136int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
 137                               int cpuid, void *opaque)
 138{
 139    struct riscv32_note note;
 140    RISCVCPU *cpu = RISCV_CPU(cs);
 141    CPURISCVState *env = &cpu->env;
 142    DumpState *s = opaque;
 143    int ret, i;
 144    const char name[] = "CORE";
 145
 146    riscv32_note_init(&note, s, name, sizeof(name),
 147                      NT_PRSTATUS, sizeof(note.prstatus));
 148
 149    note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
 150
 151    note.prstatus.pr_reg.pc = cpu_to_dump32(s, env->pc);
 152
 153    for (i = 0; i < 31; i++) {
 154        note.prstatus.pr_reg.regs[i] = cpu_to_dump32(s, env->gpr[i + 1]);
 155    }
 156
 157    ret = f(&note, RISCV32_PRSTATUS_NOTE_SIZE, s);
 158    if (ret < 0) {
 159        return -1;
 160    }
 161
 162    return ret;
 163}
 164
 165int cpu_get_dump_info(ArchDumpInfo *info,
 166                      const GuestPhysBlockList *guest_phys_blocks)
 167{
 168    RISCVCPU *cpu;
 169    CPURISCVState *env;
 170
 171    if (first_cpu == NULL) {
 172        return -1;
 173    }
 174    cpu = RISCV_CPU(first_cpu);
 175    env = &cpu->env;
 176
 177    info->d_machine = EM_RISCV;
 178
 179#if defined(TARGET_RISCV64)
 180    info->d_class = ELFCLASS64;
 181#else
 182    info->d_class = ELFCLASS32;
 183#endif
 184
 185    info->d_endian = (env->mstatus & MSTATUS_UBE) != 0
 186                     ? ELFDATA2MSB : ELFDATA2LSB;
 187
 188    return 0;
 189}
 190
 191ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
 192{
 193    size_t note_size;
 194
 195    if (class == ELFCLASS64) {
 196        note_size = RISCV64_PRSTATUS_NOTE_SIZE;
 197    } else {
 198        note_size = RISCV32_PRSTATUS_NOTE_SIZE;
 199    }
 200
 201    return note_size * nr_cpus;
 202}
 203