1 /* Support for writing ELF notes for ARM architectures
3 * Copyright (C) 2015 Red Hat Inc.
5 * Author: Andrew Jones <drjones@redhat.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
24 #include "sysemu/dump.h"
26 /* struct user_pt_regs from arch/arm64/include/uapi/asm/ptrace.h */
27 struct aarch64_user_regs
{
34 QEMU_BUILD_BUG_ON(sizeof(struct aarch64_user_regs
) != 272);
36 /* struct elf_prstatus from include/uapi/linux/elfcore.h */
37 struct aarch64_elf_prstatus
{
38 char pad1
[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */
40 char pad2
[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) -
41 offsetof(struct elf_prstatus, pr_ppid) */
42 struct aarch64_user_regs pr_reg
;
47 QEMU_BUILD_BUG_ON(sizeof(struct aarch64_elf_prstatus
) != 392);
49 /* struct user_fpsimd_state from arch/arm64/include/uapi/asm/ptrace.h
51 * While the vregs member of user_fpsimd_state is of type __uint128_t,
52 * QEMU uses an array of uint64_t, where the high half of the 128-bit
53 * value is always in the 2n+1'th index. Thus we also break the 128-
54 * bit values into two halves in this reproduction of user_fpsimd_state.
56 struct aarch64_user_vfp_state
{
63 QEMU_BUILD_BUG_ON(sizeof(struct aarch64_user_vfp_state
) != 528);
67 char name
[8]; /* align_up(sizeof("CORE"), 4) */
69 struct aarch64_elf_prstatus prstatus
;
70 struct aarch64_user_vfp_state vfp
;
74 #define AARCH64_NOTE_HEADER_SIZE offsetof(struct aarch64_note, prstatus)
75 #define AARCH64_PRSTATUS_NOTE_SIZE \
76 (AARCH64_NOTE_HEADER_SIZE + sizeof(struct aarch64_elf_prstatus))
77 #define AARCH64_PRFPREG_NOTE_SIZE \
78 (AARCH64_NOTE_HEADER_SIZE + sizeof(struct aarch64_user_vfp_state))
80 static void aarch64_note_init(struct aarch64_note
*note
, DumpState
*s
,
81 const char *name
, Elf64_Word namesz
,
82 Elf64_Word type
, Elf64_Word descsz
)
84 memset(note
, 0, sizeof(*note
));
86 note
->hdr
.n_namesz
= cpu_to_dump32(s
, namesz
);
87 note
->hdr
.n_descsz
= cpu_to_dump32(s
, descsz
);
88 note
->hdr
.n_type
= cpu_to_dump32(s
, type
);
90 memcpy(note
->name
, name
, namesz
);
93 static int aarch64_write_elf64_prfpreg(WriteCoreDumpFunction f
,
94 CPUARMState
*env
, int cpuid
,
97 struct aarch64_note note
;
100 aarch64_note_init(¬e
, s
, "CORE", 5, NT_PRFPREG
, sizeof(note
.vfp
));
102 for (i
= 0; i
< 64; ++i
) {
103 note
.vfp
.vregs
[i
] = cpu_to_dump64(s
, float64_val(env
->vfp
.regs
[i
]));
106 if (s
->dump_info
.d_endian
== ELFDATA2MSB
) {
107 /* For AArch64 we must always swap the vfp.regs's 2n and 2n+1
108 * entries when generating BE notes, because even big endian
109 * hosts use 2n+1 for the high half.
111 for (i
= 0; i
< 32; ++i
) {
112 uint64_t tmp
= note
.vfp
.vregs
[2*i
];
113 note
.vfp
.vregs
[2*i
] = note
.vfp
.vregs
[2*i
+1];
114 note
.vfp
.vregs
[2*i
+1] = tmp
;
118 note
.vfp
.fpsr
= cpu_to_dump32(s
, vfp_get_fpsr(env
));
119 note
.vfp
.fpcr
= cpu_to_dump32(s
, vfp_get_fpcr(env
));
121 ret
= f(¬e
, AARCH64_PRFPREG_NOTE_SIZE
, s
);
129 int arm_cpu_write_elf64_note(WriteCoreDumpFunction f
, CPUState
*cs
,
130 int cpuid
, void *opaque
)
132 struct aarch64_note note
;
133 CPUARMState
*env
= &ARM_CPU(cs
)->env
;
134 DumpState
*s
= opaque
;
138 aarch64_note_init(¬e
, s
, "CORE", 5, NT_PRSTATUS
, sizeof(note
.prstatus
));
140 note
.prstatus
.pr_pid
= cpu_to_dump32(s
, cpuid
);
141 note
.prstatus
.pr_fpvalid
= cpu_to_dump32(s
, 1);
144 aarch64_sync_32_to_64(env
);
145 pstate
= cpsr_read(env
);
148 pstate
= pstate_read(env
);
152 for (i
= 0; i
< 31; ++i
) {
153 note
.prstatus
.pr_reg
.regs
[i
] = cpu_to_dump64(s
, env
->xregs
[i
]);
155 note
.prstatus
.pr_reg
.sp
= cpu_to_dump64(s
, sp
);
156 note
.prstatus
.pr_reg
.pc
= cpu_to_dump64(s
, env
->pc
);
157 note
.prstatus
.pr_reg
.pstate
= cpu_to_dump64(s
, pstate
);
159 ret
= f(¬e
, AARCH64_PRSTATUS_NOTE_SIZE
, s
);
164 return aarch64_write_elf64_prfpreg(f
, env
, cpuid
, s
);
167 /* struct pt_regs from arch/arm/include/asm/ptrace.h */
168 struct arm_user_regs
{
173 QEMU_BUILD_BUG_ON(sizeof(struct arm_user_regs
) != 72);
175 /* struct elf_prstatus from include/uapi/linux/elfcore.h */
176 struct arm_elf_prstatus
{
177 char pad1
[24]; /* 24 == offsetof(struct elf_prstatus, pr_pid) */
179 char pad2
[44]; /* 44 == offsetof(struct elf_prstatus, pr_reg) -
180 offsetof(struct elf_prstatus, pr_ppid) */
181 struct arm_user_regs pr_reg
;
183 } QEMU_PACKED arm_elf_prstatus
;
185 QEMU_BUILD_BUG_ON(sizeof(struct arm_elf_prstatus
) != 148);
187 /* struct user_vfp from arch/arm/include/asm/user.h */
188 struct arm_user_vfp_state
{
193 QEMU_BUILD_BUG_ON(sizeof(struct arm_user_vfp_state
) != 260);
197 char name
[8]; /* align_up(sizeof("LINUX"), 4) */
199 struct arm_elf_prstatus prstatus
;
200 struct arm_user_vfp_state vfp
;
204 #define ARM_NOTE_HEADER_SIZE offsetof(struct arm_note, prstatus)
205 #define ARM_PRSTATUS_NOTE_SIZE \
206 (ARM_NOTE_HEADER_SIZE + sizeof(struct arm_elf_prstatus))
207 #define ARM_VFP_NOTE_SIZE \
208 (ARM_NOTE_HEADER_SIZE + sizeof(struct arm_user_vfp_state))
210 static void arm_note_init(struct arm_note
*note
, DumpState
*s
,
211 const char *name
, Elf32_Word namesz
,
212 Elf32_Word type
, Elf32_Word descsz
)
214 memset(note
, 0, sizeof(*note
));
216 note
->hdr
.n_namesz
= cpu_to_dump32(s
, namesz
);
217 note
->hdr
.n_descsz
= cpu_to_dump32(s
, descsz
);
218 note
->hdr
.n_type
= cpu_to_dump32(s
, type
);
220 memcpy(note
->name
, name
, namesz
);
223 static int arm_write_elf32_vfp(WriteCoreDumpFunction f
, CPUARMState
*env
,
224 int cpuid
, DumpState
*s
)
226 struct arm_note note
;
229 arm_note_init(¬e
, s
, "LINUX", 6, NT_ARM_VFP
, sizeof(note
.vfp
));
231 for (i
= 0; i
< 32; ++i
) {
232 note
.vfp
.vregs
[i
] = cpu_to_dump64(s
, float64_val(env
->vfp
.regs
[i
]));
235 note
.vfp
.fpscr
= cpu_to_dump32(s
, vfp_get_fpscr(env
));
237 ret
= f(¬e
, ARM_VFP_NOTE_SIZE
, s
);
245 int arm_cpu_write_elf32_note(WriteCoreDumpFunction f
, CPUState
*cs
,
246 int cpuid
, void *opaque
)
248 struct arm_note note
;
249 CPUARMState
*env
= &ARM_CPU(cs
)->env
;
250 DumpState
*s
= opaque
;
251 int ret
, i
, fpvalid
= !!arm_feature(env
, ARM_FEATURE_VFP
);
253 arm_note_init(¬e
, s
, "CORE", 5, NT_PRSTATUS
, sizeof(note
.prstatus
));
255 note
.prstatus
.pr_pid
= cpu_to_dump32(s
, cpuid
);
256 note
.prstatus
.pr_fpvalid
= cpu_to_dump32(s
, fpvalid
);
258 for (i
= 0; i
< 16; ++i
) {
259 note
.prstatus
.pr_reg
.regs
[i
] = cpu_to_dump32(s
, env
->regs
[i
]);
261 note
.prstatus
.pr_reg
.regs
[16] = cpu_to_dump32(s
, cpsr_read(env
));
263 ret
= f(¬e
, ARM_PRSTATUS_NOTE_SIZE
, s
);
266 } else if (fpvalid
) {
267 return arm_write_elf32_vfp(f
, env
, cpuid
, s
);
273 int cpu_get_dump_info(ArchDumpInfo
*info
,
274 const GuestPhysBlockList
*guest_phys_blocks
)
278 GuestPhysBlock
*block
;
279 hwaddr lowest_addr
= ULLONG_MAX
;
281 if (first_cpu
== NULL
) {
285 cpu
= ARM_CPU(first_cpu
);
288 /* Take a best guess at the phys_base. If we get it wrong then crash
289 * will need '--machdep phys_offset=<phys-offset>' added to its command
290 * line, which isn't any worse than assuming we can use zero, but being
291 * wrong. This is the same algorithm the crash utility uses when
292 * attempting to guess as it loads non-dumpfile formatted files.
294 QTAILQ_FOREACH(block
, &guest_phys_blocks
->head
, next
) {
295 if (block
->target_start
< lowest_addr
) {
296 lowest_addr
= block
->target_start
;
300 if (arm_feature(env
, ARM_FEATURE_AARCH64
)) {
301 info
->d_machine
= EM_AARCH64
;
302 info
->d_class
= ELFCLASS64
;
303 info
->page_size
= (1 << 16); /* aarch64 max pagesize */
304 if (lowest_addr
!= ULLONG_MAX
) {
305 info
->phys_base
= lowest_addr
;
308 info
->d_machine
= EM_ARM
;
309 info
->d_class
= ELFCLASS32
;
310 info
->page_size
= (1 << 12);
311 if (lowest_addr
< UINT_MAX
) {
312 info
->phys_base
= lowest_addr
;
316 /* We assume the relevant endianness is that of EL1; this is right
317 * for kernels, but might give the wrong answer if you're trying to
318 * dump a hypervisor that happens to be running an opposite-endian
321 info
->d_endian
= (env
->cp15
.sctlr_el
[1] & SCTLR_EE
) != 0
322 ? ELFDATA2MSB
: ELFDATA2LSB
;
327 ssize_t
cpu_get_note_size(int class, int machine
, int nr_cpus
)
329 ARMCPU
*cpu
= ARM_CPU(first_cpu
);
330 CPUARMState
*env
= &cpu
->env
;
333 if (class == ELFCLASS64
) {
334 note_size
= AARCH64_PRSTATUS_NOTE_SIZE
;
335 note_size
+= AARCH64_PRFPREG_NOTE_SIZE
;
337 note_size
= ARM_PRSTATUS_NOTE_SIZE
;
338 if (arm_feature(env
, ARM_FEATURE_VFP
)) {
339 note_size
+= ARM_VFP_NOTE_SIZE
;
343 return note_size
* nr_cpus
;