mirror of https://github.com/xemu-project/xemu.git
target-arm queue:
* contrib/elf2dmp: Improve robustness to corrupt input files * docs: update copyright date to the year 2024 * hw/arm: Deprecate various old Arm machine types -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmXvV4gZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3oe5EACvvve9LOJ7UA4teEbn8zzs O7GGsycpu3XWINX98sUi5Cuu+uexkcXsHf2Vg8GABj2fUuA+EEqPIdIWZhVcfB2t RYGPgat/JVTwRUsl38OQ97l4joI2JeW18B20Pmh4/2tbZCJuIHoiHxxb+3aQl6Nl gz/H137ayy+Q5utt1b6z1qXnw4etiUhk4wg2ltGVtAw63w5GZOvamTicSQ1DC3ZP zfbIKW2WpGNjzrC1tCvaW/dNojt2blpZbsnpdPsL8cNE8puo01FnFLsUZCzOtu3m 23uoQq0KjQZBJrU2oZMtshc+sKT/FGPADJ9B+J8jjU0EY6cV+Qo7FT4E78mxzoR0 JbY9SLATtY7RE1Fbh3/Am+3OEyb3ZDor5nCux0CWOsuFoBk96dzD7r5MXxM2eft1 pGmdJStYysZkdlSyx61bu6OifHOaGjnOe+lYWpaCrVy1U3cO3hbMWH2siSQygppM 8EfjyfadzfST+nAnXfduSgWMv7Nc4ql4GIOxVnMIfGig32PIp545IvM9neh6GIp/ 8fzw6TdoCQkHcWaazV1ibPF0ceH6JwRvLIMkWlNpr/QBSNdsx+zkdh7WZD+3S91U XrCAA7hgf7OIvHauSD0ucSbztIiFRMROcHxIoh0ui6BermtaD6fnlei4QcsJI17o 6XZSNSWm5/+JEsn+dcVh4g== =UHyi -----END PGP SIGNATURE----- Merge tag 'pull-target-arm-20240311' of https://git.linaro.org/people/pmaydell/qemu-arm into staging target-arm queue: * contrib/elf2dmp: Improve robustness to corrupt input files * docs: update copyright date to the year 2024 * hw/arm: Deprecate various old Arm machine types # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmXvV4gZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3oe5EACvvve9LOJ7UA4teEbn8zzs # O7GGsycpu3XWINX98sUi5Cuu+uexkcXsHf2Vg8GABj2fUuA+EEqPIdIWZhVcfB2t # RYGPgat/JVTwRUsl38OQ97l4joI2JeW18B20Pmh4/2tbZCJuIHoiHxxb+3aQl6Nl # gz/H137ayy+Q5utt1b6z1qXnw4etiUhk4wg2ltGVtAw63w5GZOvamTicSQ1DC3ZP # zfbIKW2WpGNjzrC1tCvaW/dNojt2blpZbsnpdPsL8cNE8puo01FnFLsUZCzOtu3m # 23uoQq0KjQZBJrU2oZMtshc+sKT/FGPADJ9B+J8jjU0EY6cV+Qo7FT4E78mxzoR0 # JbY9SLATtY7RE1Fbh3/Am+3OEyb3ZDor5nCux0CWOsuFoBk96dzD7r5MXxM2eft1 # pGmdJStYysZkdlSyx61bu6OifHOaGjnOe+lYWpaCrVy1U3cO3hbMWH2siSQygppM # 8EfjyfadzfST+nAnXfduSgWMv7Nc4ql4GIOxVnMIfGig32PIp545IvM9neh6GIp/ # 8fzw6TdoCQkHcWaazV1ibPF0ceH6JwRvLIMkWlNpr/QBSNdsx+zkdh7WZD+3S91U # XrCAA7hgf7OIvHauSD0ucSbztIiFRMROcHxIoh0ui6BermtaD6fnlei4QcsJI17o # 6XZSNSWm5/+JEsn+dcVh4g== # =UHyi # -----END PGP SIGNATURE----- # gpg: Signature made Mon 11 Mar 2024 19:12:08 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # gpg: aka "Peter Maydell <peter@archaic.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * tag 'pull-target-arm-20240311' of https://git.linaro.org/people/pmaydell/qemu-arm: docs: update copyright date to the year 2024 contrib/elf2dmp: Ensure phdrs fit in file contrib/elf2dmp: Clamp QEMU note to file size contrib/elf2dmp: Use GPtrArray MAINTAINERS: Add Akihiko Odaki as a elf2dmp reviewer contrib/elf2dmp: Use rol64() to decode contrib/elf2dmp: Use lduw_le_p() to read PDB contrib/elf2dmp: Ensure segment fits in file contrib/elf2dmp: Always destroy PA space contrib/elf2dmp: Always check for PA resolution failure contrib/elf2dmp: Fix error reporting style in main.c contrib/elf2dmp: Fix error reporting style in qemu_elf.c contrib/elf2dmp: Fix error reporting style in pdb.c contrib/elf2dmp: Fix error reporting style in download.c contrib/elf2dmp: Fix error reporting style in addrspace.c contrib/elf2dmp: Change pa_space_create() signature contrib/elf2dmp: Continue even contexts are lacking contrib/elf2dmp: Assume error by default contrib/elf2dmp: Remove unnecessary err flags hw/arm: Deprecate various old Arm machine types Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
1c268991b3
|
@ -3587,6 +3587,7 @@ F: util/iova-tree.c
|
|||
|
||||
elf2dmp
|
||||
M: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
|
||||
R: Akihiko Odaki <akihiko.odaki@daynix.com>
|
||||
S: Maintained
|
||||
F: contrib/elf2dmp/
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ static struct pa_block *pa_space_find_block(struct pa_space *ps, uint64_t pa)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static uint8_t *pa_space_resolve(struct pa_space *ps, uint64_t pa)
|
||||
static void *pa_space_resolve(struct pa_space *ps, uint64_t pa)
|
||||
{
|
||||
struct pa_block *block = pa_space_find_block(ps, pa);
|
||||
|
||||
|
@ -33,6 +33,19 @@ static uint8_t *pa_space_resolve(struct pa_space *ps, uint64_t pa)
|
|||
return block->addr + (pa - block->paddr);
|
||||
}
|
||||
|
||||
static bool pa_space_read64(struct pa_space *ps, uint64_t pa, uint64_t *value)
|
||||
{
|
||||
uint64_t *resolved = pa_space_resolve(ps, pa);
|
||||
|
||||
if (!resolved) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*value = *resolved;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void pa_block_align(struct pa_block *b)
|
||||
{
|
||||
uint64_t low_align = ((b->paddr - 1) | ELF2DMP_PAGE_MASK) + 1 - b->paddr;
|
||||
|
@ -57,7 +70,7 @@ static void pa_block_align(struct pa_block *b)
|
|||
b->paddr += low_align;
|
||||
}
|
||||
|
||||
int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
|
||||
void pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
|
||||
{
|
||||
Elf64_Half phdr_nr = elf_getphdrnum(qemu_elf->map);
|
||||
Elf64_Phdr *phdr = elf64_getphdr(qemu_elf->map);
|
||||
|
@ -75,11 +88,12 @@ int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
|
|||
ps->block = g_new(struct pa_block, ps->block_nr);
|
||||
|
||||
for (i = 0; i < phdr_nr; i++) {
|
||||
if (phdr[i].p_type == PT_LOAD) {
|
||||
if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset < qemu_elf->size) {
|
||||
ps->block[block_i] = (struct pa_block) {
|
||||
.addr = (uint8_t *)qemu_elf->map + phdr[i].p_offset,
|
||||
.paddr = phdr[i].p_paddr,
|
||||
.size = phdr[i].p_filesz,
|
||||
.size = MIN(phdr[i].p_filesz,
|
||||
qemu_elf->size - phdr[i].p_offset),
|
||||
};
|
||||
pa_block_align(&ps->block[block_i]);
|
||||
block_i = ps->block[block_i].size ? (block_i + 1) : block_i;
|
||||
|
@ -87,8 +101,6 @@ int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
|
|||
}
|
||||
|
||||
ps->block_nr = block_i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pa_space_destroy(struct pa_space *ps)
|
||||
|
@ -108,19 +120,20 @@ void va_space_create(struct va_space *vs, struct pa_space *ps, uint64_t dtb)
|
|||
va_space_set_dtb(vs, dtb);
|
||||
}
|
||||
|
||||
static uint64_t get_pml4e(struct va_space *vs, uint64_t va)
|
||||
static bool get_pml4e(struct va_space *vs, uint64_t va, uint64_t *value)
|
||||
{
|
||||
uint64_t pa = (vs->dtb & 0xffffffffff000) | ((va & 0xff8000000000) >> 36);
|
||||
|
||||
return *(uint64_t *)pa_space_resolve(vs->ps, pa);
|
||||
return pa_space_read64(vs->ps, pa, value);
|
||||
}
|
||||
|
||||
static uint64_t get_pdpi(struct va_space *vs, uint64_t va, uint64_t pml4e)
|
||||
static bool get_pdpi(struct va_space *vs, uint64_t va, uint64_t pml4e,
|
||||
uint64_t *value)
|
||||
{
|
||||
uint64_t pdpte_paddr = (pml4e & 0xffffffffff000) |
|
||||
((va & 0x7FC0000000) >> 27);
|
||||
|
||||
return *(uint64_t *)pa_space_resolve(vs->ps, pdpte_paddr);
|
||||
return pa_space_read64(vs->ps, pdpte_paddr, value);
|
||||
}
|
||||
|
||||
static uint64_t pde_index(uint64_t va)
|
||||
|
@ -133,11 +146,12 @@ static uint64_t pdba_base(uint64_t pdpe)
|
|||
return pdpe & 0xFFFFFFFFFF000;
|
||||
}
|
||||
|
||||
static uint64_t get_pgd(struct va_space *vs, uint64_t va, uint64_t pdpe)
|
||||
static bool get_pgd(struct va_space *vs, uint64_t va, uint64_t pdpe,
|
||||
uint64_t *value)
|
||||
{
|
||||
uint64_t pgd_entry = pdba_base(pdpe) + pde_index(va) * 8;
|
||||
|
||||
return *(uint64_t *)pa_space_resolve(vs->ps, pgd_entry);
|
||||
return pa_space_read64(vs->ps, pgd_entry, value);
|
||||
}
|
||||
|
||||
static uint64_t pte_index(uint64_t va)
|
||||
|
@ -150,11 +164,12 @@ static uint64_t ptba_base(uint64_t pde)
|
|||
return pde & 0xFFFFFFFFFF000;
|
||||
}
|
||||
|
||||
static uint64_t get_pte(struct va_space *vs, uint64_t va, uint64_t pgd)
|
||||
static bool get_pte(struct va_space *vs, uint64_t va, uint64_t pgd,
|
||||
uint64_t *value)
|
||||
{
|
||||
uint64_t pgd_val = ptba_base(pgd) + pte_index(va) * 8;
|
||||
|
||||
return *(uint64_t *)pa_space_resolve(vs->ps, pgd_val);
|
||||
return pa_space_read64(vs->ps, pgd_val, value);
|
||||
}
|
||||
|
||||
static uint64_t get_paddr(uint64_t va, uint64_t pte)
|
||||
|
@ -186,13 +201,11 @@ static uint64_t va_space_va2pa(struct va_space *vs, uint64_t va)
|
|||
{
|
||||
uint64_t pml4e, pdpe, pgd, pte;
|
||||
|
||||
pml4e = get_pml4e(vs, va);
|
||||
if (!is_present(pml4e)) {
|
||||
if (!get_pml4e(vs, va, &pml4e) || !is_present(pml4e)) {
|
||||
return INVALID_PA;
|
||||
}
|
||||
|
||||
pdpe = get_pdpi(vs, va, pml4e);
|
||||
if (!is_present(pdpe)) {
|
||||
if (!get_pdpi(vs, va, pml4e, &pdpe) || !is_present(pdpe)) {
|
||||
return INVALID_PA;
|
||||
}
|
||||
|
||||
|
@ -200,8 +213,7 @@ static uint64_t va_space_va2pa(struct va_space *vs, uint64_t va)
|
|||
return get_1GB_paddr(va, pdpe);
|
||||
}
|
||||
|
||||
pgd = get_pgd(vs, va, pdpe);
|
||||
if (!is_present(pgd)) {
|
||||
if (!get_pgd(vs, va, pdpe, &pgd) || !is_present(pgd)) {
|
||||
return INVALID_PA;
|
||||
}
|
||||
|
||||
|
@ -209,8 +221,7 @@ static uint64_t va_space_va2pa(struct va_space *vs, uint64_t va)
|
|||
return get_2MB_paddr(va, pgd);
|
||||
}
|
||||
|
||||
pte = get_pte(vs, va, pgd);
|
||||
if (!is_present(pte)) {
|
||||
if (!get_pte(vs, va, pgd, &pte) || !is_present(pte)) {
|
||||
return INVALID_PA;
|
||||
}
|
||||
|
||||
|
@ -228,7 +239,7 @@ void *va_space_resolve(struct va_space *vs, uint64_t va)
|
|||
return pa_space_resolve(vs->ps, pa);
|
||||
}
|
||||
|
||||
int va_space_rw(struct va_space *vs, uint64_t addr,
|
||||
bool va_space_rw(struct va_space *vs, uint64_t addr,
|
||||
void *buf, size_t size, int is_write)
|
||||
{
|
||||
while (size) {
|
||||
|
@ -240,7 +251,7 @@ int va_space_rw(struct va_space *vs, uint64_t addr,
|
|||
|
||||
ptr = va_space_resolve(vs, addr);
|
||||
if (!ptr) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_write) {
|
||||
|
@ -254,5 +265,5 @@ int va_space_rw(struct va_space *vs, uint64_t addr,
|
|||
addr += s;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -33,13 +33,13 @@ struct va_space {
|
|||
struct pa_space *ps;
|
||||
};
|
||||
|
||||
int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf);
|
||||
void pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf);
|
||||
void pa_space_destroy(struct pa_space *ps);
|
||||
|
||||
void va_space_create(struct va_space *vs, struct pa_space *ps, uint64_t dtb);
|
||||
void va_space_set_dtb(struct va_space *vs, uint64_t dtb);
|
||||
void *va_space_resolve(struct va_space *vs, uint64_t va);
|
||||
int va_space_rw(struct va_space *vs, uint64_t addr,
|
||||
bool va_space_rw(struct va_space *vs, uint64_t addr,
|
||||
void *buf, size_t size, int is_write);
|
||||
|
||||
#endif /* ADDRSPACE_H */
|
||||
|
|
|
@ -9,19 +9,18 @@
|
|||
#include <curl/curl.h>
|
||||
#include "download.h"
|
||||
|
||||
int download_url(const char *name, const char *url)
|
||||
bool download_url(const char *name, const char *url)
|
||||
{
|
||||
int err = 0;
|
||||
bool success = false;
|
||||
FILE *file;
|
||||
CURL *curl = curl_easy_init();
|
||||
|
||||
if (!curl) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
file = fopen(name, "wb");
|
||||
if (!file) {
|
||||
err = 1;
|
||||
goto out_curl;
|
||||
}
|
||||
|
||||
|
@ -33,13 +32,12 @@ int download_url(const char *name, const char *url)
|
|||
|| curl_easy_perform(curl) != CURLE_OK) {
|
||||
unlink(name);
|
||||
fclose(file);
|
||||
err = 1;
|
||||
} else {
|
||||
err = fclose(file);
|
||||
success = !fclose(file);
|
||||
}
|
||||
|
||||
out_curl:
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
return err;
|
||||
return success;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
#ifndef DOWNLOAD_H
|
||||
#define DOWNLOAD_H
|
||||
|
||||
int download_url(const char *name, const char *url);
|
||||
bool download_url(const char *name, const char *url);
|
||||
|
||||
#endif /* DOWNLOAD_H */
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
|
||||
#include "err.h"
|
||||
#include "addrspace.h"
|
||||
|
@ -47,11 +48,6 @@ static const uint64_t SharedUserData = 0xfffff78000000000;
|
|||
s ? printf(#s" = 0x%016"PRIx64"\n", s) :\
|
||||
eprintf("Failed to resolve "#s"\n"), s)
|
||||
|
||||
static uint64_t rol(uint64_t x, uint64_t y)
|
||||
{
|
||||
return (x << y) | (x >> (64 - y));
|
||||
}
|
||||
|
||||
/*
|
||||
* Decoding algorithm can be found in Volatility project
|
||||
*/
|
||||
|
@ -64,7 +60,7 @@ static void kdbg_decode(uint64_t *dst, uint64_t *src, size_t size,
|
|||
uint64_t block;
|
||||
|
||||
block = src[i];
|
||||
block = rol(block ^ kwn, (uint8_t)kwn);
|
||||
block = rol64(block ^ kwn, kwn);
|
||||
block = __builtin_bswap64(block ^ kdbe) ^ kwa;
|
||||
dst[i] = block;
|
||||
}
|
||||
|
@ -79,7 +75,7 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb,
|
|||
bool decode = false;
|
||||
uint64_t kwn, kwa, KdpDataBlockEncoded;
|
||||
|
||||
if (va_space_rw(vs,
|
||||
if (!va_space_rw(vs,
|
||||
KdDebuggerDataBlock + offsetof(KDDEBUGGER_DATA64, Header),
|
||||
&kdbg_hdr, sizeof(kdbg_hdr), 0)) {
|
||||
eprintf("Failed to extract KDBG header\n");
|
||||
|
@ -97,8 +93,8 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (va_space_rw(vs, KiWaitNever, &kwn, sizeof(kwn), 0) ||
|
||||
va_space_rw(vs, KiWaitAlways, &kwa, sizeof(kwa), 0)) {
|
||||
if (!va_space_rw(vs, KiWaitNever, &kwn, sizeof(kwn), 0) ||
|
||||
!va_space_rw(vs, KiWaitAlways, &kwa, sizeof(kwa), 0)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -122,7 +118,7 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb,
|
|||
|
||||
kdbg = g_malloc(kdbg_hdr.Size);
|
||||
|
||||
if (va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 0)) {
|
||||
if (!va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 0)) {
|
||||
eprintf("Failed to extract entire KDBG\n");
|
||||
g_free(kdbg);
|
||||
return NULL;
|
||||
|
@ -186,13 +182,13 @@ static void win_context_init_from_qemu_cpu_state(WinContext64 *ctx,
|
|||
* Finds paging-structure hierarchy base,
|
||||
* if previously set doesn't give access to kernel structures
|
||||
*/
|
||||
static int fix_dtb(struct va_space *vs, QEMU_Elf *qe)
|
||||
static bool fix_dtb(struct va_space *vs, QEMU_Elf *qe)
|
||||
{
|
||||
/*
|
||||
* Firstly, test previously set DTB.
|
||||
*/
|
||||
if (va_space_resolve(vs, SharedUserData)) {
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -206,7 +202,7 @@ static int fix_dtb(struct va_space *vs, QEMU_Elf *qe)
|
|||
va_space_set_dtb(vs, s->cr[3]);
|
||||
printf("DTB 0x%016"PRIx64" has been found from CPU #%zu"
|
||||
" as system task CR3\n", vs->dtb, i);
|
||||
return !(va_space_resolve(vs, SharedUserData));
|
||||
return va_space_resolve(vs, SharedUserData);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,16 +216,16 @@ static int fix_dtb(struct va_space *vs, QEMU_Elf *qe)
|
|||
uint64_t *cr3 = va_space_resolve(vs, Prcb + 0x7000);
|
||||
|
||||
if (!cr3) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
va_space_set_dtb(vs, *cr3);
|
||||
printf("DirectoryTableBase = 0x%016"PRIx64" has been found from CPU #0"
|
||||
" as interrupt handling CR3\n", vs->dtb);
|
||||
return !(va_space_resolve(vs, SharedUserData));
|
||||
return va_space_resolve(vs, SharedUserData);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void try_merge_runs(struct pa_space *ps,
|
||||
|
@ -268,9 +264,10 @@ static void try_merge_runs(struct pa_space *ps,
|
|||
}
|
||||
}
|
||||
|
||||
static int fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
|
||||
static bool fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
|
||||
struct va_space *vs, uint64_t KdDebuggerDataBlock,
|
||||
KDDEBUGGER_DATA64 *kdbg, uint64_t KdVersionBlock, int nr_cpus)
|
||||
KDDEBUGGER_DATA64 *kdbg, uint64_t KdVersionBlock,
|
||||
int nr_cpus)
|
||||
{
|
||||
uint32_t *suite_mask = va_space_resolve(vs, SharedUserData +
|
||||
KUSD_OFFSET_SUITE_MASK);
|
||||
|
@ -283,12 +280,12 @@ static int fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
|
|||
QEMU_BUILD_BUG_ON(KUSD_OFFSET_PRODUCT_TYPE >= ELF2DMP_PAGE_SIZE);
|
||||
|
||||
if (!suite_mask || !product_type) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (va_space_rw(vs, KdVersionBlock, &kvb, sizeof(kvb), 0)) {
|
||||
if (!va_space_rw(vs, KdVersionBlock, &kvb, sizeof(kvb), 0)) {
|
||||
eprintf("Failed to extract KdVersionBlock\n");
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
h = (WinDumpHeader64) {
|
||||
|
@ -333,10 +330,15 @@ static int fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
|
|||
|
||||
*hdr = h;
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int fill_context(KDDEBUGGER_DATA64 *kdbg,
|
||||
/*
|
||||
* fill_context() continues even if it fails to fill contexts of some CPUs.
|
||||
* A dump may still contain valuable information even if it lacks contexts of
|
||||
* some CPUs due to dump corruption or a failure before starting CPUs.
|
||||
*/
|
||||
static void fill_context(KDDEBUGGER_DATA64 *kdbg,
|
||||
struct va_space *vs, QEMU_Elf *qe)
|
||||
{
|
||||
int i;
|
||||
|
@ -347,10 +349,10 @@ static int fill_context(KDDEBUGGER_DATA64 *kdbg,
|
|||
WinContext64 ctx;
|
||||
QEMUCPUState *s = qe->state[i];
|
||||
|
||||
if (va_space_rw(vs, kdbg->KiProcessorBlock + sizeof(Prcb) * i,
|
||||
if (!va_space_rw(vs, kdbg->KiProcessorBlock + sizeof(Prcb) * i,
|
||||
&Prcb, sizeof(Prcb), 0)) {
|
||||
eprintf("Failed to read CPU #%d PRCB location\n", i);
|
||||
return 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Prcb) {
|
||||
|
@ -358,25 +360,23 @@ static int fill_context(KDDEBUGGER_DATA64 *kdbg,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (va_space_rw(vs, Prcb + kdbg->OffsetPrcbContext,
|
||||
if (!va_space_rw(vs, Prcb + kdbg->OffsetPrcbContext,
|
||||
&Context, sizeof(Context), 0)) {
|
||||
eprintf("Failed to read CPU #%d ContextFrame location\n", i);
|
||||
return 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Filling context for CPU #%d...\n", i);
|
||||
win_context_init_from_qemu_cpu_state(&ctx, s);
|
||||
|
||||
if (va_space_rw(vs, Context, &ctx, sizeof(ctx), 1)) {
|
||||
if (!va_space_rw(vs, Context, &ctx, sizeof(ctx), 1)) {
|
||||
eprintf("Failed to fill CPU #%d context\n", i);
|
||||
return 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pe_get_data_dir_entry(uint64_t base, void *start_addr, int idx,
|
||||
static bool pe_get_data_dir_entry(uint64_t base, void *start_addr, int idx,
|
||||
void *entry, size_t size, struct va_space *vs)
|
||||
{
|
||||
const char e_magic[2] = "MZ";
|
||||
|
@ -390,32 +390,30 @@ static int pe_get_data_dir_entry(uint64_t base, void *start_addr, int idx,
|
|||
QEMU_BUILD_BUG_ON(sizeof(*dos_hdr) >= ELF2DMP_PAGE_SIZE);
|
||||
|
||||
if (memcmp(&dos_hdr->e_magic, e_magic, sizeof(e_magic))) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (va_space_rw(vs, base + dos_hdr->e_lfanew,
|
||||
if (!va_space_rw(vs, base + dos_hdr->e_lfanew,
|
||||
&nt_hdrs, sizeof(nt_hdrs), 0)) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(&nt_hdrs.Signature, Signature, sizeof(Signature)) ||
|
||||
file_hdr->Machine != 0x8664 || opt_hdr->Magic != 0x020b) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (va_space_rw(vs,
|
||||
base + data_dir[idx].VirtualAddress,
|
||||
entry, size, 0)) {
|
||||
return 1;
|
||||
if (!va_space_rw(vs, base + data_dir[idx].VirtualAddress, entry, size, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Data directory entry #%d: RVA = 0x%08"PRIx32"\n", idx,
|
||||
(uint32_t)data_dir[idx].VirtualAddress);
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int write_dump(struct pa_space *ps,
|
||||
static bool write_dump(struct pa_space *ps,
|
||||
WinDumpHeader64 *hdr, const char *name)
|
||||
{
|
||||
FILE *dmp_file = fopen(name, "wb");
|
||||
|
@ -423,7 +421,7 @@ static int write_dump(struct pa_space *ps,
|
|||
|
||||
if (!dmp_file) {
|
||||
eprintf("Failed to open output file \'%s\'\n", name);
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("Writing header to file...\n");
|
||||
|
@ -431,7 +429,7 @@ static int write_dump(struct pa_space *ps,
|
|||
if (fwrite(hdr, sizeof(*hdr), 1, dmp_file) != 1) {
|
||||
eprintf("Failed to write dump header\n");
|
||||
fclose(dmp_file);
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < ps->block_nr; i++) {
|
||||
|
@ -442,11 +440,11 @@ static int write_dump(struct pa_space *ps,
|
|||
if (fwrite(b->addr, b->size, 1, dmp_file) != 1) {
|
||||
eprintf("Failed to write block\n");
|
||||
fclose(dmp_file);
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return fclose(dmp_file);
|
||||
return !fclose(dmp_file);
|
||||
}
|
||||
|
||||
static bool pe_check_pdb_name(uint64_t base, void *start_addr,
|
||||
|
@ -456,7 +454,7 @@ static bool pe_check_pdb_name(uint64_t base, void *start_addr,
|
|||
IMAGE_DEBUG_DIRECTORY debug_dir;
|
||||
char pdb_name[sizeof(PDB_NAME)];
|
||||
|
||||
if (pe_get_data_dir_entry(base, start_addr, IMAGE_FILE_DEBUG_DIRECTORY,
|
||||
if (!pe_get_data_dir_entry(base, start_addr, IMAGE_FILE_DEBUG_DIRECTORY,
|
||||
&debug_dir, sizeof(debug_dir), vs)) {
|
||||
eprintf("Failed to get Debug Directory\n");
|
||||
return false;
|
||||
|
@ -467,8 +465,7 @@ static bool pe_check_pdb_name(uint64_t base, void *start_addr,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (va_space_rw(vs,
|
||||
base + debug_dir.AddressOfRawData,
|
||||
if (!va_space_rw(vs, base + debug_dir.AddressOfRawData,
|
||||
rsds, sizeof(*rsds), 0)) {
|
||||
eprintf("Failed to resolve OMFSignatureRSDS\n");
|
||||
return false;
|
||||
|
@ -485,9 +482,9 @@ static bool pe_check_pdb_name(uint64_t base, void *start_addr,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (va_space_rw(vs, base + debug_dir.AddressOfRawData +
|
||||
offsetof(OMFSignatureRSDS, name), pdb_name, sizeof(PDB_NAME),
|
||||
0)) {
|
||||
if (!va_space_rw(vs, base + debug_dir.AddressOfRawData +
|
||||
offsetof(OMFSignatureRSDS, name),
|
||||
pdb_name, sizeof(PDB_NAME), 0)) {
|
||||
eprintf("Failed to resolve PDB name\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -511,7 +508,7 @@ static void pe_get_pdb_symstore_hash(OMFSignatureRSDS *rsds, char *hash)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int err = 0;
|
||||
int err = 1;
|
||||
QEMU_Elf qemu_elf;
|
||||
struct pa_space ps;
|
||||
struct va_space vs;
|
||||
|
@ -535,33 +532,27 @@ int main(int argc, char *argv[])
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (QEMU_Elf_init(&qemu_elf, argv[1])) {
|
||||
if (!QEMU_Elf_init(&qemu_elf, argv[1])) {
|
||||
eprintf("Failed to initialize QEMU ELF dump\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pa_space_create(&ps, &qemu_elf)) {
|
||||
eprintf("Failed to initialize physical address space\n");
|
||||
err = 1;
|
||||
goto out_elf;
|
||||
}
|
||||
pa_space_create(&ps, &qemu_elf);
|
||||
|
||||
state = qemu_elf.state[0];
|
||||
printf("CPU #0 CR3 is 0x%016"PRIx64"\n", state->cr[3]);
|
||||
|
||||
va_space_create(&vs, &ps, state->cr[3]);
|
||||
if (fix_dtb(&vs, &qemu_elf)) {
|
||||
if (!fix_dtb(&vs, &qemu_elf)) {
|
||||
eprintf("Failed to find paging base\n");
|
||||
err = 1;
|
||||
goto out_elf;
|
||||
goto out_ps;
|
||||
}
|
||||
|
||||
printf("CPU #0 IDT is at 0x%016"PRIx64"\n", state->idt.base);
|
||||
|
||||
if (va_space_rw(&vs, state->idt.base,
|
||||
if (!va_space_rw(&vs, state->idt.base,
|
||||
&first_idt_desc, sizeof(first_idt_desc), 0)) {
|
||||
eprintf("Failed to get CPU #0 IDT[0]\n");
|
||||
err = 1;
|
||||
goto out_ps;
|
||||
}
|
||||
printf("CPU #0 IDT[0] -> 0x%016"PRIx64"\n", idt_desc_addr(first_idt_desc));
|
||||
|
@ -586,7 +577,6 @@ int main(int argc, char *argv[])
|
|||
|
||||
if (!kernel_found) {
|
||||
eprintf("Failed to find NT kernel image\n");
|
||||
err = 1;
|
||||
goto out_ps;
|
||||
}
|
||||
|
||||
|
@ -598,47 +588,40 @@ int main(int argc, char *argv[])
|
|||
sprintf(pdb_url, "%s%s/%s/%s", SYM_URL_BASE, PDB_NAME, pdb_hash, PDB_NAME);
|
||||
printf("PDB URL is %s\n", pdb_url);
|
||||
|
||||
if (download_url(PDB_NAME, pdb_url)) {
|
||||
if (!download_url(PDB_NAME, pdb_url)) {
|
||||
eprintf("Failed to download PDB file\n");
|
||||
err = 1;
|
||||
goto out_ps;
|
||||
}
|
||||
|
||||
if (pdb_init_from_file(PDB_NAME, &pdb)) {
|
||||
if (!pdb_init_from_file(PDB_NAME, &pdb)) {
|
||||
eprintf("Failed to initialize PDB reader\n");
|
||||
err = 1;
|
||||
goto out_pdb_file;
|
||||
}
|
||||
|
||||
if (!SYM_RESOLVE(KernBase, &pdb, KdDebuggerDataBlock) ||
|
||||
!SYM_RESOLVE(KernBase, &pdb, KdVersionBlock)) {
|
||||
err = 1;
|
||||
goto out_pdb;
|
||||
}
|
||||
|
||||
kdbg = get_kdbg(KernBase, &pdb, &vs, KdDebuggerDataBlock);
|
||||
if (!kdbg) {
|
||||
err = 1;
|
||||
goto out_pdb;
|
||||
}
|
||||
|
||||
if (fill_header(&header, &ps, &vs, KdDebuggerDataBlock, kdbg,
|
||||
if (!fill_header(&header, &ps, &vs, KdDebuggerDataBlock, kdbg,
|
||||
KdVersionBlock, qemu_elf.state_nr)) {
|
||||
err = 1;
|
||||
goto out_kdbg;
|
||||
}
|
||||
|
||||
if (fill_context(kdbg, &vs, &qemu_elf)) {
|
||||
err = 1;
|
||||
goto out_kdbg;
|
||||
}
|
||||
fill_context(kdbg, &vs, &qemu_elf);
|
||||
|
||||
if (write_dump(&ps, &header, argv[2])) {
|
||||
if (!write_dump(&ps, &header, argv[2])) {
|
||||
eprintf("Failed to save dump\n");
|
||||
err = 1;
|
||||
goto out_kdbg;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
out_kdbg:
|
||||
g_free(kdbg);
|
||||
out_pdb:
|
||||
|
@ -647,7 +630,6 @@ out_pdb_file:
|
|||
unlink(PDB_NAME);
|
||||
out_ps:
|
||||
pa_space_destroy(&ps);
|
||||
out_elf:
|
||||
QEMU_Elf_exit(&qemu_elf);
|
||||
|
||||
return err;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bswap.h"
|
||||
|
||||
#include "pdb.h"
|
||||
#include "err.h"
|
||||
|
@ -158,36 +159,35 @@ static void *pdb_ds_read_file(struct pdb_reader* r, uint32_t file_number)
|
|||
return pdb_ds_read(r->ds.header, block_list, file_size[file_number]);
|
||||
}
|
||||
|
||||
static int pdb_init_segments(struct pdb_reader *r)
|
||||
static bool pdb_init_segments(struct pdb_reader *r)
|
||||
{
|
||||
unsigned stream_idx = r->segments;
|
||||
|
||||
r->segs = pdb_ds_read_file(r, stream_idx);
|
||||
if (!r->segs) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
r->segs_size = pdb_get_file_size(r, stream_idx);
|
||||
if (!r->segs_size) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int pdb_init_symbols(struct pdb_reader *r)
|
||||
static bool pdb_init_symbols(struct pdb_reader *r)
|
||||
{
|
||||
int err = 0;
|
||||
PDB_SYMBOLS *symbols;
|
||||
|
||||
symbols = pdb_ds_read_file(r, 3);
|
||||
if (!symbols) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
r->symbols = symbols;
|
||||
|
||||
r->segments = *(uint16_t *)((const char *)symbols + sizeof(PDB_SYMBOLS) +
|
||||
r->segments = lduw_le_p((const char *)symbols + sizeof(PDB_SYMBOLS) +
|
||||
symbols->module_size + symbols->offset_size +
|
||||
symbols->hash_size + symbols->srcmodule_size +
|
||||
symbols->pdbimport_size + symbols->unknown2_size +
|
||||
|
@ -196,22 +196,21 @@ static int pdb_init_symbols(struct pdb_reader *r)
|
|||
/* Read global symbol table */
|
||||
r->modimage = pdb_ds_read_file(r, symbols->gsym_file);
|
||||
if (!r->modimage) {
|
||||
err = 1;
|
||||
goto out_symbols;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
|
||||
out_symbols:
|
||||
g_free(symbols);
|
||||
|
||||
return err;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
|
||||
static bool pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
|
||||
{
|
||||
if (hdr->block_size == 0) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(r->file_used, 0, sizeof(r->file_used));
|
||||
|
@ -220,42 +219,38 @@ static int pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
|
|||
hdr->toc_page * hdr->block_size), hdr->toc_size);
|
||||
|
||||
if (!r->ds.toc) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int pdb_reader_init(struct pdb_reader *r, void *data)
|
||||
static bool pdb_reader_init(struct pdb_reader *r, void *data)
|
||||
{
|
||||
int err = 0;
|
||||
const char pdb7[] = "Microsoft C/C++ MSF 7.00";
|
||||
|
||||
if (memcmp(data, pdb7, sizeof(pdb7) - 1)) {
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pdb_reader_ds_init(r, data)) {
|
||||
return 1;
|
||||
if (!pdb_reader_ds_init(r, data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
r->ds.root = pdb_ds_read_file(r, 1);
|
||||
if (!r->ds.root) {
|
||||
err = 1;
|
||||
goto out_ds;
|
||||
}
|
||||
|
||||
if (pdb_init_symbols(r)) {
|
||||
err = 1;
|
||||
if (!pdb_init_symbols(r)) {
|
||||
goto out_root;
|
||||
}
|
||||
|
||||
if (pdb_init_segments(r)) {
|
||||
err = 1;
|
||||
if (!pdb_init_segments(r)) {
|
||||
goto out_sym;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
|
||||
out_sym:
|
||||
pdb_exit_symbols(r);
|
||||
|
@ -264,7 +259,7 @@ out_root:
|
|||
out_ds:
|
||||
pdb_reader_ds_exit(r);
|
||||
|
||||
return err;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void pdb_reader_exit(struct pdb_reader *r)
|
||||
|
@ -275,32 +270,30 @@ static void pdb_reader_exit(struct pdb_reader *r)
|
|||
pdb_reader_ds_exit(r);
|
||||
}
|
||||
|
||||
int pdb_init_from_file(const char *name, struct pdb_reader *reader)
|
||||
bool pdb_init_from_file(const char *name, struct pdb_reader *reader)
|
||||
{
|
||||
GError *gerr = NULL;
|
||||
int err = 0;
|
||||
void *map;
|
||||
|
||||
reader->gmf = g_mapped_file_new(name, TRUE, &gerr);
|
||||
if (gerr) {
|
||||
eprintf("Failed to map PDB file \'%s\'\n", name);
|
||||
g_error_free(gerr);
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
reader->file_size = g_mapped_file_get_length(reader->gmf);
|
||||
map = g_mapped_file_get_contents(reader->gmf);
|
||||
if (pdb_reader_init(reader, map)) {
|
||||
err = 1;
|
||||
if (!pdb_reader_init(reader, map)) {
|
||||
goto out_unmap;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
|
||||
out_unmap:
|
||||
g_mapped_file_unref(reader->gmf);
|
||||
|
||||
return err;
|
||||
return false;
|
||||
}
|
||||
|
||||
void pdb_exit(struct pdb_reader *reader)
|
||||
|
|
|
@ -233,7 +233,7 @@ struct pdb_reader {
|
|||
size_t segs_size;
|
||||
};
|
||||
|
||||
int pdb_init_from_file(const char *name, struct pdb_reader *reader);
|
||||
bool pdb_init_from_file(const char *name, struct pdb_reader *reader);
|
||||
void pdb_exit(struct pdb_reader *reader);
|
||||
uint64_t pdb_resolve(uint64_t img_base, struct pdb_reader *r, const char *name);
|
||||
uint64_t pdb_find_public_v3_symbol(struct pdb_reader *reader, const char *name);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "err.h"
|
||||
#include "qemu_elf.h"
|
||||
|
||||
|
@ -15,36 +16,11 @@
|
|||
#define ROUND_UP(n, d) (((n) + (d) - 1) & -(0 ? (n) : (d)))
|
||||
#endif
|
||||
|
||||
#ifndef DIV_ROUND_UP
|
||||
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
|
||||
#endif
|
||||
|
||||
#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \
|
||||
((DIV_ROUND_UP((hdr_size), 4) + \
|
||||
DIV_ROUND_UP((name_size), 4) + \
|
||||
DIV_ROUND_UP((desc_size), 4)) * 4)
|
||||
|
||||
int is_system(QEMUCPUState *s)
|
||||
{
|
||||
return s->gs.base >> 63;
|
||||
}
|
||||
|
||||
static char *nhdr_get_name(Elf64_Nhdr *nhdr)
|
||||
{
|
||||
return (char *)nhdr + ROUND_UP(sizeof(*nhdr), 4);
|
||||
}
|
||||
|
||||
static void *nhdr_get_desc(Elf64_Nhdr *nhdr)
|
||||
{
|
||||
return nhdr_get_name(nhdr) + ROUND_UP(nhdr->n_namesz, 4);
|
||||
}
|
||||
|
||||
static Elf64_Nhdr *nhdr_get_next(Elf64_Nhdr *nhdr)
|
||||
{
|
||||
return (void *)((uint8_t *)nhdr + ELF_NOTE_SIZE(sizeof(*nhdr),
|
||||
nhdr->n_namesz, nhdr->n_descsz));
|
||||
}
|
||||
|
||||
Elf64_Phdr *elf64_getphdr(void *map)
|
||||
{
|
||||
Elf64_Ehdr *ehdr = map;
|
||||
|
@ -60,54 +36,92 @@ Elf64_Half elf_getphdrnum(void *map)
|
|||
return ehdr->e_phnum;
|
||||
}
|
||||
|
||||
static int init_states(QEMU_Elf *qe)
|
||||
static bool advance_note_offset(uint64_t *offsetp, uint64_t size, uint64_t end)
|
||||
{
|
||||
uint64_t offset = *offsetp;
|
||||
|
||||
if (uadd64_overflow(offset, size, &offset) || offset > UINT64_MAX - 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
offset = ROUND_UP(offset, 4);
|
||||
|
||||
if (offset > end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*offsetp = offset;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool init_states(QEMU_Elf *qe)
|
||||
{
|
||||
Elf64_Phdr *phdr = elf64_getphdr(qe->map);
|
||||
Elf64_Nhdr *start = (void *)((uint8_t *)qe->map + phdr[0].p_offset);
|
||||
Elf64_Nhdr *end = (void *)((uint8_t *)start + phdr[0].p_memsz);
|
||||
Elf64_Nhdr *nhdr;
|
||||
size_t cpu_nr = 0;
|
||||
GPtrArray *states;
|
||||
QEMUCPUState *state;
|
||||
uint32_t state_size;
|
||||
uint64_t offset;
|
||||
uint64_t end_offset;
|
||||
char *name;
|
||||
|
||||
if (phdr[0].p_type != PT_NOTE) {
|
||||
eprintf("Failed to find PT_NOTE\n");
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
qe->has_kernel_gs_base = 1;
|
||||
offset = phdr[0].p_offset;
|
||||
states = g_ptr_array_new();
|
||||
|
||||
for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
|
||||
if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
|
||||
QEMUCPUState *state = nhdr_get_desc(nhdr);
|
||||
if (uadd64_overflow(offset, phdr[0].p_memsz, &end_offset) ||
|
||||
end_offset > qe->size) {
|
||||
end_offset = qe->size;
|
||||
}
|
||||
|
||||
if (state->size < sizeof(*state)) {
|
||||
eprintf("CPU #%zu: QEMU CPU state size %u doesn't match\n",
|
||||
cpu_nr, state->size);
|
||||
while (offset < end_offset) {
|
||||
nhdr = (void *)((uint8_t *)qe->map + offset);
|
||||
|
||||
if (!advance_note_offset(&offset, sizeof(*nhdr), end_offset)) {
|
||||
break;
|
||||
}
|
||||
|
||||
name = (char *)qe->map + offset;
|
||||
|
||||
if (!advance_note_offset(&offset, nhdr->n_namesz, end_offset)) {
|
||||
break;
|
||||
}
|
||||
|
||||
state = (void *)((uint8_t *)qe->map + offset);
|
||||
|
||||
if (!advance_note_offset(&offset, nhdr->n_descsz, end_offset)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!strcmp(name, QEMU_NOTE_NAME) &&
|
||||
nhdr->n_descsz >= offsetof(QEMUCPUState, kernel_gs_base)) {
|
||||
state_size = MIN(state->size, nhdr->n_descsz);
|
||||
|
||||
if (state_size < sizeof(*state)) {
|
||||
eprintf("CPU #%u: QEMU CPU state size %u doesn't match\n",
|
||||
states->len, state_size);
|
||||
/*
|
||||
* We assume either every QEMU CPU state has KERNEL_GS_BASE or
|
||||
* no one has.
|
||||
*/
|
||||
qe->has_kernel_gs_base = 0;
|
||||
}
|
||||
cpu_nr++;
|
||||
g_ptr_array_add(states, state);
|
||||
}
|
||||
}
|
||||
|
||||
printf("%zu CPU states has been found\n", cpu_nr);
|
||||
printf("%u CPU states has been found\n", states->len);
|
||||
|
||||
qe->state = g_new(QEMUCPUState*, cpu_nr);
|
||||
qe->state_nr = states->len;
|
||||
qe->state = (void *)g_ptr_array_free(states, FALSE);
|
||||
|
||||
cpu_nr = 0;
|
||||
|
||||
for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
|
||||
if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
|
||||
qe->state[cpu_nr] = nhdr_get_desc(nhdr);
|
||||
cpu_nr++;
|
||||
}
|
||||
}
|
||||
|
||||
qe->state_nr = cpu_nr;
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void exit_states(QEMU_Elf *qe)
|
||||
|
@ -118,6 +132,7 @@ static void exit_states(QEMU_Elf *qe)
|
|||
static bool check_ehdr(QEMU_Elf *qe)
|
||||
{
|
||||
Elf64_Ehdr *ehdr = qe->map;
|
||||
uint64_t phendoff;
|
||||
|
||||
if (sizeof(Elf64_Ehdr) > qe->size) {
|
||||
eprintf("Invalid input dump file size\n");
|
||||
|
@ -159,10 +174,17 @@ static bool check_ehdr(QEMU_Elf *qe)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (umul64_overflow(ehdr->e_phnum, sizeof(Elf64_Phdr), &phendoff) ||
|
||||
uadd64_overflow(phendoff, ehdr->e_phoff, &phendoff) ||
|
||||
phendoff > qe->size) {
|
||||
eprintf("phdrs do not fit in file\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
|
||||
static bool QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
|
||||
{
|
||||
#ifdef CONFIG_LINUX
|
||||
struct stat st;
|
||||
|
@ -173,13 +195,13 @@ static int QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
|
|||
fd = open(filename, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
eprintf("Failed to open ELF dump file \'%s\'\n", filename);
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fstat(fd, &st)) {
|
||||
eprintf("Failed to get size of ELF dump file\n");
|
||||
close(fd);
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
qe->size = st.st_size;
|
||||
|
||||
|
@ -188,7 +210,7 @@ static int QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
|
|||
if (qe->map == MAP_FAILED) {
|
||||
eprintf("Failed to map ELF file\n");
|
||||
close(fd);
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
@ -201,14 +223,14 @@ static int QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
|
|||
if (gerr) {
|
||||
eprintf("Failed to map ELF dump file \'%s\'\n", filename);
|
||||
g_error_free(gerr);
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
qe->map = g_mapped_file_get_contents(qe->gmf);
|
||||
qe->size = g_mapped_file_get_length(qe->gmf);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void QEMU_Elf_unmap(QEMU_Elf *qe)
|
||||
|
@ -220,25 +242,25 @@ static void QEMU_Elf_unmap(QEMU_Elf *qe)
|
|||
#endif
|
||||
}
|
||||
|
||||
int QEMU_Elf_init(QEMU_Elf *qe, const char *filename)
|
||||
bool QEMU_Elf_init(QEMU_Elf *qe, const char *filename)
|
||||
{
|
||||
if (QEMU_Elf_map(qe, filename)) {
|
||||
return 1;
|
||||
if (!QEMU_Elf_map(qe, filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_ehdr(qe)) {
|
||||
eprintf("Input file has the wrong format\n");
|
||||
QEMU_Elf_unmap(qe);
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (init_states(qe)) {
|
||||
if (!init_states(qe)) {
|
||||
eprintf("Failed to extract QEMU CPU states\n");
|
||||
QEMU_Elf_unmap(qe);
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void QEMU_Elf_exit(QEMU_Elf *qe)
|
||||
|
|
|
@ -42,7 +42,7 @@ typedef struct QEMU_Elf {
|
|||
int has_kernel_gs_base;
|
||||
} QEMU_Elf;
|
||||
|
||||
int QEMU_Elf_init(QEMU_Elf *qe, const char *filename);
|
||||
bool QEMU_Elf_init(QEMU_Elf *qe, const char *filename);
|
||||
void QEMU_Elf_exit(QEMU_Elf *qe);
|
||||
|
||||
Elf64_Phdr *elf64_getphdr(void *map);
|
||||
|
|
|
@ -245,6 +245,21 @@ to correct issues, mostly regarding migration compatibility. These are
|
|||
no longer maintained and removing them will make the code easier to
|
||||
read and maintain. Use versions 2.12 and above as a replacement.
|
||||
|
||||
Arm machines ``akita``, ``borzoi``, ``cheetah``, ``connex``, ``mainstone``, ``n800``, ``n810``, ``spitz``, ``terrier``, ``tosa``, ``verdex``, ``z2`` (since 9.0)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
QEMU includes models of some machine types where the QEMU code that
|
||||
emulates their SoCs is very old and unmaintained. This code is now
|
||||
blocking our ability to move forward with various changes across
|
||||
the codebase, and over many years nobody has been interested in
|
||||
trying to modernise it. We don't expect any of these machines to have
|
||||
a large number of users, because they're all modelling hardware that
|
||||
has now passed away into history. We are therefore dropping support
|
||||
for all machine types using the PXA2xx and OMAP2 SoCs. We are also
|
||||
dropping the ``cheetah`` OMAP1 board, because we don't have any
|
||||
test images for it and don't know of anybody who does; the ``sx1``
|
||||
and ``sx1-v1`` OMAP1 machines remain supported for now.
|
||||
|
||||
Backend options
|
||||
---------------
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ default_role = 'any'
|
|||
|
||||
# General information about the project.
|
||||
project = u'QEMU'
|
||||
copyright = u'2023, The QEMU Project Developers'
|
||||
copyright = u'2024, The QEMU Project Developers'
|
||||
author = u'The QEMU Project Developers'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
|
|
|
@ -106,6 +106,7 @@ static void connex_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "Gumstix Connex (PXA255)";
|
||||
mc->init = connex_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
}
|
||||
|
||||
static const TypeInfo connex_type = {
|
||||
|
@ -121,6 +122,7 @@ static void verdex_class_init(ObjectClass *oc, void *data)
|
|||
mc->desc = "Gumstix Verdex Pro XL6P COMs (PXA270)";
|
||||
mc->init = verdex_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
|
||||
}
|
||||
|
||||
|
|
|
@ -169,6 +169,7 @@ static void mainstone2_machine_init(MachineClass *mc)
|
|||
mc->init = mainstone_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5");
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("mainstone", mainstone2_machine_init)
|
||||
|
|
|
@ -1430,6 +1430,7 @@ static void n800_class_init(ObjectClass *oc, void *data)
|
|||
/* Actually two chips of 0x4000000 bytes each */
|
||||
mc->default_ram_size = 0x08000000;
|
||||
mc->default_ram_id = "omap2.dram";
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
|
||||
machine_add_audiodev_property(mc);
|
||||
}
|
||||
|
@ -1452,6 +1453,7 @@ static void n810_class_init(ObjectClass *oc, void *data)
|
|||
/* Actually two chips of 0x4000000 bytes each */
|
||||
mc->default_ram_size = 0x08000000;
|
||||
mc->default_ram_id = "omap2.dram";
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
|
||||
machine_add_audiodev_property(mc);
|
||||
}
|
||||
|
|
|
@ -309,6 +309,7 @@ static void palmte_machine_init(MachineClass *mc)
|
|||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("ti925t");
|
||||
mc->default_ram_size = 0x02000000;
|
||||
mc->default_ram_id = "omap1.dram";
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
|
||||
machine_add_audiodev_property(mc);
|
||||
}
|
||||
|
|
|
@ -1041,6 +1041,7 @@ static void spitz_common_class_init(ObjectClass *oc, void *data)
|
|||
mc->block_default_type = IF_IDE;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
mc->init = spitz_common_init;
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
|
||||
machine_add_audiodev_property(mc);
|
||||
}
|
||||
|
|
|
@ -270,6 +270,7 @@ static void tosapda_machine_init(MachineClass *mc)
|
|||
mc->init = tosa_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("tosa", tosapda_machine_init)
|
||||
|
|
|
@ -347,6 +347,7 @@ static void z2_machine_init(MachineClass *mc)
|
|||
mc->init = z2_init;
|
||||
mc->ignore_memory_transaction_failures = true;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5");
|
||||
mc->deprecation_reason = "machine is old and unmaintained";
|
||||
|
||||
machine_add_audiodev_property(mc);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define QEMU_HELP_TEXTS_H
|
||||
|
||||
/* Copyright string for -version arguments, About dialogs, etc */
|
||||
#define QEMU_COPYRIGHT "Copyright (c) 2003-2023 " \
|
||||
#define QEMU_COPYRIGHT "Copyright (c) 2003-2024 " \
|
||||
"Fabrice Bellard and the QEMU Project developers"
|
||||
|
||||
/* Bug reporting information for --help arguments, About dialogs, etc */
|
||||
|
|
Loading…
Reference in New Issue