12da91b54SViktor Prutyanov /* 2*ac978771SPhilippe Mathieu-Daudé * Windows crashdump (target specific implementations) 32da91b54SViktor Prutyanov * 42da91b54SViktor Prutyanov * Copyright (c) 2018 Virtuozzo International GmbH 52da91b54SViktor Prutyanov * 62da91b54SViktor Prutyanov * This work is licensed under the terms of the GNU GPL, version 2 or later. 72da91b54SViktor Prutyanov * See the COPYING file in the top-level directory. 82da91b54SViktor Prutyanov * 92da91b54SViktor Prutyanov */ 102da91b54SViktor Prutyanov 112da91b54SViktor Prutyanov #include "qemu/osdep.h" 122da91b54SViktor Prutyanov #include "sysemu/dump.h" 132da91b54SViktor Prutyanov #include "qapi/error.h" 142da91b54SViktor Prutyanov #include "qapi/qmp/qerror.h" 15*ac978771SPhilippe Mathieu-Daudé #include "exec/cpu-defs.h" 16*ac978771SPhilippe Mathieu-Daudé #include "hw/core/cpu.h" 17*ac978771SPhilippe Mathieu-Daudé #include "qemu/win_dump_defs.h" 182da91b54SViktor Prutyanov #include "win_dump.h" 19*ac978771SPhilippe Mathieu-Daudé #include "cpu.h" 202da91b54SViktor Prutyanov 21f5daa829SViktor Prutyanov static size_t win_dump_ptr_size(bool x64) 22f5daa829SViktor Prutyanov { 23f5daa829SViktor Prutyanov return x64 ? sizeof(uint64_t) : sizeof(uint32_t); 24f5daa829SViktor Prutyanov } 25fb21efe9SViktor Prutyanov 26f5daa829SViktor Prutyanov #define _WIN_DUMP_FIELD(f) (x64 ? h->x64.f : h->x32.f) 27fb21efe9SViktor Prutyanov #define WIN_DUMP_FIELD(field) _WIN_DUMP_FIELD(field) 28fb21efe9SViktor Prutyanov 29f5daa829SViktor Prutyanov #define _WIN_DUMP_FIELD_PTR(f) (x64 ? (void *)&h->x64.f : (void *)&h->x32.f) 30fb21efe9SViktor Prutyanov #define WIN_DUMP_FIELD_PTR(field) _WIN_DUMP_FIELD_PTR(field) 31fb21efe9SViktor Prutyanov 32f5daa829SViktor Prutyanov #define _WIN_DUMP_FIELD_SIZE(f) (x64 ? sizeof(h->x64.f) : sizeof(h->x32.f)) 33fb21efe9SViktor Prutyanov #define WIN_DUMP_FIELD_SIZE(field) _WIN_DUMP_FIELD_SIZE(field) 34fb21efe9SViktor Prutyanov 35f5daa829SViktor Prutyanov static size_t win_dump_ctx_size(bool x64) 36f5daa829SViktor Prutyanov { 37f5daa829SViktor Prutyanov return x64 ? sizeof(WinContext64) : sizeof(WinContext32); 38f5daa829SViktor Prutyanov } 39fb21efe9SViktor Prutyanov 40fb21efe9SViktor Prutyanov static size_t write_run(uint64_t base_page, uint64_t page_count, 41fb21efe9SViktor Prutyanov int fd, Error **errp) 422da91b54SViktor Prutyanov { 432da91b54SViktor Prutyanov void *buf; 44fb21efe9SViktor Prutyanov uint64_t addr = base_page << TARGET_PAGE_BITS; 45fb21efe9SViktor Prutyanov uint64_t size = page_count << TARGET_PAGE_BITS; 467184de64SViktor Prutyanov uint64_t len, l; 477184de64SViktor Prutyanov size_t total = 0; 487184de64SViktor Prutyanov 497184de64SViktor Prutyanov while (size) { 507184de64SViktor Prutyanov len = size; 512da91b54SViktor Prutyanov 522da91b54SViktor Prutyanov buf = cpu_physical_memory_map(addr, &len, false); 532da91b54SViktor Prutyanov if (!buf) { 547184de64SViktor Prutyanov error_setg(errp, "win-dump: failed to map physical range" 557184de64SViktor Prutyanov " 0x%016" PRIx64 "-0x%016" PRIx64, addr, addr + size - 1); 562da91b54SViktor Prutyanov return 0; 572da91b54SViktor Prutyanov } 582da91b54SViktor Prutyanov 597184de64SViktor Prutyanov l = qemu_write_full(fd, buf, len); 602da91b54SViktor Prutyanov cpu_physical_memory_unmap(buf, addr, false, len); 617184de64SViktor Prutyanov if (l != len) { 627184de64SViktor Prutyanov error_setg(errp, QERR_IO_ERROR); 637184de64SViktor Prutyanov return 0; 647184de64SViktor Prutyanov } 652da91b54SViktor Prutyanov 667184de64SViktor Prutyanov addr += l; 677184de64SViktor Prutyanov size -= l; 687184de64SViktor Prutyanov total += l; 697184de64SViktor Prutyanov } 707184de64SViktor Prutyanov 717184de64SViktor Prutyanov return total; 722da91b54SViktor Prutyanov } 732da91b54SViktor Prutyanov 74f5daa829SViktor Prutyanov static void write_runs(DumpState *s, WinDumpHeader *h, bool x64, Error **errp) 752da91b54SViktor Prutyanov { 76fb21efe9SViktor Prutyanov uint64_t BasePage, PageCount; 772da91b54SViktor Prutyanov Error *local_err = NULL; 782da91b54SViktor Prutyanov int i; 792da91b54SViktor Prutyanov 80fb21efe9SViktor Prutyanov for (i = 0; i < WIN_DUMP_FIELD(PhysicalMemoryBlock.NumberOfRuns); i++) { 81fb21efe9SViktor Prutyanov BasePage = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].BasePage); 82fb21efe9SViktor Prutyanov PageCount = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].PageCount); 83fb21efe9SViktor Prutyanov s->written_size += write_run(BasePage, PageCount, s->fd, &local_err); 842da91b54SViktor Prutyanov if (local_err) { 852da91b54SViktor Prutyanov error_propagate(errp, local_err); 862da91b54SViktor Prutyanov return; 872da91b54SViktor Prutyanov } 882da91b54SViktor Prutyanov } 892da91b54SViktor Prutyanov } 902da91b54SViktor Prutyanov 91f5daa829SViktor Prutyanov static int cpu_read_ptr(bool x64, CPUState *cpu, uint64_t addr, uint64_t *ptr) 92fb21efe9SViktor Prutyanov { 93fb21efe9SViktor Prutyanov int ret; 94f5daa829SViktor Prutyanov uint32_t ptr32; 95fb21efe9SViktor Prutyanov uint64_t ptr64; 96fb21efe9SViktor Prutyanov 97f5daa829SViktor Prutyanov ret = cpu_memory_rw_debug(cpu, addr, x64 ? (void *)&ptr64 : (void *)&ptr32, 98f5daa829SViktor Prutyanov win_dump_ptr_size(x64), 0); 99fb21efe9SViktor Prutyanov 100f5daa829SViktor Prutyanov *ptr = x64 ? ptr64 : ptr32; 101fb21efe9SViktor Prutyanov 102fb21efe9SViktor Prutyanov return ret; 103fb21efe9SViktor Prutyanov } 104fb21efe9SViktor Prutyanov 105f5daa829SViktor Prutyanov static void patch_mm_pfn_database(WinDumpHeader *h, bool x64, Error **errp) 1062da91b54SViktor Prutyanov { 1072da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 108f5daa829SViktor Prutyanov WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET, 109fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_PTR(PfnDatabase), 110fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_SIZE(PfnDatabase), 0)) { 1112da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read MmPfnDatabase"); 1122da91b54SViktor Prutyanov return; 1132da91b54SViktor Prutyanov } 1142da91b54SViktor Prutyanov } 1152da91b54SViktor Prutyanov 116f5daa829SViktor Prutyanov static void patch_bugcheck_data(WinDumpHeader *h, bool x64, Error **errp) 1172da91b54SViktor Prutyanov { 1182da91b54SViktor Prutyanov uint64_t KiBugcheckData; 1192da91b54SViktor Prutyanov 120f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 121f5daa829SViktor Prutyanov WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_KI_BUGCHECK_DATA_OFFSET, 122fb21efe9SViktor Prutyanov &KiBugcheckData)) { 1232da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read KiBugcheckData"); 1242da91b54SViktor Prutyanov return; 1252da91b54SViktor Prutyanov } 1262da91b54SViktor Prutyanov 127fb21efe9SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, KiBugcheckData, 128fb21efe9SViktor Prutyanov WIN_DUMP_FIELD(BugcheckData), 129fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_SIZE(BugcheckData), 0)) { 1302da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read bugcheck data"); 1312da91b54SViktor Prutyanov return; 1322da91b54SViktor Prutyanov } 1332ad9b50fSViktor Prutyanov 1342ad9b50fSViktor Prutyanov /* 1352ad9b50fSViktor Prutyanov * If BugcheckCode wasn't saved, we consider guest OS as alive. 1362ad9b50fSViktor Prutyanov */ 1372ad9b50fSViktor Prutyanov 138fb21efe9SViktor Prutyanov if (!WIN_DUMP_FIELD(BugcheckCode)) { 139fb21efe9SViktor Prutyanov *(uint32_t *)WIN_DUMP_FIELD_PTR(BugcheckCode) = LIVE_SYSTEM_DUMP; 1402ad9b50fSViktor Prutyanov } 1412da91b54SViktor Prutyanov } 1422da91b54SViktor Prutyanov 1432da91b54SViktor Prutyanov /* 1442da91b54SViktor Prutyanov * This routine tries to correct mistakes in crashdump header. 1452da91b54SViktor Prutyanov */ 146f5daa829SViktor Prutyanov static void patch_header(WinDumpHeader *h, bool x64) 1472da91b54SViktor Prutyanov { 1482da91b54SViktor Prutyanov Error *local_err = NULL; 1492da91b54SViktor Prutyanov 150f5daa829SViktor Prutyanov if (x64) { 151f5daa829SViktor Prutyanov h->x64.RequiredDumpSpace = sizeof(WinDumpHeader64) + 152f5daa829SViktor Prutyanov (h->x64.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); 153f5daa829SViktor Prutyanov h->x64.PhysicalMemoryBlock.unused = 0; 154f5daa829SViktor Prutyanov h->x64.unused1 = 0; 155f5daa829SViktor Prutyanov } else { 156f5daa829SViktor Prutyanov h->x32.RequiredDumpSpace = sizeof(WinDumpHeader32) + 157f5daa829SViktor Prutyanov (h->x32.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); 158f5daa829SViktor Prutyanov } 1592da91b54SViktor Prutyanov 160f5daa829SViktor Prutyanov patch_mm_pfn_database(h, x64, &local_err); 1612da91b54SViktor Prutyanov if (local_err) { 1622da91b54SViktor Prutyanov warn_report_err(local_err); 1632da91b54SViktor Prutyanov local_err = NULL; 1642da91b54SViktor Prutyanov } 165f5daa829SViktor Prutyanov patch_bugcheck_data(h, x64, &local_err); 1662da91b54SViktor Prutyanov if (local_err) { 1672da91b54SViktor Prutyanov warn_report_err(local_err); 1682da91b54SViktor Prutyanov } 1692da91b54SViktor Prutyanov } 1702da91b54SViktor Prutyanov 171f5daa829SViktor Prutyanov static bool check_header(WinDumpHeader *h, bool *x64, Error **errp) 1722da91b54SViktor Prutyanov { 1732da91b54SViktor Prutyanov const char Signature[] = "PAGE"; 1742da91b54SViktor Prutyanov 1752da91b54SViktor Prutyanov if (memcmp(h->Signature, Signature, sizeof(h->Signature))) { 1762da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid header, expected '%.4s'," 1772da91b54SViktor Prutyanov " got '%.4s'", Signature, h->Signature); 178f5daa829SViktor Prutyanov return false; 1792da91b54SViktor Prutyanov } 1802da91b54SViktor Prutyanov 181f5daa829SViktor Prutyanov if (!memcmp(h->ValidDump, "DUMP", sizeof(h->ValidDump))) { 182f5daa829SViktor Prutyanov *x64 = false; 183f5daa829SViktor Prutyanov } else if (!memcmp(h->ValidDump, "DU64", sizeof(h->ValidDump))) { 184f5daa829SViktor Prutyanov *x64 = true; 185f5daa829SViktor Prutyanov } else { 186f5daa829SViktor Prutyanov error_setg(errp, "win-dump: invalid header, expected 'DUMP' or 'DU64'," 187f5daa829SViktor Prutyanov " got '%.4s'", h->ValidDump); 188f5daa829SViktor Prutyanov return false; 1892da91b54SViktor Prutyanov } 1902da91b54SViktor Prutyanov 191f5daa829SViktor Prutyanov return true; 192f5daa829SViktor Prutyanov } 193f5daa829SViktor Prutyanov 194f5daa829SViktor Prutyanov static void check_kdbg(WinDumpHeader *h, bool x64, Error **errp) 1952da91b54SViktor Prutyanov { 1962da91b54SViktor Prutyanov const char OwnerTag[] = "KDBG"; 1972da91b54SViktor Prutyanov char read_OwnerTag[4]; 198fb21efe9SViktor Prutyanov uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock); 1992ababfccSViktor Prutyanov bool try_fallback = true; 2002da91b54SViktor Prutyanov 2012ababfccSViktor Prutyanov try_again: 2022da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 203f5daa829SViktor Prutyanov KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET, 2042da91b54SViktor Prutyanov (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) { 2052da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read OwnerTag"); 2062da91b54SViktor Prutyanov return; 2072da91b54SViktor Prutyanov } 2082da91b54SViktor Prutyanov 2092da91b54SViktor Prutyanov if (memcmp(read_OwnerTag, OwnerTag, sizeof(read_OwnerTag))) { 2102ababfccSViktor Prutyanov if (try_fallback) { 2112ababfccSViktor Prutyanov /* 2122ababfccSViktor Prutyanov * If attempt to use original KDBG failed 2132ababfccSViktor Prutyanov * (most likely because of its encryption), 2142ababfccSViktor Prutyanov * we try to use KDBG obtained by guest driver. 2152ababfccSViktor Prutyanov */ 2162ababfccSViktor Prutyanov 217fb21efe9SViktor Prutyanov KdDebuggerDataBlock = WIN_DUMP_FIELD(BugcheckParameter1); 2182ababfccSViktor Prutyanov try_fallback = false; 2192ababfccSViktor Prutyanov goto try_again; 2202ababfccSViktor Prutyanov } else { 2212da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid KDBG OwnerTag," 2222ababfccSViktor Prutyanov " expected '%.4s', got '%.4s'", 2232da91b54SViktor Prutyanov OwnerTag, read_OwnerTag); 2242da91b54SViktor Prutyanov return; 2252da91b54SViktor Prutyanov } 2262da91b54SViktor Prutyanov } 2272da91b54SViktor Prutyanov 228f5daa829SViktor Prutyanov if (x64) { 229f5daa829SViktor Prutyanov h->x64.KdDebuggerDataBlock = KdDebuggerDataBlock; 230f5daa829SViktor Prutyanov } else { 231f5daa829SViktor Prutyanov h->x32.KdDebuggerDataBlock = KdDebuggerDataBlock; 232f5daa829SViktor Prutyanov } 2332ababfccSViktor Prutyanov } 2342ababfccSViktor Prutyanov 2352ad9b50fSViktor Prutyanov struct saved_context { 236f5daa829SViktor Prutyanov WinContext ctx; 2372ad9b50fSViktor Prutyanov uint64_t addr; 2382ad9b50fSViktor Prutyanov }; 2392ad9b50fSViktor Prutyanov 240f5daa829SViktor Prutyanov static void patch_and_save_context(WinDumpHeader *h, bool x64, 2412ad9b50fSViktor Prutyanov struct saved_context *saved_ctx, 2422ad9b50fSViktor Prutyanov Error **errp) 2432ad9b50fSViktor Prutyanov { 244fb21efe9SViktor Prutyanov uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock); 2452ad9b50fSViktor Prutyanov uint64_t KiProcessorBlock; 2462ad9b50fSViktor Prutyanov uint16_t OffsetPrcbContext; 2472ad9b50fSViktor Prutyanov CPUState *cpu; 2482ad9b50fSViktor Prutyanov int i = 0; 2492ad9b50fSViktor Prutyanov 250f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 251f5daa829SViktor Prutyanov KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET, 252fb21efe9SViktor Prutyanov &KiProcessorBlock)) { 2532ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read KiProcessorBlock"); 2542ad9b50fSViktor Prutyanov return; 2552ad9b50fSViktor Prutyanov } 2562ad9b50fSViktor Prutyanov 2572ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 258f5daa829SViktor Prutyanov KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET, 2592ad9b50fSViktor Prutyanov (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) { 2602ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read OffsetPrcbContext"); 2612ad9b50fSViktor Prutyanov return; 2622ad9b50fSViktor Prutyanov } 2632ad9b50fSViktor Prutyanov 2642ad9b50fSViktor Prutyanov CPU_FOREACH(cpu) { 2652ad9b50fSViktor Prutyanov X86CPU *x86_cpu = X86_CPU(cpu); 2662ad9b50fSViktor Prutyanov CPUX86State *env = &x86_cpu->env; 2672ad9b50fSViktor Prutyanov uint64_t Prcb; 2682ad9b50fSViktor Prutyanov uint64_t Context; 269f5daa829SViktor Prutyanov WinContext ctx; 2702ad9b50fSViktor Prutyanov 271e38c24cbSViktor Prutyanov if (i >= WIN_DUMP_FIELD(NumberProcessors)) { 272e38c24cbSViktor Prutyanov warn_report("win-dump: number of QEMU CPUs is bigger than" 273e38c24cbSViktor Prutyanov " NumberProcessors (%u) in guest Windows", 274e38c24cbSViktor Prutyanov WIN_DUMP_FIELD(NumberProcessors)); 275e38c24cbSViktor Prutyanov return; 276e38c24cbSViktor Prutyanov } 277e38c24cbSViktor Prutyanov 278f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 279f5daa829SViktor Prutyanov KiProcessorBlock + i * win_dump_ptr_size(x64), 280fb21efe9SViktor Prutyanov &Prcb)) { 2812ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read" 2822ad9b50fSViktor Prutyanov " CPU #%d PRCB location", i); 2832ad9b50fSViktor Prutyanov return; 2842ad9b50fSViktor Prutyanov } 2852ad9b50fSViktor Prutyanov 286f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 2872ad9b50fSViktor Prutyanov Prcb + OffsetPrcbContext, 288fb21efe9SViktor Prutyanov &Context)) { 2892ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read" 2902ad9b50fSViktor Prutyanov " CPU #%d ContextFrame location", i); 2912ad9b50fSViktor Prutyanov return; 2922ad9b50fSViktor Prutyanov } 2932ad9b50fSViktor Prutyanov 2942ad9b50fSViktor Prutyanov saved_ctx[i].addr = Context; 2952ad9b50fSViktor Prutyanov 296f5daa829SViktor Prutyanov if (x64) { 297f5daa829SViktor Prutyanov ctx.x64 = (WinContext64){ 298a64b4e17SViktor Prutyanov .ContextFlags = WIN_CTX64_ALL, 2992ad9b50fSViktor Prutyanov .MxCsr = env->mxcsr, 3002ad9b50fSViktor Prutyanov 3012ad9b50fSViktor Prutyanov .SegEs = env->segs[0].selector, 3022ad9b50fSViktor Prutyanov .SegCs = env->segs[1].selector, 3032ad9b50fSViktor Prutyanov .SegSs = env->segs[2].selector, 3042ad9b50fSViktor Prutyanov .SegDs = env->segs[3].selector, 3052ad9b50fSViktor Prutyanov .SegFs = env->segs[4].selector, 3062ad9b50fSViktor Prutyanov .SegGs = env->segs[5].selector, 3072ad9b50fSViktor Prutyanov .EFlags = cpu_compute_eflags(env), 3082ad9b50fSViktor Prutyanov 3092ad9b50fSViktor Prutyanov .Dr0 = env->dr[0], 3102ad9b50fSViktor Prutyanov .Dr1 = env->dr[1], 3112ad9b50fSViktor Prutyanov .Dr2 = env->dr[2], 3122ad9b50fSViktor Prutyanov .Dr3 = env->dr[3], 3132ad9b50fSViktor Prutyanov .Dr6 = env->dr[6], 3142ad9b50fSViktor Prutyanov .Dr7 = env->dr[7], 3152ad9b50fSViktor Prutyanov 3162ad9b50fSViktor Prutyanov .Rax = env->regs[R_EAX], 3172ad9b50fSViktor Prutyanov .Rbx = env->regs[R_EBX], 3182ad9b50fSViktor Prutyanov .Rcx = env->regs[R_ECX], 3192ad9b50fSViktor Prutyanov .Rdx = env->regs[R_EDX], 3202ad9b50fSViktor Prutyanov .Rsp = env->regs[R_ESP], 3212ad9b50fSViktor Prutyanov .Rbp = env->regs[R_EBP], 3222ad9b50fSViktor Prutyanov .Rsi = env->regs[R_ESI], 3232ad9b50fSViktor Prutyanov .Rdi = env->regs[R_EDI], 3242ad9b50fSViktor Prutyanov .R8 = env->regs[8], 3252ad9b50fSViktor Prutyanov .R9 = env->regs[9], 3262ad9b50fSViktor Prutyanov .R10 = env->regs[10], 3272ad9b50fSViktor Prutyanov .R11 = env->regs[11], 3282ad9b50fSViktor Prutyanov .R12 = env->regs[12], 3292ad9b50fSViktor Prutyanov .R13 = env->regs[13], 3302ad9b50fSViktor Prutyanov .R14 = env->regs[14], 3312ad9b50fSViktor Prutyanov .R15 = env->regs[15], 3322ad9b50fSViktor Prutyanov 3332ad9b50fSViktor Prutyanov .Rip = env->eip, 3342ad9b50fSViktor Prutyanov .FltSave = { 3352ad9b50fSViktor Prutyanov .MxCsr = env->mxcsr, 3362ad9b50fSViktor Prutyanov }, 3372ad9b50fSViktor Prutyanov }; 338f5daa829SViktor Prutyanov } else { 339f5daa829SViktor Prutyanov ctx.x32 = (WinContext32){ 340f5daa829SViktor Prutyanov .ContextFlags = WIN_CTX32_FULL | WIN_CTX_DBG, 341f5daa829SViktor Prutyanov 342f5daa829SViktor Prutyanov .SegEs = env->segs[0].selector, 343f5daa829SViktor Prutyanov .SegCs = env->segs[1].selector, 344f5daa829SViktor Prutyanov .SegSs = env->segs[2].selector, 345f5daa829SViktor Prutyanov .SegDs = env->segs[3].selector, 346f5daa829SViktor Prutyanov .SegFs = env->segs[4].selector, 347f5daa829SViktor Prutyanov .SegGs = env->segs[5].selector, 348f5daa829SViktor Prutyanov .EFlags = cpu_compute_eflags(env), 349f5daa829SViktor Prutyanov 350f5daa829SViktor Prutyanov .Dr0 = env->dr[0], 351f5daa829SViktor Prutyanov .Dr1 = env->dr[1], 352f5daa829SViktor Prutyanov .Dr2 = env->dr[2], 353f5daa829SViktor Prutyanov .Dr3 = env->dr[3], 354f5daa829SViktor Prutyanov .Dr6 = env->dr[6], 355f5daa829SViktor Prutyanov .Dr7 = env->dr[7], 356f5daa829SViktor Prutyanov 357f5daa829SViktor Prutyanov .Eax = env->regs[R_EAX], 358f5daa829SViktor Prutyanov .Ebx = env->regs[R_EBX], 359f5daa829SViktor Prutyanov .Ecx = env->regs[R_ECX], 360f5daa829SViktor Prutyanov .Edx = env->regs[R_EDX], 361f5daa829SViktor Prutyanov .Esp = env->regs[R_ESP], 362f5daa829SViktor Prutyanov .Ebp = env->regs[R_EBP], 363f5daa829SViktor Prutyanov .Esi = env->regs[R_ESI], 364f5daa829SViktor Prutyanov .Edi = env->regs[R_EDI], 365f5daa829SViktor Prutyanov 366f5daa829SViktor Prutyanov .Eip = env->eip, 367f5daa829SViktor Prutyanov }; 368f5daa829SViktor Prutyanov } 3692ad9b50fSViktor Prutyanov 3702ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, Context, 371f5daa829SViktor Prutyanov &saved_ctx[i].ctx, win_dump_ctx_size(x64), 0)) { 3722ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to save CPU #%d context", i); 3732ad9b50fSViktor Prutyanov return; 3742ad9b50fSViktor Prutyanov } 3752ad9b50fSViktor Prutyanov 3762ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, Context, 377f5daa829SViktor Prutyanov &ctx, win_dump_ctx_size(x64), 1)) { 3782ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to write CPU #%d context", i); 3792ad9b50fSViktor Prutyanov return; 3802ad9b50fSViktor Prutyanov } 3812ad9b50fSViktor Prutyanov 3822ad9b50fSViktor Prutyanov i++; 3832ad9b50fSViktor Prutyanov } 3842ad9b50fSViktor Prutyanov } 3852ad9b50fSViktor Prutyanov 386f5daa829SViktor Prutyanov static void restore_context(WinDumpHeader *h, bool x64, 3872ad9b50fSViktor Prutyanov struct saved_context *saved_ctx) 3882ad9b50fSViktor Prutyanov { 3892ad9b50fSViktor Prutyanov int i; 3902ad9b50fSViktor Prutyanov 391fb21efe9SViktor Prutyanov for (i = 0; i < WIN_DUMP_FIELD(NumberProcessors); i++) { 3922ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr, 393f5daa829SViktor Prutyanov &saved_ctx[i].ctx, win_dump_ctx_size(x64), 1)) { 394b0e70950SVladimir Sementsov-Ogievskiy warn_report("win-dump: failed to restore CPU #%d context", i); 3952ad9b50fSViktor Prutyanov } 3962ad9b50fSViktor Prutyanov } 3972ad9b50fSViktor Prutyanov } 3982ad9b50fSViktor Prutyanov 3992da91b54SViktor Prutyanov void create_win_dump(DumpState *s, Error **errp) 4002da91b54SViktor Prutyanov { 401f5daa829SViktor Prutyanov WinDumpHeader *h = (void *)(s->guest_note + VMCOREINFO_ELF_NOTE_HDR_SIZE); 40292d1b3d5SViktor Prutyanov X86CPU *first_x86_cpu = X86_CPU(first_cpu); 40392d1b3d5SViktor Prutyanov uint64_t saved_cr3 = first_x86_cpu->env.cr[3]; 4042ad9b50fSViktor Prutyanov struct saved_context *saved_ctx = NULL; 4052da91b54SViktor Prutyanov Error *local_err = NULL; 406f5daa829SViktor Prutyanov bool x64 = true; 407f5daa829SViktor Prutyanov size_t hdr_size; 4082da91b54SViktor Prutyanov 409f5daa829SViktor Prutyanov if (s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE32 && 410f5daa829SViktor Prutyanov s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE64) { 4112da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid vmcoreinfo note size"); 4122da91b54SViktor Prutyanov return; 4132da91b54SViktor Prutyanov } 4142da91b54SViktor Prutyanov 415f5daa829SViktor Prutyanov if (!check_header(h, &x64, &local_err)) { 4162da91b54SViktor Prutyanov error_propagate(errp, local_err); 4172da91b54SViktor Prutyanov return; 4182da91b54SViktor Prutyanov } 4192da91b54SViktor Prutyanov 420f5daa829SViktor Prutyanov hdr_size = x64 ? sizeof(WinDumpHeader64) : sizeof(WinDumpHeader32); 421f5daa829SViktor Prutyanov 42292d1b3d5SViktor Prutyanov /* 42392d1b3d5SViktor Prutyanov * Further access to kernel structures by virtual addresses 42492d1b3d5SViktor Prutyanov * should be made from system context. 42592d1b3d5SViktor Prutyanov */ 42692d1b3d5SViktor Prutyanov 427fb21efe9SViktor Prutyanov first_x86_cpu->env.cr[3] = WIN_DUMP_FIELD(DirectoryTableBase); 42892d1b3d5SViktor Prutyanov 429f5daa829SViktor Prutyanov check_kdbg(h, x64, &local_err); 4302da91b54SViktor Prutyanov if (local_err) { 4312da91b54SViktor Prutyanov error_propagate(errp, local_err); 43292d1b3d5SViktor Prutyanov goto out_cr3; 4332da91b54SViktor Prutyanov } 4342da91b54SViktor Prutyanov 435f5daa829SViktor Prutyanov patch_header(h, x64); 4362da91b54SViktor Prutyanov 437fb21efe9SViktor Prutyanov saved_ctx = g_new(struct saved_context, WIN_DUMP_FIELD(NumberProcessors)); 4382ad9b50fSViktor Prutyanov 4392ad9b50fSViktor Prutyanov /* 4402ad9b50fSViktor Prutyanov * Always patch context because there is no way 4412ad9b50fSViktor Prutyanov * to determine if the system-saved context is valid 4422ad9b50fSViktor Prutyanov */ 4432ad9b50fSViktor Prutyanov 444f5daa829SViktor Prutyanov patch_and_save_context(h, x64, saved_ctx, &local_err); 4452ad9b50fSViktor Prutyanov if (local_err) { 4462ad9b50fSViktor Prutyanov error_propagate(errp, local_err); 4472ad9b50fSViktor Prutyanov goto out_free; 4482ad9b50fSViktor Prutyanov } 4492ad9b50fSViktor Prutyanov 450fb21efe9SViktor Prutyanov s->total_size = WIN_DUMP_FIELD(RequiredDumpSpace); 4512da91b54SViktor Prutyanov 452f5daa829SViktor Prutyanov s->written_size = qemu_write_full(s->fd, h, hdr_size); 453f5daa829SViktor Prutyanov if (s->written_size != hdr_size) { 4542da91b54SViktor Prutyanov error_setg(errp, QERR_IO_ERROR); 4552ad9b50fSViktor Prutyanov goto out_restore; 4562da91b54SViktor Prutyanov } 4572da91b54SViktor Prutyanov 458f5daa829SViktor Prutyanov write_runs(s, h, x64, &local_err); 4592da91b54SViktor Prutyanov if (local_err) { 4602da91b54SViktor Prutyanov error_propagate(errp, local_err); 4612ad9b50fSViktor Prutyanov goto out_restore; 4622da91b54SViktor Prutyanov } 46392d1b3d5SViktor Prutyanov 4642ad9b50fSViktor Prutyanov out_restore: 465f5daa829SViktor Prutyanov restore_context(h, x64, saved_ctx); 4662ad9b50fSViktor Prutyanov out_free: 4672ad9b50fSViktor Prutyanov g_free(saved_ctx); 46892d1b3d5SViktor Prutyanov out_cr3: 46992d1b3d5SViktor Prutyanov first_x86_cpu->env.cr[3] = saved_cr3; 47092d1b3d5SViktor Prutyanov 47192d1b3d5SViktor Prutyanov return; 4722da91b54SViktor Prutyanov } 473