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