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, DumpState *s)
  68{
  69    struct riscv64_note note;
  70    RISCVCPU *cpu = RISCV_CPU(cs);
  71    CPURISCVState *env = &cpu->env;
  72    int ret, i = 0;
  73    const char name[] = "CORE";
  74
  75    riscv64_note_init(&note, s, name, sizeof(name),
  76                      NT_PRSTATUS, sizeof(note.prstatus));
  77
  78    note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
  79
  80    note.prstatus.pr_reg.pc = cpu_to_dump64(s, env->pc);
  81
  82    for (i = 0; i < 31; i++) {
  83        note.prstatus.pr_reg.regs[i] = cpu_to_dump64(s, env->gpr[i + 1]);
  84    }
  85
  86    ret = f(&note, RISCV64_PRSTATUS_NOTE_SIZE, s);
  87    if (ret < 0) {
  88        return -1;
  89    }
  90
  91    return ret;
  92}
  93
  94struct riscv32_user_regs {
  95    uint32_t pc;
  96    uint32_t regs[31];
  97} QEMU_PACKED;
  98
  99QEMU_BUILD_BUG_ON(sizeof(struct riscv32_user_regs) != 128);
 100
 101struct riscv32_elf_prstatus {
 102    char pad1[24]; /* 24 == offsetof(struct elf_prstatus, pr_pid) */
 103    uint32_t pr_pid;
 104    char pad2[44]; /* 44 == offsetof(struct elf_prstatus, pr_reg) -
 105                            offsetof(struct elf_prstatus, pr_ppid) */
 106    struct riscv32_user_regs pr_reg;
 107    char pad3[4];
 108} QEMU_PACKED;
 109
 110QEMU_BUILD_BUG_ON(sizeof(struct riscv32_elf_prstatus) != 204);
 111
 112struct riscv32_note {
 113    Elf32_Nhdr hdr;
 114    char name[8]; /* align_up(sizeof("CORE"), 4) */
 115    struct riscv32_elf_prstatus prstatus;
 116} QEMU_PACKED;
 117
 118#define RISCV32_NOTE_HEADER_SIZE offsetof(struct riscv32_note, prstatus)
 119#define RISCV32_PRSTATUS_NOTE_SIZE \
 120            (RISCV32_NOTE_HEADER_SIZE + sizeof(struct riscv32_elf_prstatus))
 121
 122static void riscv32_note_init(struct riscv32_note *note, DumpState *s,
 123                              const char *name, Elf32_Word namesz,
 124                              Elf32_Word type, Elf32_Word descsz)
 125{
 126    memset(note, 0, sizeof(*note));
 127
 128    note->hdr.n_namesz = cpu_to_dump32(s, namesz);
 129    note->hdr.n_descsz = cpu_to_dump32(s, descsz);
 130    note->hdr.n_type = cpu_to_dump32(s, type);
 131
 132    memcpy(note->name, name, namesz);
 133}
 134
 135int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
 136                               int cpuid, DumpState *s)
 137{
 138    struct riscv32_note note;
 139    RISCVCPU *cpu = RISCV_CPU(cs);
 140    CPURISCVState *env = &cpu->env;
 141    int ret, i;
 142    const char name[] = "CORE";
 143
 144    riscv32_note_init(&note, s, name, sizeof(name),
 145                      NT_PRSTATUS, sizeof(note.prstatus));
 146
 147    note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
 148
 149    note.prstatus.pr_reg.pc = cpu_to_dump32(s, env->pc);
 150
 151    for (i = 0; i < 31; i++) {
 152        note.prstatus.pr_reg.regs[i] = cpu_to_dump32(s, env->gpr[i + 1]);
 153    }
 154
 155    ret = f(&note, RISCV32_PRSTATUS_NOTE_SIZE, s);
 156    if (ret < 0) {
 157        return -1;
 158    }
 159
 160    return ret;
 161}
 162
 163int cpu_get_dump_info(ArchDumpInfo *info,
 164                      const GuestPhysBlockList *guest_phys_blocks)
 165{
 166    RISCVCPU *cpu;
 167    CPURISCVState *env;
 168
 169    if (first_cpu == NULL) {
 170        return -1;
 171    }
 172    cpu = RISCV_CPU(first_cpu);
 173    env = &cpu->env;
 174
 175    info->d_machine = EM_RISCV;
 176
 177#if defined(TARGET_RISCV64)
 178    info->d_class = ELFCLASS64;
 179#else
 180    info->d_class = ELFCLASS32;
 181#endif
 182
 183    info->d_endian = (env->mstatus & MSTATUS_UBE) != 0
 184                     ? ELFDATA2MSB : ELFDATA2LSB;
 185
 186    return 0;
 187}
 188
 189ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
 190{
 191    size_t note_size;
 192
 193    if (class == ELFCLASS64) {
 194        note_size = RISCV64_PRSTATUS_NOTE_SIZE;
 195    } else {
 196        note_size = RISCV32_PRSTATUS_NOTE_SIZE;
 197    }
 198
 199    return note_size * nr_cpus;
 200}
 201