~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to target/arm/arch_dump.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Support for writing ELF notes for ARM architectures
 
2
 *
 
3
 * Copyright (C) 2015 Red Hat Inc.
 
4
 *
 
5
 * Author: Andrew Jones <drjones@redhat.com>
 
6
 *
 
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.
 
11
 *
 
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.
 
16
 *
 
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/>.
 
19
 */
 
20
 
 
21
#include "qemu/osdep.h"
 
22
#include "cpu.h"
 
23
#include "elf.h"
 
24
#include "sysemu/dump.h"
 
25
 
 
26
/* struct user_pt_regs from arch/arm64/include/uapi/asm/ptrace.h */
 
27
struct aarch64_user_regs {
 
28
    uint64_t regs[31];
 
29
    uint64_t sp;
 
30
    uint64_t pc;
 
31
    uint64_t pstate;
 
32
} QEMU_PACKED;
 
33
 
 
34
QEMU_BUILD_BUG_ON(sizeof(struct aarch64_user_regs) != 272);
 
35
 
 
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) */
 
39
    uint32_t 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;
 
43
    uint32_t pr_fpvalid;
 
44
    char pad3[4];
 
45
} QEMU_PACKED;
 
46
 
 
47
QEMU_BUILD_BUG_ON(sizeof(struct aarch64_elf_prstatus) != 392);
 
48
 
 
49
/* struct user_fpsimd_state from arch/arm64/include/uapi/asm/ptrace.h
 
50
 *
 
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.
 
55
 */
 
56
struct aarch64_user_vfp_state {
 
57
    uint64_t vregs[64];
 
58
    uint32_t fpsr;
 
59
    uint32_t fpcr;
 
60
    char pad[8];
 
61
} QEMU_PACKED;
 
62
 
 
63
QEMU_BUILD_BUG_ON(sizeof(struct aarch64_user_vfp_state) != 528);
 
64
 
 
65
struct aarch64_note {
 
66
    Elf64_Nhdr hdr;
 
67
    char name[8]; /* align_up(sizeof("CORE"), 4) */
 
68
    union {
 
69
        struct aarch64_elf_prstatus prstatus;
 
70
        struct aarch64_user_vfp_state vfp;
 
71
    };
 
72
} QEMU_PACKED;
 
73
 
 
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))
 
79
 
 
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)
 
83
{
 
84
    memset(note, 0, sizeof(*note));
 
85
 
 
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);
 
89
 
 
90
    memcpy(note->name, name, namesz);
 
91
}
 
92
 
 
93
static int aarch64_write_elf64_prfpreg(WriteCoreDumpFunction f,
 
94
                                       CPUARMState *env, int cpuid,
 
95
                                       DumpState *s)
 
96
{
 
97
    struct aarch64_note note;
 
98
    int ret, i;
 
99
 
 
100
    aarch64_note_init(&note, s, "CORE", 5, NT_PRFPREG, sizeof(note.vfp));
 
101
 
 
102
    for (i = 0; i < 64; ++i) {
 
103
        note.vfp.vregs[i] = cpu_to_dump64(s, float64_val(env->vfp.regs[i]));
 
104
    }
 
105
 
 
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.
 
110
         */
 
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;
 
115
        }
 
116
    }
 
117
 
 
118
    note.vfp.fpsr = cpu_to_dump32(s, vfp_get_fpsr(env));
 
119
    note.vfp.fpcr = cpu_to_dump32(s, vfp_get_fpcr(env));
 
120
 
 
121
    ret = f(&note, AARCH64_PRFPREG_NOTE_SIZE, s);
 
122
    if (ret < 0) {
 
123
        return -1;
 
124
    }
 
125
 
 
126
    return 0;
 
127
}
 
128
 
 
129
int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
 
130
                             int cpuid, void *opaque)
 
