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:
Peter Maydell 2024-03-12 11:35:35 +00:00
commit 1c268991b3
20 changed files with 263 additions and 232 deletions

View File

@ -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/

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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
---------------

View File

@ -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

View File

@ -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");
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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 */