xref: /qemu/target/riscv/arch_dump.c (revision 1af0006ab959864dfa2f59e9136c5fb93000b61f)
143a96588SYifei Jiang /* Support for writing ELF notes for RISC-V architectures
243a96588SYifei Jiang  *
343a96588SYifei Jiang  * Copyright (C) 2021 Huawei Technologies Co., Ltd
443a96588SYifei Jiang  *
543a96588SYifei Jiang  * This program is free software; you can redistribute it and/or modify it
643a96588SYifei Jiang  * under the terms and conditions of the GNU General Public License,
743a96588SYifei Jiang  * version 2 or later, as published by the Free Software Foundation.
843a96588SYifei Jiang  *
943a96588SYifei Jiang  * This program is distributed in the hope it will be useful, but WITHOUT
1043a96588SYifei Jiang  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1143a96588SYifei Jiang  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
1243a96588SYifei Jiang  * more details.
1343a96588SYifei Jiang  *
1443a96588SYifei Jiang  * You should have received a copy of the GNU General Public License along with
1543a96588SYifei Jiang  * this program.  If not, see <http://www.gnu.org/licenses/>.
1643a96588SYifei Jiang  */
1743a96588SYifei Jiang 
1843a96588SYifei Jiang #include "qemu/osdep.h"
1943a96588SYifei Jiang #include "cpu.h"
2043a96588SYifei Jiang #include "elf.h"
2143a96588SYifei Jiang #include "sysemu/dump.h"
2243a96588SYifei Jiang 
2343a96588SYifei Jiang /* struct user_regs_struct from arch/riscv/include/uapi/asm/ptrace.h */
2443a96588SYifei Jiang struct riscv64_user_regs {
2543a96588SYifei Jiang     uint64_t pc;
2643a96588SYifei Jiang     uint64_t regs[31];
2743a96588SYifei Jiang } QEMU_PACKED;
2843a96588SYifei Jiang 
2943a96588SYifei Jiang QEMU_BUILD_BUG_ON(sizeof(struct riscv64_user_regs) != 256);
3043a96588SYifei Jiang 
3143a96588SYifei Jiang /* struct elf_prstatus from include/linux/elfcore.h */
3243a96588SYifei Jiang struct riscv64_elf_prstatus {
3343a96588SYifei Jiang     char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */
3443a96588SYifei Jiang     uint32_t pr_pid;
3543a96588SYifei Jiang     char pad2[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) -
3643a96588SYifei Jiang                             offsetof(struct elf_prstatus, pr_ppid) */
3743a96588SYifei Jiang     struct riscv64_user_regs pr_reg;
3843a96588SYifei Jiang     char pad3[8];
3943a96588SYifei Jiang } QEMU_PACKED;
4043a96588SYifei Jiang 
4143a96588SYifei Jiang QEMU_BUILD_BUG_ON(sizeof(struct riscv64_elf_prstatus) != 376);
4243a96588SYifei Jiang 
4343a96588SYifei Jiang struct riscv64_note {
4443a96588SYifei Jiang     Elf64_Nhdr hdr;
4543a96588SYifei Jiang     char name[8]; /* align_up(sizeof("CORE"), 4) */
4643a96588SYifei Jiang     struct riscv64_elf_prstatus prstatus;
4743a96588SYifei Jiang } QEMU_PACKED;
4843a96588SYifei Jiang 
4943a96588SYifei Jiang #define RISCV64_NOTE_HEADER_SIZE offsetof(struct riscv64_note, prstatus)
5043a96588SYifei Jiang #define RISCV64_PRSTATUS_NOTE_SIZE \
5143a96588SYifei Jiang             (RISCV64_NOTE_HEADER_SIZE + sizeof(struct riscv64_elf_prstatus))
5243a96588SYifei Jiang 
5343a96588SYifei Jiang static void riscv64_note_init(struct riscv64_note *note, DumpState *s,
5443a96588SYifei Jiang                               const char *name, Elf64_Word namesz,
5543a96588SYifei Jiang                               Elf64_Word type, Elf64_Word descsz)
5643a96588SYifei Jiang {
5743a96588SYifei Jiang     memset(note, 0, sizeof(*note));
5843a96588SYifei Jiang 
5943a96588SYifei Jiang     note->hdr.n_namesz = cpu_to_dump32(s, namesz);
6043a96588SYifei Jiang     note->hdr.n_descsz = cpu_to_dump32(s, descsz);
6143a96588SYifei Jiang     note->hdr.n_type = cpu_to_dump32(s, type);
6243a96588SYifei Jiang 
6343a96588SYifei Jiang     memcpy(note->name, name, namesz);
6443a96588SYifei Jiang }
6543a96588SYifei Jiang 
6643a96588SYifei Jiang int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
67*1af0006aSJanosch Frank                                int cpuid, DumpState *s)
6843a96588SYifei Jiang {
6943a96588SYifei Jiang     struct riscv64_note note;
7043a96588SYifei Jiang     RISCVCPU *cpu = RISCV_CPU(cs);
7143a96588SYifei Jiang     CPURISCVState *env = &cpu->env;
7243a96588SYifei Jiang     int ret, i = 0;
7343a96588SYifei Jiang     const char name[] = "CORE";
7443a96588SYifei Jiang 
7543a96588SYifei Jiang     riscv64_note_init(&note, s, name, sizeof(name),
7643a96588SYifei Jiang                       NT_PRSTATUS, sizeof(note.prstatus));
7743a96588SYifei Jiang 
7843a96588SYifei Jiang     note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
7943a96588SYifei Jiang 
8043a96588SYifei Jiang     note.prstatus.pr_reg.pc = cpu_to_dump64(s, env->pc);
8143a96588SYifei Jiang 
8243a96588SYifei Jiang     for (i = 0; i < 31; i++) {
8343a96588SYifei Jiang         note.prstatus.pr_reg.regs[i] = cpu_to_dump64(s, env->gpr[i + 1]);
8443a96588SYifei Jiang     }
8543a96588SYifei Jiang 
8643a96588SYifei Jiang     ret = f(&note, RISCV64_PRSTATUS_NOTE_SIZE, s);
8743a96588SYifei Jiang     if (ret < 0) {
8843a96588SYifei Jiang         return -1;
8943a96588SYifei Jiang     }
9043a96588SYifei Jiang 
9143a96588SYifei Jiang     return ret;
9243a96588SYifei Jiang }
9343a96588SYifei Jiang 
9443a96588SYifei Jiang struct riscv32_user_regs {
9543a96588SYifei Jiang     uint32_t pc;
9643a96588SYifei Jiang     uint32_t regs[31];
9743a96588SYifei Jiang } QEMU_PACKED;
9843a96588SYifei Jiang 
9943a96588SYifei Jiang QEMU_BUILD_BUG_ON(sizeof(struct riscv32_user_regs) != 128);
10043a96588SYifei Jiang 
10143a96588SYifei Jiang struct riscv32_elf_prstatus {
10243a96588SYifei Jiang     char pad1[24]; /* 24 == offsetof(struct elf_prstatus, pr_pid) */
10343a96588SYifei Jiang     uint32_t pr_pid;
10443a96588SYifei Jiang     char pad2[44]; /* 44 == offsetof(struct elf_prstatus, pr_reg) -
10543a96588SYifei Jiang                             offsetof(struct elf_prstatus, pr_ppid) */
10643a96588SYifei Jiang     struct riscv32_user_regs pr_reg;
10743a96588SYifei Jiang     char pad3[4];
10843a96588SYifei Jiang } QEMU_PACKED;
10943a96588SYifei Jiang 
11043a96588SYifei Jiang QEMU_BUILD_BUG_ON(sizeof(struct riscv32_elf_prstatus) != 204);
11143a96588SYifei Jiang 
11243a96588SYifei Jiang struct riscv32_note {
11343a96588SYifei Jiang     Elf32_Nhdr hdr;
11443a96588SYifei Jiang     char name[8]; /* align_up(sizeof("CORE"), 4) */
11543a96588SYifei Jiang     struct riscv32_elf_prstatus prstatus;
11643a96588SYifei Jiang } QEMU_PACKED;
11743a96588SYifei Jiang 
11843a96588SYifei Jiang #define RISCV32_NOTE_HEADER_SIZE offsetof(struct riscv32_note, prstatus)
11943a96588SYifei Jiang #define RISCV32_PRSTATUS_NOTE_SIZE \
12043a96588SYifei Jiang             (RISCV32_NOTE_HEADER_SIZE + sizeof(struct riscv32_elf_prstatus))
12143a96588SYifei Jiang 
12243a96588SYifei Jiang static void riscv32_note_init(struct riscv32_note *note, DumpState *s,
12343a96588SYifei Jiang                               const char *name, Elf32_Word namesz,
12443a96588SYifei Jiang                               Elf32_Word type, Elf32_Word descsz)
12543a96588SYifei Jiang {
12643a96588SYifei Jiang     memset(note, 0, sizeof(*note));
12743a96588SYifei Jiang 
12843a96588SYifei Jiang     note->hdr.n_namesz = cpu_to_dump32(s, namesz);
12943a96588SYifei Jiang     note->hdr.n_descsz = cpu_to_dump32(s, descsz);
13043a96588SYifei Jiang     note->hdr.n_type = cpu_to_dump32(s, type);
13143a96588SYifei Jiang 
13243a96588SYifei Jiang     memcpy(note->name, name, namesz);
13343a96588SYifei Jiang }
13443a96588SYifei Jiang 
13543a96588SYifei Jiang int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
136*1af0006aSJanosch Frank                                int cpuid, DumpState *s)
13743a96588SYifei Jiang {
13843a96588SYifei Jiang     struct riscv32_note note;
13943a96588SYifei Jiang     RISCVCPU *cpu = RISCV_CPU(cs);
14043a96588SYifei Jiang     CPURISCVState *env = &cpu->env;
14143a96588SYifei Jiang     int ret, i;
14243a96588SYifei Jiang     const char name[] = "CORE";
14343a96588SYifei Jiang 
14443a96588SYifei Jiang     riscv32_note_init(&note, s, name, sizeof(name),
14543a96588SYifei Jiang                       NT_PRSTATUS, sizeof(note.prstatus));
14643a96588SYifei Jiang 
14743a96588SYifei Jiang     note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
14843a96588SYifei Jiang 
14943a96588SYifei Jiang     note.prstatus.pr_reg.pc = cpu_to_dump32(s, env->pc);
15043a96588SYifei Jiang 
15143a96588SYifei Jiang     for (i = 0; i < 31; i++) {
15243a96588SYifei Jiang         note.prstatus.pr_reg.regs[i] = cpu_to_dump32(s, env->gpr[i + 1]);
15343a96588SYifei Jiang     }
15443a96588SYifei Jiang 
15543a96588SYifei Jiang     ret = f(&note, RISCV32_PRSTATUS_NOTE_SIZE, s);
15643a96588SYifei Jiang     if (ret < 0) {
15743a96588SYifei Jiang         return -1;
15843a96588SYifei Jiang     }
15943a96588SYifei Jiang 
16043a96588SYifei Jiang     return ret;
16143a96588SYifei Jiang }
16243a96588SYifei Jiang 
16343a96588SYifei Jiang int cpu_get_dump_info(ArchDumpInfo *info,
16443a96588SYifei Jiang                       const GuestPhysBlockList *guest_phys_blocks)
16543a96588SYifei Jiang {
16643a96588SYifei Jiang     RISCVCPU *cpu;
16743a96588SYifei Jiang     CPURISCVState *env;
16843a96588SYifei Jiang 
16943a96588SYifei Jiang     if (first_cpu == NULL) {
17043a96588SYifei Jiang         return -1;
17143a96588SYifei Jiang     }
17243a96588SYifei Jiang     cpu = RISCV_CPU(first_cpu);
17343a96588SYifei Jiang     env = &cpu->env;
17443a96588SYifei Jiang 
17543a96588SYifei Jiang     info->d_machine = EM_RISCV;
17643a96588SYifei Jiang 
17743a96588SYifei Jiang #if defined(TARGET_RISCV64)
17843a96588SYifei Jiang     info->d_class = ELFCLASS64;
17943a96588SYifei Jiang #else
18043a96588SYifei Jiang     info->d_class = ELFCLASS32;
18143a96588SYifei Jiang #endif
18243a96588SYifei Jiang 
18343a96588SYifei Jiang     info->d_endian = (env->mstatus & MSTATUS_UBE) != 0
18443a96588SYifei Jiang                      ? ELFDATA2MSB : ELFDATA2LSB;
18543a96588SYifei Jiang 
18643a96588SYifei Jiang     return 0;
18743a96588SYifei Jiang }
18843a96588SYifei Jiang 
18943a96588SYifei Jiang ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
19043a96588SYifei Jiang {
19143a96588SYifei Jiang     size_t note_size;
19243a96588SYifei Jiang 
19343a96588SYifei Jiang     if (class == ELFCLASS64) {
19443a96588SYifei Jiang         note_size = RISCV64_PRSTATUS_NOTE_SIZE;
19543a96588SYifei Jiang     } else {
19643a96588SYifei Jiang         note_size = RISCV32_PRSTATUS_NOTE_SIZE;
19743a96588SYifei Jiang     }
19843a96588SYifei Jiang 
19943a96588SYifei Jiang     return note_size * nr_cpus;
20043a96588SYifei Jiang }
201