12da91b54SViktor Prutyanov /* 2ac978771SPhilippe 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" 15ac978771SPhilippe Mathieu-Daudé #include "exec/cpu-defs.h" 16ac978771SPhilippe Mathieu-Daudé #include "hw/core/cpu.h" 17ac978771SPhilippe Mathieu-Daudé #include "qemu/win_dump_defs.h" 182da91b54SViktor Prutyanov #include "win_dump.h" 19ac978771SPhilippe Mathieu-Daudé #include "cpu.h" 202da91b54SViktor Prutyanov 21efc3146aSPhilippe Mathieu-Daudé #if defined(TARGET_X86_64) 22efc3146aSPhilippe Mathieu-Daudé 23efc3146aSPhilippe Mathieu-Daudé bool win_dump_available(Error **errp) 24efc3146aSPhilippe Mathieu-Daudé { 25efc3146aSPhilippe Mathieu-Daudé return true; 26efc3146aSPhilippe Mathieu-Daudé } 27efc3146aSPhilippe Mathieu-Daudé 28f5daa829SViktor Prutyanov static size_t win_dump_ptr_size(bool x64) 29f5daa829SViktor Prutyanov { 30f5daa829SViktor Prutyanov return x64 ? sizeof(uint64_t) : sizeof(uint32_t); 31f5daa829SViktor Prutyanov } 32fb21efe9SViktor Prutyanov 33f5daa829SViktor Prutyanov #define _WIN_DUMP_FIELD(f) (x64 ? h->x64.f : h->x32.f) 34fb21efe9SViktor Prutyanov #define WIN_DUMP_FIELD(field) _WIN_DUMP_FIELD(field) 35fb21efe9SViktor Prutyanov 36f5daa829SViktor Prutyanov #define _WIN_DUMP_FIELD_PTR(f) (x64 ? (void *)&h->x64.f : (void *)&h->x32.f) 37fb21efe9SViktor Prutyanov #define WIN_DUMP_FIELD_PTR(field) _WIN_DUMP_FIELD_PTR(field) 38fb21efe9SViktor Prutyanov 39f5daa829SViktor Prutyanov #define _WIN_DUMP_FIELD_SIZE(f) (x64 ? sizeof(h->x64.f) : sizeof(h->x32.f)) 40fb21efe9SViktor Prutyanov #define WIN_DUMP_FIELD_SIZE(field) _WIN_DUMP_FIELD_SIZE(field) 41fb21efe9SViktor Prutyanov 42f5daa829SViktor Prutyanov static size_t win_dump_ctx_size(bool x64) 43f5daa829SViktor Prutyanov { 44f5daa829SViktor Prutyanov return x64 ? sizeof(WinContext64) : sizeof(WinContext32); 45f5daa829SViktor Prutyanov } 46fb21efe9SViktor Prutyanov 47fb21efe9SViktor Prutyanov static size_t write_run(uint64_t base_page, uint64_t page_count, 48fb21efe9SViktor Prutyanov int fd, Error **errp) 492da91b54SViktor Prutyanov { 502da91b54SViktor Prutyanov void *buf; 51fb21efe9SViktor Prutyanov uint64_t addr = base_page << TARGET_PAGE_BITS; 52fb21efe9SViktor Prutyanov uint64_t size = page_count << TARGET_PAGE_BITS; 537184de64SViktor Prutyanov uint64_t len, l; 547184de64SViktor Prutyanov size_t total = 0; 557184de64SViktor Prutyanov 567184de64SViktor Prutyanov while (size) { 577184de64SViktor Prutyanov len = size; 582da91b54SViktor Prutyanov 592da91b54SViktor Prutyanov buf = cpu_physical_memory_map(addr, &len, false); 602da91b54SViktor Prutyanov if (!buf) { 617184de64SViktor Prutyanov error_setg(errp, "win-dump: failed to map physical range" 627184de64SViktor Prutyanov " 0x%016" PRIx64 "-0x%016" PRIx64, addr, addr + size - 1); 632da91b54SViktor Prutyanov return 0; 642da91b54SViktor Prutyanov } 652da91b54SViktor Prutyanov 667184de64SViktor Prutyanov l = qemu_write_full(fd, buf, len); 672da91b54SViktor Prutyanov cpu_physical_memory_unmap(buf, addr, false, len); 687184de64SViktor Prutyanov if (l != len) { 697184de64SViktor Prutyanov error_setg(errp, QERR_IO_ERROR); 707184de64SViktor Prutyanov return 0; 717184de64SViktor Prutyanov } 722da91b54SViktor Prutyanov 737184de64SViktor Prutyanov addr += l; 747184de64SViktor Prutyanov size -= l; 757184de64SViktor Prutyanov total += l; 767184de64SViktor Prutyanov } 777184de64SViktor Prutyanov 787184de64SViktor Prutyanov return total; 792da91b54SViktor Prutyanov } 802da91b54SViktor Prutyanov 81f5daa829SViktor Prutyanov static void write_runs(DumpState *s, WinDumpHeader *h, bool x64, Error **errp) 822da91b54SViktor Prutyanov { 83fb21efe9SViktor Prutyanov uint64_t BasePage, PageCount; 842da91b54SViktor Prutyanov Error *local_err = NULL; 852da91b54SViktor Prutyanov int i; 862da91b54SViktor Prutyanov 87fb21efe9SViktor Prutyanov for (i = 0; i < WIN_DUMP_FIELD(PhysicalMemoryBlock.NumberOfRuns); i++) { 88fb21efe9SViktor Prutyanov BasePage = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].BasePage); 89fb21efe9SViktor Prutyanov PageCount = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].PageCount); 90fb21efe9SViktor Prutyanov s->written_size += write_run(BasePage, PageCount, s->fd, &local_err); 912da91b54SViktor Prutyanov if (local_err) { 922da91b54SViktor Prutyanov error_propagate(errp, local_err); 932da91b54SViktor Prutyanov return; 942da91b54SViktor Prutyanov } 952da91b54SViktor Prutyanov } 962da91b54SViktor Prutyanov } 972da91b54SViktor Prutyanov 98f5daa829SViktor Prutyanov static int cpu_read_ptr(bool x64, CPUState *cpu, uint64_t addr, uint64_t *ptr) 99fb21efe9SViktor Prutyanov { 100fb21efe9SViktor Prutyanov int ret; 101f5daa829SViktor Prutyanov uint32_t ptr32; 102fb21efe9SViktor Prutyanov uint64_t ptr64; 103fb21efe9SViktor Prutyanov 104f5daa829SViktor Prutyanov ret = cpu_memory_rw_debug(cpu, addr, x64 ? (void *)&ptr64 : (void *)&ptr32, 105f5daa829SViktor Prutyanov win_dump_ptr_size(x64), 0); 106fb21efe9SViktor Prutyanov 107f5daa829SViktor Prutyanov *ptr = x64 ? ptr64 : ptr32; 108fb21efe9SViktor Prutyanov 109fb21efe9SViktor Prutyanov return ret; 110fb21efe9SViktor Prutyanov } 111fb21efe9SViktor Prutyanov 112f5daa829SViktor Prutyanov static void patch_mm_pfn_database(WinDumpHeader *h, bool x64, Error **errp) 1132da91b54SViktor Prutyanov { 1142da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 115f5daa829SViktor Prutyanov WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET, 116fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_PTR(PfnDatabase), 117fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_SIZE(PfnDatabase), 0)) { 1182da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read MmPfnDatabase"); 1192da91b54SViktor Prutyanov return; 1202da91b54SViktor Prutyanov } 1212da91b54SViktor Prutyanov } 1222da91b54SViktor Prutyanov 123f5daa829SViktor Prutyanov static void patch_bugcheck_data(WinDumpHeader *h, bool x64, Error **errp) 1242da91b54SViktor Prutyanov { 1252da91b54SViktor Prutyanov uint64_t KiBugcheckData; 1262da91b54SViktor Prutyanov 127f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 128f5daa829SViktor Prutyanov WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_KI_BUGCHECK_DATA_OFFSET, 129fb21efe9SViktor Prutyanov &KiBugcheckData)) { 1302da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read KiBugcheckData"); 1312da91b54SViktor Prutyanov return; 1322da91b54SViktor Prutyanov } 1332da91b54SViktor Prutyanov 134fb21efe9SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, KiBugcheckData, 135fb21efe9SViktor Prutyanov WIN_DUMP_FIELD(BugcheckData), 136fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_SIZE(BugcheckData), 0)) { 1372da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read bugcheck data"); 1382da91b54SViktor Prutyanov return; 1392da91b54SViktor Prutyanov } 1402ad9b50fSViktor Prutyanov 1412ad9b50fSViktor Prutyanov /* 1422ad9b50fSViktor Prutyanov * If BugcheckCode wasn't saved, we consider guest OS as alive. 1432ad9b50fSViktor Prutyanov */ 1442ad9b50fSViktor Prutyanov 145fb21efe9SViktor Prutyanov if (!WIN_DUMP_FIELD(BugcheckCode)) { 146fb21efe9SViktor Prutyanov *(uint32_t *)WIN_DUMP_FIELD_PTR(BugcheckCode) = LIVE_SYSTEM_DUMP; 1472ad9b50fSViktor Prutyanov } 1482da91b54SViktor Prutyanov } 1492da91b54SViktor Prutyanov 1502da91b54SViktor Prutyanov /* 1512da91b54SViktor Prutyanov * This routine tries to correct mistakes in crashdump header. 1522da91b54SViktor Prutyanov */ 153f5daa829SViktor Prutyanov static void patch_header(WinDumpHeader *h, bool x64) 1542da91b54SViktor Prutyanov { 1552da91b54SViktor Prutyanov Error *local_err = NULL; 1562da91b54SViktor Prutyanov 157f5daa829SViktor Prutyanov if (x64) { 158f5daa829SViktor Prutyanov h->x64.RequiredDumpSpace = sizeof(WinDumpHeader64) + 159f5daa829SViktor Prutyanov (h->x64.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); 160f5daa829SViktor Prutyanov h->x64.PhysicalMemoryBlock.unused = 0; 161f5daa829SViktor Prutyanov h->x64.unused1 = 0; 162f5daa829SViktor Prutyanov } else { 163f5daa829SViktor Prutyanov h->x32.RequiredDumpSpace = sizeof(WinDumpHeader32) + 164f5daa829SViktor Prutyanov (h->x32.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); 165f5daa829SViktor Prutyanov } 1662da91b54SViktor Prutyanov 167f5daa829SViktor Prutyanov patch_mm_pfn_database(h, x64, &local_err); 1682da91b54SViktor Prutyanov if (local_err) { 1692da91b54SViktor Prutyanov warn_report_err(local_err); 1702da91b54SViktor Prutyanov local_err = NULL; 1712da91b54SViktor Prutyanov } 172f5daa829SViktor Prutyanov patch_bugcheck_data(h, x64, &local_err); 1732da91b54SViktor Prutyanov if (local_err) { 1742da91b54SViktor Prutyanov warn_report_err(local_err); 1752da91b54SViktor Prutyanov } 1762da91b54SViktor Prutyanov } 1772da91b54SViktor Prutyanov 178f5daa829SViktor Prutyanov static bool check_header(WinDumpHeader *h, bool *x64, Error **errp) 1792da91b54SViktor Prutyanov { 1802da91b54SViktor Prutyanov const char Signature[] = "PAGE"; 1812da91b54SViktor Prutyanov 1822da91b54SViktor Prutyanov if (memcmp(h->Signature, Signature, sizeof(h->Signature))) { 1832da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid header, expected '%.4s'," 1842da91b54SViktor Prutyanov " got '%.4s'", Signature, h->Signature); 185f5daa829SViktor Prutyanov return false; 1862da91b54SViktor Prutyanov } 1872da91b54SViktor Prutyanov 188f5daa829SViktor Prutyanov if (!memcmp(h->ValidDump, "DUMP", sizeof(h->ValidDump))) { 189f5daa829SViktor Prutyanov *x64 = false; 190f5daa829SViktor Prutyanov } else if (!memcmp(h->ValidDump, "DU64", sizeof(h->ValidDump))) { 191f5daa829SViktor Prutyanov *x64 = true; 192f5daa829SViktor Prutyanov } else { 193f5daa829SViktor Prutyanov error_setg(errp, "win-dump: invalid header, expected 'DUMP' or 'DU64'," 194f5daa829SViktor Prutyanov " got '%.4s'", h->ValidDump); 195f5daa829SViktor Prutyanov return false; 1962da91b54SViktor Prutyanov } 1972da91b54SViktor Prutyanov 198f5daa829SViktor Prutyanov return true; 199f5daa829SViktor Prutyanov } 200f5daa829SViktor Prutyanov 201f5daa829SViktor Prutyanov static void check_kdbg(WinDumpHeader *h, bool x64, Error **errp) 2022da91b54SViktor Prutyanov { 2032da91b54SViktor Prutyanov const char OwnerTag[] = "KDBG"; 2042da91b54SViktor Prutyanov char read_OwnerTag[4]; 205fb21efe9SViktor Prutyanov uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock); 2062ababfccSViktor Prutyanov bool try_fallback = true; 2072da91b54SViktor Prutyanov 2082ababfccSViktor Prutyanov try_again: 2092da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 210f5daa829SViktor Prutyanov KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET, 2112da91b54SViktor Prutyanov (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) { 2122da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read OwnerTag"); 2132da91b54SViktor Prutyanov return; 2142da91b54SViktor Prutyanov } 2152da91b54SViktor Prutyanov 2162da91b54SViktor Prutyanov if (memcmp(read_OwnerTag, OwnerTag, sizeof(read_OwnerTag))) { 2172ababfccSViktor Prutyanov if (try_fallback) { 2182ababfccSViktor Prutyanov /* 2192ababfccSViktor Prutyanov * If attempt to use original KDBG failed 2202ababfccSViktor Prutyanov * (most likely because of its encryption), 2212ababfccSViktor Prutyanov * we try to use KDBG obtained by guest driver. 2222ababfccSViktor Prutyanov */ 2232ababfccSViktor Prutyanov 224fb21efe9SViktor Prutyanov KdDebuggerDataBlock = WIN_DUMP_FIELD(BugcheckParameter1); 2252ababfccSViktor Prutyanov try_fallback = false; 2262ababfccSViktor Prutyanov goto try_again; 2272ababfccSViktor Prutyanov } else { 2282da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid KDBG OwnerTag," 2292ababfccSViktor Prutyanov " expected '%.4s', got '%.4s'", 2302da91b54SViktor Prutyanov OwnerTag, read_OwnerTag); 2312da91b54SViktor Prutyanov return; 2322da91b54SViktor Prutyanov } 2332da91b54SViktor Prutyanov } 2342da91b54SViktor Prutyanov 235f5daa829SViktor Prutyanov if (x64) { 236f5daa829SViktor Prutyanov h->x64.KdDebuggerDataBlock = KdDebuggerDataBlock; 237f5daa829SViktor Prutyanov } else { 238f5daa829SViktor Prutyanov h->x32.KdDebuggerDataBlock = KdDebuggerDataBlock; 239f5daa829SViktor Prutyanov } 2402ababfccSViktor Prutyanov } 2412ababfccSViktor Prutyanov 2422ad9b50fSViktor Prutyanov struct saved_context { 243f5daa829SViktor Prutyanov WinContext ctx; 2442ad9b50fSViktor Prutyanov uint64_t addr; 2452ad9b50fSViktor Prutyanov }; 2462ad9b50fSViktor Prutyanov 247f5daa829SViktor Prutyanov static void patch_and_save_context(WinDumpHeader *h, bool x64, 2482ad9b50fSViktor Prutyanov struct saved_context *saved_ctx, 2492ad9b50fSViktor Prutyanov Error **errp) 2502ad9b50fSViktor Prutyanov { 251fb21efe9SViktor Prutyanov uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock); 2522ad9b50fSViktor Prutyanov uint64_t KiProcessorBlock; 2532ad9b50fSViktor Prutyanov uint16_t OffsetPrcbContext; 2542ad9b50fSViktor Prutyanov CPUState *cpu; 2552ad9b50fSViktor Prutyanov int i = 0; 2562ad9b50fSViktor Prutyanov 257f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 258f5daa829SViktor Prutyanov KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET, 259fb21efe9SViktor Prutyanov &KiProcessorBlock)) { 2602ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read KiProcessorBlock"); 2612ad9b50fSViktor Prutyanov return; 2622ad9b50fSViktor Prutyanov } 2632ad9b50fSViktor Prutyanov 2642ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 265f5daa829SViktor Prutyanov KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET, 2662ad9b50fSViktor Prutyanov (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) { 2672ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read OffsetPrcbContext"); 2682ad9b50fSViktor Prutyanov return; 2692ad9b50fSViktor Prutyanov } 2702ad9b50fSViktor Prutyanov 2712ad9b50fSViktor Prutyanov CPU_FOREACH(cpu) { 2722ad9b50fSViktor Prutyanov X86CPU *x86_cpu = X86_CPU(cpu); 2732ad9b50fSViktor Prutyanov CPUX86State *env = &x86_cpu->env; 2742ad9b50fSViktor Prutyanov uint64_t Prcb; 2752ad9b50fSViktor Prutyanov uint64_t Context; 276f5daa829SViktor Prutyanov WinContext ctx; 2772ad9b50fSViktor Prutyanov 278e38c24cbSViktor Prutyanov if (i >= WIN_DUMP_FIELD(NumberProcessors)) { 279e38c24cbSViktor Prutyanov warn_report("win-dump: number of QEMU CPUs is bigger than" 280e38c24cbSViktor Prutyanov " NumberProcessors (%u) in guest Windows", 281e38c24cbSViktor Prutyanov WIN_DUMP_FIELD(NumberProcessors)); 282e38c24cbSViktor Prutyanov return; 283e38c24cbSViktor Prutyanov } 284e38c24cbSViktor Prutyanov 285f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 286f5daa829SViktor Prutyanov KiProcessorBlock + i * win_dump_ptr_size(x64), 287fb21efe9SViktor Prutyanov &Prcb)) { 2882ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read" 2892ad9b50fSViktor Prutyanov " CPU #%d PRCB location", i); 2902ad9b50fSViktor Prutyanov return; 2912ad9b50fSViktor Prutyanov } 2922ad9b50fSViktor Prutyanov 293f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 2942ad9b50fSViktor Prutyanov Prcb + OffsetPrcbContext, 295fb21efe9SViktor Prutyanov &Context)) { 2962ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read" 2972ad9b50fSViktor Prutyanov " CPU #%d ContextFrame location", i); 2982ad9b50fSViktor Prutyanov return; 2992ad9b50fSViktor Prutyanov } 3002ad9b50fSViktor Prutyanov 3012ad9b50fSViktor Prutyanov saved_ctx[i].addr = Context; 3022ad9b50fSViktor Prutyanov 303f5daa829SViktor Prutyanov if (x64) { 304f5daa829SViktor Prutyanov ctx.x64 = (WinContext64){ 305a64b4e17SViktor Prutyanov .ContextFlags = WIN_CTX64_ALL, 3062ad9b50fSViktor Prutyanov .MxCsr = env->mxcsr, 3072ad9b50fSViktor Prutyanov 3082ad9b50fSViktor Prutyanov .SegEs = env->segs[0].selector, 3092ad9b50fSViktor Prutyanov .SegCs = env->segs[1].selector, 3102ad9b50fSViktor Prutyanov .SegSs = env->segs[2].selector, 3112ad9b50fSViktor Prutyanov .SegDs = env->segs[3].selector, 3122ad9b50fSViktor Prutyanov .SegFs = env->segs[4].selector, 3132ad9b50fSViktor Prutyanov .SegGs = env->segs[5].selector, 3142ad9b50fSViktor Prutyanov .EFlags = cpu_compute_eflags(env), 3152ad9b50fSViktor Prutyanov 3162ad9b50fSViktor Prutyanov .Dr0 = env->dr[0], 3172ad9b50fSViktor Prutyanov .Dr1 = env->dr[1], 3182ad9b50fSViktor Prutyanov .Dr2 = env->dr[2], 3192ad9b50fSViktor Prutyanov .Dr3 = env->dr[3], 3202ad9b50fSViktor Prutyanov .Dr6 = env->dr[6], 3212ad9b50fSViktor Prutyanov .Dr7 = env->dr[7], 3222ad9b50fSViktor Prutyanov 3232ad9b50fSViktor Prutyanov .Rax = env->regs[R_EAX], 3242ad9b50fSViktor Prutyanov .Rbx = env->regs[R_EBX], 3252ad9b50fSViktor Prutyanov .Rcx = env->regs[R_ECX], 3262ad9b50fSViktor Prutyanov .Rdx = env->regs[R_EDX], 3272ad9b50fSViktor Prutyanov .Rsp = env->regs[R_ESP], 3282ad9b50fSViktor Prutyanov .Rbp = env->regs[R_EBP], 3292ad9b50fSViktor Prutyanov .Rsi = env->regs[R_ESI], 3302ad9b50fSViktor Prutyanov .Rdi = env->regs[R_EDI], 3312ad9b50fSViktor Prutyanov .R8 = env->regs[8], 3322ad9b50fSViktor Prutyanov .R9 = env->regs[9], 3332ad9b50fSViktor Prutyanov .R10 = env->regs[10], 3342ad9b50fSViktor Prutyanov .R11 = env->regs[11], 3352ad9b50fSViktor Prutyanov .R12 = env->regs[12], 3362ad9b50fSViktor Prutyanov .R13 = env->regs[13], 3372ad9b50fSViktor Prutyanov .R14 = env->regs[14], 3382ad9b50fSViktor Prutyanov .R15 = env->regs[15], 3392ad9b50fSViktor Prutyanov 3402ad9b50fSViktor Prutyanov .Rip = env->eip, 3412ad9b50fSViktor Prutyanov .FltSave = { 3422ad9b50fSViktor Prutyanov .MxCsr = env->mxcsr, 3432ad9b50fSViktor Prutyanov }, 3442ad9b50fSViktor Prutyanov }; 345f5daa829SViktor Prutyanov } else { 346f5daa829SViktor Prutyanov ctx.x32 = (WinContext32){ 347f5daa829SViktor Prutyanov .ContextFlags = WIN_CTX32_FULL | WIN_CTX_DBG, 348f5daa829SViktor Prutyanov 349f5daa829SViktor Prutyanov .SegEs = env->segs[0].selector, 350f5daa829SViktor Prutyanov .SegCs = env->segs[1].selector, 351f5daa829SViktor Prutyanov .SegSs = env->segs[2].selector, 352f5daa829SViktor Prutyanov .SegDs = env->segs[3].selector, 353f5daa829SViktor Prutyanov .SegFs = env->segs[4].selector, 354f5daa829SViktor Prutyanov .SegGs = env->segs[5].selector, 355f5daa829SViktor Prutyanov .EFlags = cpu_compute_eflags(env), 356f5daa829SViktor Prutyanov 357f5daa829SViktor Prutyanov .Dr0 = env->dr[0], 358f5daa829SViktor Prutyanov .Dr1 = env->dr[1], 359f5daa829SViktor Prutyanov .Dr2 = env->dr[2], 360f5daa829SViktor Prutyanov .Dr3 = env->dr[3], 361f5daa829SViktor Prutyanov .Dr6 = env->dr[6], 362f5daa829SViktor Prutyanov .Dr7 = env->dr[7], 363f5daa829SViktor Prutyanov 364f5daa829SViktor Prutyanov .Eax = env->regs[R_EAX], 365f5daa829SViktor Prutyanov .Ebx = env->regs[R_EBX], 366f5daa829SViktor Prutyanov .Ecx = env->regs[R_ECX], 367f5daa829SViktor Prutyanov .Edx = env->regs[R_EDX], 368f5daa829SViktor Prutyanov .Esp = env->regs[R_ESP], 369f5daa829SViktor Prutyanov .Ebp = env->regs[R_EBP], 370f5daa829SViktor Prutyanov .Esi = env->regs[R_ESI], 371f5daa829SViktor Prutyanov .Edi = env->regs[R_EDI], 372f5daa829SViktor Prutyanov 373f5daa829SViktor Prutyanov .Eip = env->eip, 374f5daa829SViktor Prutyanov }; 375f5daa829SViktor Prutyanov } 3762ad9b50fSViktor Prutyanov 3772ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, Context, 378f5daa829SViktor Prutyanov &saved_ctx[i].ctx, win_dump_ctx_size(x64), 0)) { 3792ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to save CPU #%d context", i); 3802ad9b50fSViktor Prutyanov return; 3812ad9b50fSViktor Prutyanov } 3822ad9b50fSViktor Prutyanov 3832ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, Context, 384f5daa829SViktor Prutyanov &ctx, win_dump_ctx_size(x64), 1)) { 3852ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to write CPU #%d context", i); 3862ad9b50fSViktor Prutyanov return; 3872ad9b50fSViktor Prutyanov } 3882ad9b50fSViktor Prutyanov 3892ad9b50fSViktor Prutyanov i++; 3902ad9b50fSViktor Prutyanov } 3912ad9b50fSViktor Prutyanov } 3922ad9b50fSViktor Prutyanov 393f5daa829SViktor Prutyanov static void restore_context(WinDumpHeader *h, bool x64, 3942ad9b50fSViktor Prutyanov struct saved_context *saved_ctx) 3952ad9b50fSViktor Prutyanov { 3962ad9b50fSViktor Prutyanov int i; 3972ad9b50fSViktor Prutyanov 398fb21efe9SViktor Prutyanov for (i = 0; i < WIN_DUMP_FIELD(NumberProcessors); i++) { 3992ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr, 400f5daa829SViktor Prutyanov &saved_ctx[i].ctx, win_dump_ctx_size(x64), 1)) { 401b0e70950SVladimir Sementsov-Ogievskiy warn_report("win-dump: failed to restore CPU #%d context", i); 4022ad9b50fSViktor Prutyanov } 4032ad9b50fSViktor Prutyanov } 4042ad9b50fSViktor Prutyanov } 4052ad9b50fSViktor Prutyanov 4062da91b54SViktor Prutyanov void create_win_dump(DumpState *s, Error **errp) 4072da91b54SViktor Prutyanov { 408f5daa829SViktor Prutyanov WinDumpHeader *h = (void *)(s->guest_note + VMCOREINFO_ELF_NOTE_HDR_SIZE); 40992d1b3d5SViktor Prutyanov X86CPU *first_x86_cpu = X86_CPU(first_cpu); 41092d1b3d5SViktor Prutyanov uint64_t saved_cr3 = first_x86_cpu->env.cr[3]; 4112ad9b50fSViktor Prutyanov struct saved_context *saved_ctx = NULL; 4122da91b54SViktor Prutyanov Error *local_err = NULL; 413f5daa829SViktor Prutyanov bool x64 = true; 414f5daa829SViktor Prutyanov size_t hdr_size; 4152da91b54SViktor Prutyanov 416f5daa829SViktor Prutyanov if (s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE32 && 417f5daa829SViktor Prutyanov s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE64) { 4182da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid vmcoreinfo note size"); 4192da91b54SViktor Prutyanov return; 4202da91b54SViktor Prutyanov } 4212da91b54SViktor Prutyanov 422f5daa829SViktor Prutyanov if (!check_header(h, &x64, &local_err)) { 4232da91b54SViktor Prutyanov error_propagate(errp, local_err); 4242da91b54SViktor Prutyanov return; 4252da91b54SViktor Prutyanov } 4262da91b54SViktor Prutyanov 427f5daa829SViktor Prutyanov hdr_size = x64 ? sizeof(WinDumpHeader64) : sizeof(WinDumpHeader32); 428f5daa829SViktor Prutyanov 42992d1b3d5SViktor Prutyanov /* 43092d1b3d5SViktor Prutyanov * Further access to kernel structures by virtual addresses 43192d1b3d5SViktor Prutyanov * should be made from system context. 43292d1b3d5SViktor Prutyanov */ 43392d1b3d5SViktor Prutyanov 434fb21efe9SViktor Prutyanov first_x86_cpu->env.cr[3] = WIN_DUMP_FIELD(DirectoryTableBase); 43592d1b3d5SViktor Prutyanov 436f5daa829SViktor Prutyanov check_kdbg(h, x64, &local_err); 4372da91b54SViktor Prutyanov if (local_err) { 4382da91b54SViktor Prutyanov error_propagate(errp, local_err); 43992d1b3d5SViktor Prutyanov goto out_cr3; 4402da91b54SViktor Prutyanov } 4412da91b54SViktor Prutyanov 442f5daa829SViktor Prutyanov patch_header(h, x64); 4432da91b54SViktor Prutyanov 444fb21efe9SViktor Prutyanov saved_ctx = g_new(struct saved_context, WIN_DUMP_FIELD(NumberProcessors)); 4452ad9b50fSViktor Prutyanov 4462ad9b50fSViktor Prutyanov /* 4472ad9b50fSViktor Prutyanov * Always patch context because there is no way 4482ad9b50fSViktor Prutyanov * to determine if the system-saved context is valid 4492ad9b50fSViktor Prutyanov */ 4502ad9b50fSViktor Prutyanov 451f5daa829SViktor Prutyanov patch_and_save_context(h, x64, saved_ctx, &local_err); 4522ad9b50fSViktor Prutyanov if (local_err) { 4532ad9b50fSViktor Prutyanov error_propagate(errp, local_err); 4542ad9b50fSViktor Prutyanov goto out_free; 4552ad9b50fSViktor Prutyanov } 4562ad9b50fSViktor Prutyanov 457fb21efe9SViktor Prutyanov s->total_size = WIN_DUMP_FIELD(RequiredDumpSpace); 4582da91b54SViktor Prutyanov 459f5daa829SViktor Prutyanov s->written_size = qemu_write_full(s->fd, h, hdr_size); 460f5daa829SViktor Prutyanov if (s->written_size != hdr_size) { 4612da91b54SViktor Prutyanov error_setg(errp, QERR_IO_ERROR); 4622ad9b50fSViktor Prutyanov goto out_restore; 4632da91b54SViktor Prutyanov } 4642da91b54SViktor Prutyanov 465f5daa829SViktor Prutyanov write_runs(s, h, x64, &local_err); 4662da91b54SViktor Prutyanov if (local_err) { 4672da91b54SViktor Prutyanov error_propagate(errp, local_err); 4682ad9b50fSViktor Prutyanov goto out_restore; 4692da91b54SViktor Prutyanov } 47092d1b3d5SViktor Prutyanov 4712ad9b50fSViktor Prutyanov out_restore: 472f5daa829SViktor Prutyanov restore_context(h, x64, saved_ctx); 4732ad9b50fSViktor Prutyanov out_free: 4742ad9b50fSViktor Prutyanov g_free(saved_ctx); 47592d1b3d5SViktor Prutyanov out_cr3: 47692d1b3d5SViktor Prutyanov first_x86_cpu->env.cr[3] = saved_cr3; 47792d1b3d5SViktor Prutyanov 47892d1b3d5SViktor Prutyanov return; 4792da91b54SViktor Prutyanov } 480efc3146aSPhilippe Mathieu-Daudé 481efc3146aSPhilippe Mathieu-Daudé #else /* !TARGET_X86_64 */ 482efc3146aSPhilippe Mathieu-Daudé 483efc3146aSPhilippe Mathieu-Daudé bool win_dump_available(Error **errp) 484efc3146aSPhilippe Mathieu-Daudé { 485efc3146aSPhilippe Mathieu-Daudé error_setg(errp, "Windows dump is only available for x86-64"); 486efc3146aSPhilippe Mathieu-Daudé 487efc3146aSPhilippe Mathieu-Daudé return false; 488efc3146aSPhilippe Mathieu-Daudé } 489efc3146aSPhilippe Mathieu-Daudé 490*97244862SPhilippe Mathieu-Daudé void create_win_dump(DumpState *s, Error **errp) 491*97244862SPhilippe Mathieu-Daudé { 492*97244862SPhilippe Mathieu-Daudé win_dump_available(errp); 493*97244862SPhilippe Mathieu-Daudé } 494*97244862SPhilippe Mathieu-Daudé 495efc3146aSPhilippe Mathieu-Daudé #endif 496