131
{
 
132
    struct aarch64_note note;
 
133
    CPUARMState *env = &ARM_CPU(cs)->env;
 
134
    DumpState *s = opaque;
 
135
    uint64_t pstate, sp;
 
136
    int ret, i;
 
137
 
 
138
    aarch64_note_init(&note, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus));
 
139
 
 
140
    note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
 
141
    note.prstatus.pr_fpvalid = cpu_to_dump32(s, 1);
 
142
 
 
143
    if (!is_a64(env)) {
 
144
        aarch64_sync_32_to_64(env);
 
145
        pstate = cpsr_read(env);
 
146
        sp = 0;
 
147
    } else {
 
148
        pstate = pstate_read(env);
 
149
        sp = env->xregs[31];
 
150
    }
 
151
 
 
152
    for (i = 0; i < 31; ++i) {
 
153
        note.prstatus.pr_reg.regs[i] = cpu_to_dump64(s, env->xregs[i]);
 
154
    }
 
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);
 
158
 
 
159
    ret = f(&note, AARCH64_PRSTATUS_NOTE_SIZE, s);
 
160
    if (ret < 0) {
 
161
        return -1;
 
162
    }
 
163
 
 
164
    return aarch64_write_elf64_prfpreg(f, env, cpuid, s);
 
165
}
 
166
 
 
167
/* struct pt_regs from arch/arm/include/asm/ptrace.h */
 
168
struct arm_user_regs {
 
169
    uint32_t regs[17];
 
170
    char pad[4];
 
171
} QEMU_PACKED;
 
172
 
 
173
QEMU_BUILD_BUG_ON(sizeof(struct arm_user_regs) != 72);
 
174
 
 
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) */
 
178
    uint32_t 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;
 
182
    uint32_t pr_fpvalid;
 
183
} QEMU_PACKED arm_elf_prstatus;
 
184
 
 
185
QEMU_BUILD_BUG_ON(sizeof(struct arm_elf_prstatus) != 148);
 
186
 
 
187
/* struct user_vfp from arch/arm/include/asm/user.h */
 
188
struct arm_user_vfp_state {
 
189
    uint64_t vregs[32];
 
190
    uint32_t fpscr;
 
191
} QEMU_PACKED;
 
192
 
 
193
QEMU_BUILD_BUG_ON(sizeof(struct arm_user_vfp_state) != 260);
 
194
 
 
195
struct arm_note {
 
196
    Elf32_Nhdr hdr;
 
197
    char name[8]; /* align_up(sizeof("LINUX"), 4) */
 
198
    union {
 
199
        struct arm_elf_prstatus prstatus;
 
200
        struct arm_user_vfp_state vfp;
 
201
    };
 
202
} QEMU_PACKED;
 
203
 
 
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))
 
209
 
 
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)
 
213
{
 
214
    memset(note, 0, sizeof(*note));
 
215
 
 
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);
 
219
 
 
220
    memcpy(note->name, name, namesz);
 
221
}
 
222
 
 
223
static int arm_write_elf32_vfp(WriteCoreDumpFunction f, CPUARMState *env,
 
224
                               int cpuid, DumpState *s)
 
225
{
 
226
    struct arm_note note;
 
227
    int ret, i;
 
228
 
 
229
    arm_note_init(&note, s, "LINUX", 6, NT_ARM_VFP, sizeof(note.vfp));
 
230
 
 
231
    for (i = 0; i < 32; ++i) {
 
232
        note.vfp.vregs[i] = cpu_to_dump64(s, float64_val(env->vfp.regs[i]));
 
233
    }
 
234
 
 
235
    note.vfp.fpscr = cpu_to_dump32(s, vfp_get_fpscr(env));
 
236
 
 
237
    ret = f(&note, ARM_VFP_NOTE_SIZE, s);
 
238
    if (ret < 0) {
 
239
        return -1;
 
240
    }
 
241
 
 
242
    return 0;
 
243
}
 
244
 
 
245
int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
 
246
                             int cpuid, void *opaque)
 
247
{
 
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);
 
252
 
 
253
    arm_note_init(&note, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus));
 
254
 
 
255
    note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
 
256
    note.prstatus.pr_fpvalid = cpu_to_dump32(s, fpvalid);
 
257
 
 
258
    for (i = 0; i < 16; ++i) {
 
259
        note.prstatus.pr_reg.regs[i] = cpu_to_dump32(s, env->regs[i]);
 
260
    }
 
261
    note.prstatus.pr_reg.regs[16] = cpu_to_dump32(s, cpsr_read(env));
 
262
 
 
263
    ret = f(&note, ARM_PRSTATUS_NOTE_SIZE, s);
 
264
    if (ret < 0) {
 
265
        return -1;
 
266
    } else if (fpvalid) {
 
267
        return arm_write_elf32_vfp(f, env, cpuid, s);
 
268
    }
 
269
 
 
270
    return 0;
 
271
}
 
272
 
 
273
int cpu_get_dump_info(ArchDumpInfo *info,
 
274
                      const GuestPhysBlockList *guest_phys_blocks)
 
275
{
 
276
    ARMCPU *cpu = ARM_CPU(first_cpu);
 
277
    CPUARMState *env = &cpu->env;
 
278
    GuestPhysBlock *block;
 
279
    hwaddr lowest_addr = ULLONG_MAX;
 
280
 
 
281
    /* Take a best guess at the phys_base. If we get it wrong then crash
 
282
     * will need '--machdep phys_offset=<phys-offset>' added to its command
 
283
     * line, which isn't any worse than assuming we can use zero, but being
 
284
     * wrong. This is the same algorithm the crash utility uses when
 
285
     * attempting to guess as it loads non-dumpfile formatted files.
 
286
     */
 
287
    QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) {
 
288
        if (block->target_start < lowest_addr) {
 
289
            lowest_addr = block->target_start;
 
290
        }
 
291
    }
 
292
 
 
293
    if (arm_feature(env, ARM_FEATURE_AARCH64)) {
 
294
        info->d_machine = EM_AARCH64;
 
295
        info->d_class = ELFCLASS64;
 
296
        info->page_size = (1 << 16); /* aarch64 max pagesize */
 
297
        if (lowest_addr != ULLONG_MAX) {
 
298
            info->phys_base = lowest_addr;
 
299
        }
 
300
    } else {
 
301
        info->d_machine = EM_ARM;
 
302
        info->d_class = ELFCLASS32;
 
303
        info->page_size = (1 << 12);
 
304
        if (lowest_addr < UINT_MAX) {
 
305
            info->phys_base = lowest_addr;
 
306
        }
 
307
    }
 
308
 
 
309
    /* We assume the relevant endianness is that of EL1; this is right
 
310
     * for kernels, but might give the wrong answer if you're trying to
 
311
     * dump a hypervisor that happens to be running an opposite-endian
 
312
     * kernel.
 
313
     */
 
314
    info->d_endian = (env->cp15.sctlr_el[1] & SCTLR_EE) != 0
 
315
                     ? ELFDATA2MSB : ELFDATA2LSB;
 
316
 
 
317
    return 0;
 
318
}
 
319
 
 
320
ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
 
321
{
 
322
    ARMCPU *cpu = ARM_CPU(first_cpu);
 
323
    CPUARMState *env = &cpu->env;
 
324
    size_t note_size;
 
325
 
 
326
    if (class == ELFCLASS64) {
 
327
        note_size = AARCH64_PRSTATUS_NOTE_SIZE;
 
328
        note_size += AARCH64_PRFPREG_NOTE_SIZE;
 
329
    } else {
 
330
        note_size = ARM_PRSTATUS_NOTE_SIZE;
 
331
        if (arm_feature(env, ARM_FEATURE_VFP)) {
 
332
            note_size += ARM_VFP_NOTE_SIZE;
 
333
        }
 
334
    }
 
335
 
 
336
    return note_size * nr_cpus;
 
337
}