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" 12*32cad1ffSPhilippe Mathieu-Daudé #include "system/dump.h" 132da91b54SViktor Prutyanov #include "qapi/error.h" 14cc37d98bSRichard Henderson #include "qemu/error-report.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; 5421c06f57SMarkus Armbruster int eno; 557184de64SViktor Prutyanov size_t total = 0; 567184de64SViktor Prutyanov 577184de64SViktor Prutyanov while (size) { 587184de64SViktor Prutyanov len = size; 592da91b54SViktor Prutyanov 602da91b54SViktor Prutyanov buf = cpu_physical_memory_map(addr, &len, false); 612da91b54SViktor Prutyanov if (!buf) { 627184de64SViktor Prutyanov error_setg(errp, "win-dump: failed to map physical range" 637184de64SViktor Prutyanov " 0x%016" PRIx64 "-0x%016" PRIx64, addr, addr + size - 1); 642da91b54SViktor Prutyanov return 0; 652da91b54SViktor Prutyanov } 662da91b54SViktor Prutyanov 677184de64SViktor Prutyanov l = qemu_write_full(fd, buf, len); 6821c06f57SMarkus Armbruster eno = errno; 692da91b54SViktor Prutyanov cpu_physical_memory_unmap(buf, addr, false, len); 707184de64SViktor Prutyanov if (l != len) { 7121c06f57SMarkus Armbruster error_setg_errno(errp, eno, "win-dump: failed to save memory"); 727184de64SViktor Prutyanov return 0; 737184de64SViktor Prutyanov } 742da91b54SViktor Prutyanov 757184de64SViktor Prutyanov addr += l; 767184de64SViktor Prutyanov size -= l; 777184de64SViktor Prutyanov total += l; 787184de64SViktor Prutyanov } 797184de64SViktor Prutyanov 807184de64SViktor Prutyanov return total; 812da91b54SViktor Prutyanov } 822da91b54SViktor Prutyanov 83f5daa829SViktor Prutyanov static void write_runs(DumpState *s, WinDumpHeader *h, bool x64, Error **errp) 842da91b54SViktor Prutyanov { 85fb21efe9SViktor Prutyanov uint64_t BasePage, PageCount; 862da91b54SViktor Prutyanov Error *local_err = NULL; 872da91b54SViktor Prutyanov int i; 882da91b54SViktor Prutyanov 89fb21efe9SViktor Prutyanov for (i = 0; i < WIN_DUMP_FIELD(PhysicalMemoryBlock.NumberOfRuns); i++) { 90fb21efe9SViktor Prutyanov BasePage = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].BasePage); 91fb21efe9SViktor Prutyanov PageCount = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].PageCount); 92fb21efe9SViktor Prutyanov s->written_size += write_run(BasePage, PageCount, s->fd, &local_err); 932da91b54SViktor Prutyanov if (local_err) { 942da91b54SViktor Prutyanov error_propagate(errp, local_err); 952da91b54SViktor Prutyanov return; 962da91b54SViktor Prutyanov } 972da91b54SViktor Prutyanov } 982da91b54SViktor Prutyanov } 992da91b54SViktor Prutyanov 100f5daa829SViktor Prutyanov static int cpu_read_ptr(bool x64, CPUState *cpu, uint64_t addr, uint64_t *ptr) 101fb21efe9SViktor Prutyanov { 102fb21efe9SViktor Prutyanov int ret; 103f5daa829SViktor Prutyanov uint32_t ptr32; 104fb21efe9SViktor Prutyanov uint64_t ptr64; 105fb21efe9SViktor Prutyanov 106f5daa829SViktor Prutyanov ret = cpu_memory_rw_debug(cpu, addr, x64 ? (void *)&ptr64 : (void *)&ptr32, 107f5daa829SViktor Prutyanov win_dump_ptr_size(x64), 0); 108fb21efe9SViktor Prutyanov 109f5daa829SViktor Prutyanov *ptr = x64 ? ptr64 : ptr32; 110fb21efe9SViktor Prutyanov 111fb21efe9SViktor Prutyanov return ret; 112fb21efe9SViktor Prutyanov } 113fb21efe9SViktor Prutyanov 114f5daa829SViktor Prutyanov static void patch_mm_pfn_database(WinDumpHeader *h, bool x64, Error **errp) 1152da91b54SViktor Prutyanov { 1162da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 117f5daa829SViktor Prutyanov WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET, 118fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_PTR(PfnDatabase), 119fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_SIZE(PfnDatabase), 0)) { 1202da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read MmPfnDatabase"); 1212da91b54SViktor Prutyanov return; 1222da91b54SViktor Prutyanov } 1232da91b54SViktor Prutyanov } 1242da91b54SViktor Prutyanov 125f5daa829SViktor Prutyanov static void patch_bugcheck_data(WinDumpHeader *h, bool x64, Error **errp) 1262da91b54SViktor Prutyanov { 1272da91b54SViktor Prutyanov uint64_t KiBugcheckData; 1282da91b54SViktor Prutyanov 129f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 130f5daa829SViktor Prutyanov WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_KI_BUGCHECK_DATA_OFFSET, 131fb21efe9SViktor Prutyanov &KiBugcheckData)) { 1322da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read KiBugcheckData"); 1332da91b54SViktor Prutyanov return; 1342da91b54SViktor Prutyanov } 1352da91b54SViktor Prutyanov 136fb21efe9SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, KiBugcheckData, 137fb21efe9SViktor Prutyanov WIN_DUMP_FIELD(BugcheckData), 138fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_SIZE(BugcheckData), 0)) { 1392da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read bugcheck data"); 1402da91b54SViktor Prutyanov return; 1412da91b54SViktor Prutyanov } 1422ad9b50fSViktor Prutyanov 1432ad9b50fSViktor Prutyanov /* 1442ad9b50fSViktor Prutyanov * If BugcheckCode wasn't saved, we consider guest OS as alive. 1452ad9b50fSViktor Prutyanov */ 1462ad9b50fSViktor Prutyanov 147fb21efe9SViktor Prutyanov if (!WIN_DUMP_FIELD(BugcheckCode)) { 148fb21efe9SViktor Prutyanov *(uint32_t *)WIN_DUMP_FIELD_PTR(BugcheckCode) = LIVE_SYSTEM_DUMP; 1492ad9b50fSViktor Prutyanov } 1502da91b54SViktor Prutyanov } 1512da91b54SViktor Prutyanov 1522da91b54SViktor Prutyanov /* 1532da91b54SViktor Prutyanov * This routine tries to correct mistakes in crashdump header. 1542da91b54SViktor Prutyanov */ 155f5daa829SViktor Prutyanov static void patch_header(WinDumpHeader *h, bool x64) 1562da91b54SViktor Prutyanov { 1572da91b54SViktor Prutyanov Error *local_err = NULL; 1582da91b54SViktor Prutyanov 159f5daa829SViktor Prutyanov if (x64) { 160f5daa829SViktor Prutyanov h->x64.RequiredDumpSpace = sizeof(WinDumpHeader64) + 161f5daa829SViktor Prutyanov (h->x64.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); 162f5daa829SViktor Prutyanov h->x64.PhysicalMemoryBlock.unused = 0; 163f5daa829SViktor Prutyanov h->x64.unused1 = 0; 164f5daa829SViktor Prutyanov } else { 165f5daa829SViktor Prutyanov h->x32.RequiredDumpSpace = sizeof(WinDumpHeader32) + 166f5daa829SViktor Prutyanov (h->x32.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); 167f5daa829SViktor Prutyanov } 1682da91b54SViktor Prutyanov 169f5daa829SViktor Prutyanov patch_mm_pfn_database(h, x64, &local_err); 1702da91b54SViktor Prutyanov if (local_err) { 1712da91b54SViktor Prutyanov warn_report_err(local_err); 1722da91b54SViktor Prutyanov local_err = NULL; 1732da91b54SViktor Prutyanov } 174f5daa829SViktor Prutyanov patch_bugcheck_data(h, x64, &local_err); 1752da91b54SViktor Prutyanov if (local_err) { 1762da91b54SViktor Prutyanov warn_report_err(local_err); 1772da91b54SViktor Prutyanov } 1782da91b54SViktor Prutyanov } 1792da91b54SViktor Prutyanov 180f5daa829SViktor Prutyanov static bool check_header(WinDumpHeader *h, bool *x64, Error **errp) 1812da91b54SViktor Prutyanov { 1822da91b54SViktor Prutyanov const char Signature[] = "PAGE"; 1832da91b54SViktor Prutyanov 1842da91b54SViktor Prutyanov if (memcmp(h->Signature, Signature, sizeof(h->Signature))) { 1852da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid header, expected '%.4s'," 1862da91b54SViktor Prutyanov " got '%.4s'", Signature, h->Signature); 187f5daa829SViktor Prutyanov return false; 1882da91b54SViktor Prutyanov } 1892da91b54SViktor Prutyanov 190f5daa829SViktor Prutyanov if (!memcmp(h->ValidDump, "DUMP", sizeof(h->ValidDump))) { 191f5daa829SViktor Prutyanov *x64 = false; 192f5daa829SViktor Prutyanov } else if (!memcmp(h->ValidDump, "DU64", sizeof(h->ValidDump))) { 193f5daa829SViktor Prutyanov *x64 = true; 194f5daa829SViktor Prutyanov } else { 195f5daa829SViktor Prutyanov error_setg(errp, "win-dump: invalid header, expected 'DUMP' or 'DU64'," 196f5daa829SViktor Prutyanov " got '%.4s'", h->ValidDump); 197f5daa829SViktor Prutyanov return false; 1982da91b54SViktor Prutyanov } 1992da91b54SViktor Prutyanov 200f5daa829SViktor Prutyanov return true; 201f5daa829SViktor Prutyanov } 202f5daa829SViktor Prutyanov 203f5daa829SViktor Prutyanov static void check_kdbg(WinDumpHeader *h, bool x64, Error **errp) 2042da91b54SViktor Prutyanov { 2052da91b54SViktor Prutyanov const char OwnerTag[] = "KDBG"; 2062da91b54SViktor Prutyanov char read_OwnerTag[4]; 207fb21efe9SViktor Prutyanov uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock); 2082ababfccSViktor Prutyanov bool try_fallback = true; 2092da91b54SViktor Prutyanov 2102ababfccSViktor Prutyanov try_again: 2112da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 212f5daa829SViktor Prutyanov KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET, 2132da91b54SViktor Prutyanov (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) { 2142da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read OwnerTag"); 2152da91b54SViktor Prutyanov return; 2162da91b54SViktor Prutyanov } 2172da91b54SViktor Prutyanov 2182da91b54SViktor Prutyanov if (memcmp(read_OwnerTag, OwnerTag, sizeof(read_OwnerTag))) { 2192ababfccSViktor Prutyanov if (try_fallback) { 2202ababfccSViktor Prutyanov /* 2212ababfccSViktor Prutyanov * If attempt to use original KDBG failed 2222ababfccSViktor Prutyanov * (most likely because of its encryption), 2232ababfccSViktor Prutyanov * we try to use KDBG obtained by guest driver. 2242ababfccSViktor Prutyanov */ 2252ababfccSViktor Prutyanov 226fb21efe9SViktor Prutyanov KdDebuggerDataBlock = WIN_DUMP_FIELD(BugcheckParameter1); 2272ababfccSViktor Prutyanov try_fallback = false; 2282ababfccSViktor Prutyanov goto try_again; 2292ababfccSViktor Prutyanov } else { 2302da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid KDBG OwnerTag," 2312ababfccSViktor Prutyanov " expected '%.4s', got '%.4s'", 2322da91b54SViktor Prutyanov OwnerTag, read_OwnerTag); 2332da91b54SViktor Prutyanov return; 2342da91b54SViktor Prutyanov } 2352da91b54SViktor Prutyanov } 2362da91b54SViktor Prutyanov 237f5daa829SViktor Prutyanov if (x64) { 238f5daa829SViktor Prutyanov h->x64.KdDebuggerDataBlock = KdDebuggerDataBlock; 239f5daa829SViktor Prutyanov } else { 240f5daa829SViktor Prutyanov h->x32.KdDebuggerDataBlock = KdDebuggerDataBlock; 241f5daa829SViktor Prutyanov } 2422ababfccSViktor Prutyanov } 2432ababfccSViktor Prutyanov 2442ad9b50fSViktor Prutyanov struct saved_context { 245f5daa829SViktor Prutyanov WinContext ctx; 2462ad9b50fSViktor Prutyanov uint64_t addr; 2472ad9b50fSViktor Prutyanov }; 2482ad9b50fSViktor Prutyanov 249f5daa829SViktor Prutyanov static void patch_and_save_context(WinDumpHeader *h, bool x64, 2502ad9b50fSViktor Prutyanov struct saved_context *saved_ctx, 2512ad9b50fSViktor Prutyanov Error **errp) 2522ad9b50fSViktor Prutyanov { 253fb21efe9SViktor Prutyanov uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock); 2542ad9b50fSViktor Prutyanov uint64_t KiProcessorBlock; 2552ad9b50fSViktor Prutyanov uint16_t OffsetPrcbContext; 2562ad9b50fSViktor Prutyanov CPUState *cpu; 2572ad9b50fSViktor Prutyanov int i = 0; 2582ad9b50fSViktor Prutyanov 259f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 260f5daa829SViktor Prutyanov KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET, 261fb21efe9SViktor Prutyanov &KiProcessorBlock)) { 2622ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read KiProcessorBlock"); 2632ad9b50fSViktor Prutyanov return; 2642ad9b50fSViktor Prutyanov } 2652ad9b50fSViktor Prutyanov 2662ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 267f5daa829SViktor Prutyanov KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET, 2682ad9b50fSViktor Prutyanov (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) { 2692ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read OffsetPrcbContext"); 2702ad9b50fSViktor Prutyanov return; 2712ad9b50fSViktor Prutyanov } 2722ad9b50fSViktor Prutyanov 2732ad9b50fSViktor Prutyanov CPU_FOREACH(cpu) { 2742ad9b50fSViktor Prutyanov X86CPU *x86_cpu = X86_CPU(cpu); 2752ad9b50fSViktor Prutyanov CPUX86State *env = &x86_cpu->env; 2762ad9b50fSViktor Prutyanov uint64_t Prcb; 2772ad9b50fSViktor Prutyanov uint64_t Context; 278f5daa829SViktor Prutyanov WinContext ctx; 2792ad9b50fSViktor Prutyanov 280e38c24cbSViktor Prutyanov if (i >= WIN_DUMP_FIELD(NumberProcessors)) { 281e38c24cbSViktor Prutyanov warn_report("win-dump: number of QEMU CPUs is bigger than" 282e38c24cbSViktor Prutyanov " NumberProcessors (%u) in guest Windows", 283e38c24cbSViktor Prutyanov WIN_DUMP_FIELD(NumberProcessors)); 284e38c24cbSViktor Prutyanov return; 285e38c24cbSViktor Prutyanov } 286e38c24cbSViktor Prutyanov 287f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 288f5daa829SViktor Prutyanov KiProcessorBlock + i * win_dump_ptr_size(x64), 289fb21efe9SViktor Prutyanov &Prcb)) { 2902ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read" 2912ad9b50fSViktor Prutyanov " CPU #%d PRCB location", i); 2922ad9b50fSViktor Prutyanov return; 2932ad9b50fSViktor Prutyanov } 2942ad9b50fSViktor Prutyanov 295f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 2962ad9b50fSViktor Prutyanov Prcb + OffsetPrcbContext, 297fb21efe9SViktor Prutyanov &Context)) { 2982ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read" 2992ad9b50fSViktor Prutyanov " CPU #%d ContextFrame location", i); 3002ad9b50fSViktor Prutyanov return; 3012ad9b50fSViktor Prutyanov } 3022ad9b50fSViktor Prutyanov 3032ad9b50fSViktor Prutyanov saved_ctx[i].addr = Context; 3042ad9b50fSViktor Prutyanov 305f5daa829SViktor Prutyanov if (x64) { 306f5daa829SViktor Prutyanov ctx.x64 = (WinContext64){ 307a64b4e17SViktor Prutyanov .ContextFlags = WIN_CTX64_ALL, 3082ad9b50fSViktor Prutyanov .MxCsr = env->mxcsr, 3092ad9b50fSViktor Prutyanov 3102ad9b50fSViktor Prutyanov .SegEs = env->segs[0].selector, 3112ad9b50fSViktor Prutyanov .SegCs = env->segs[1].selector, 3122ad9b50fSViktor Prutyanov .SegSs = env->segs[2].selector, 3132ad9b50fSViktor Prutyanov .SegDs = env->segs[3].selector, 3142ad9b50fSViktor Prutyanov .SegFs = env->segs[4].selector, 3152ad9b50fSViktor Prutyanov .SegGs = env->segs[5].selector, 3162ad9b50fSViktor Prutyanov .EFlags = cpu_compute_eflags(env), 3172ad9b50fSViktor Prutyanov 3182ad9b50fSViktor Prutyanov .Dr0 = env->dr[0], 3192ad9b50fSViktor Prutyanov .Dr1 = env->dr[1], 3202ad9b50fSViktor Prutyanov .Dr2 = env->dr[2], 3212ad9b50fSViktor Prutyanov .Dr3 = env->dr[3], 3222ad9b50fSViktor Prutyanov .Dr6 = env->dr[6], 3232ad9b50fSViktor Prutyanov .Dr7 = env->dr[7], 3242ad9b50fSViktor Prutyanov 3252ad9b50fSViktor Prutyanov .Rax = env->regs[R_EAX], 3262ad9b50fSViktor Prutyanov .Rbx = env->regs[R_EBX], 3272ad9b50fSViktor Prutyanov .Rcx = env->regs[R_ECX], 3282ad9b50fSViktor Prutyanov .Rdx = env->regs[R_EDX], 3292ad9b50fSViktor Prutyanov .Rsp = env->regs[R_ESP], 3302ad9b50fSViktor Prutyanov .Rbp = env->regs[R_EBP], 3312ad9b50fSViktor Prutyanov .Rsi = env->regs[R_ESI], 3322ad9b50fSViktor Prutyanov .Rdi = env->regs[R_EDI], 3332ad9b50fSViktor Prutyanov .R8 = env->regs[8], 3342ad9b50fSViktor Prutyanov .R9 = env->regs[9], 3352ad9b50fSViktor Prutyanov .R10 = env->regs[10], 3362ad9b50fSViktor Prutyanov .R11 = env->regs[11], 3372ad9b50fSViktor Prutyanov .R12 = env->regs[12], 3382ad9b50fSViktor Prutyanov .R13 = env->regs[13], 3392ad9b50fSViktor Prutyanov .R14 = env->regs[14], 3402ad9b50fSViktor Prutyanov .R15 = env->regs[15], 3412ad9b50fSViktor Prutyanov 3422ad9b50fSViktor Prutyanov .Rip = env->eip, 3432ad9b50fSViktor Prutyanov .FltSave = { 3442ad9b50fSViktor Prutyanov .MxCsr = env->mxcsr, 3452ad9b50fSViktor Prutyanov }, 3462ad9b50fSViktor Prutyanov }; 347f5daa829SViktor Prutyanov } else { 348f5daa829SViktor Prutyanov ctx.x32 = (WinContext32){ 349f5daa829SViktor Prutyanov .ContextFlags = WIN_CTX32_FULL | WIN_CTX_DBG, 350f5daa829SViktor Prutyanov 351f5daa829SViktor Prutyanov .SegEs = env->segs[0].selector, 352f5daa829SViktor Prutyanov .SegCs = env->segs[1].selector, 353f5daa829SViktor Prutyanov .SegSs = env->segs[2].selector, 354f5daa829SViktor Prutyanov .SegDs = env->segs[3].selector, 355f5daa829SViktor Prutyanov .SegFs = env->segs[4].selector, 356f5daa829SViktor Prutyanov .SegGs = env->segs[5].selector, 357f5daa829SViktor Prutyanov .EFlags = cpu_compute_eflags(env), 358f5daa829SViktor Prutyanov 359f5daa829SViktor Prutyanov .Dr0 = env->dr[0], 360f5daa829SViktor Prutyanov .Dr1 = env->dr[1], 361f5daa829SViktor Prutyanov .Dr2 = env->dr[2], 362f5daa829SViktor Prutyanov .Dr3 = env->dr[3], 363f5daa829SViktor Prutyanov .Dr6 = env->dr[6], 364f5daa829SViktor Prutyanov .Dr7 = env->dr[7], 365f5daa829SViktor Prutyanov 366f5daa829SViktor Prutyanov .Eax = env->regs[R_EAX], 367f5daa829SViktor Prutyanov .Ebx = env->regs[R_EBX], 368f5daa829SViktor Prutyanov .Ecx = env->regs[R_ECX], 369f5daa829SViktor Prutyanov .Edx = env->regs[R_EDX], 370f5daa829SViktor Prutyanov .Esp = env->regs[R_ESP], 371f5daa829SViktor Prutyanov .Ebp = env->regs[R_EBP], 372f5daa829SViktor Prutyanov .Esi = env->regs[R_ESI], 373f5daa829SViktor Prutyanov .Edi = env->regs[R_EDI], 374f5daa829SViktor Prutyanov 375f5daa829SViktor Prutyanov .Eip = env->eip, 376f5daa829SViktor Prutyanov }; 377f5daa829SViktor Prutyanov } 3782ad9b50fSViktor Prutyanov 3792ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, Context, 380f5daa829SViktor Prutyanov &saved_ctx[i].ctx, win_dump_ctx_size(x64), 0)) { 3812ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to save CPU #%d context", i); 3822ad9b50fSViktor Prutyanov return; 3832ad9b50fSViktor Prutyanov } 3842ad9b50fSViktor Prutyanov 3852ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, Context, 386f5daa829SViktor Prutyanov &ctx, win_dump_ctx_size(x64), 1)) { 3872ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to write CPU #%d context", i); 3882ad9b50fSViktor Prutyanov return; 3892ad9b50fSViktor Prutyanov } 3902ad9b50fSViktor Prutyanov 3912ad9b50fSViktor Prutyanov i++; 3922ad9b50fSViktor Prutyanov } 3932ad9b50fSViktor Prutyanov } 3942ad9b50fSViktor Prutyanov 395f5daa829SViktor Prutyanov static void restore_context(WinDumpHeader *h, bool x64, 3962ad9b50fSViktor Prutyanov struct saved_context *saved_ctx) 3972ad9b50fSViktor Prutyanov { 3982ad9b50fSViktor Prutyanov int i; 3992ad9b50fSViktor Prutyanov 400fb21efe9SViktor Prutyanov for (i = 0; i < WIN_DUMP_FIELD(NumberProcessors); i++) { 4012ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr, 402f5daa829SViktor Prutyanov &saved_ctx[i].ctx, win_dump_ctx_size(x64), 1)) { 403b0e70950SVladimir Sementsov-Ogievskiy warn_report("win-dump: failed to restore CPU #%d context", i); 4042ad9b50fSViktor Prutyanov } 4052ad9b50fSViktor Prutyanov } 4062ad9b50fSViktor Prutyanov } 4072ad9b50fSViktor Prutyanov 4082da91b54SViktor Prutyanov void create_win_dump(DumpState *s, Error **errp) 4092da91b54SViktor Prutyanov { 410f5daa829SViktor Prutyanov WinDumpHeader *h = (void *)(s->guest_note + VMCOREINFO_ELF_NOTE_HDR_SIZE); 41192d1b3d5SViktor Prutyanov X86CPU *first_x86_cpu = X86_CPU(first_cpu); 41292d1b3d5SViktor Prutyanov uint64_t saved_cr3 = first_x86_cpu->env.cr[3]; 4132ad9b50fSViktor Prutyanov struct saved_context *saved_ctx = NULL; 4142da91b54SViktor Prutyanov Error *local_err = NULL; 415f5daa829SViktor Prutyanov bool x64 = true; 416f5daa829SViktor Prutyanov size_t hdr_size; 4172da91b54SViktor Prutyanov 418f5daa829SViktor Prutyanov if (s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE32 && 419f5daa829SViktor Prutyanov s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE64) { 4202da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid vmcoreinfo note size"); 4212da91b54SViktor Prutyanov return; 4222da91b54SViktor Prutyanov } 4232da91b54SViktor Prutyanov 424f5daa829SViktor Prutyanov if (!check_header(h, &x64, &local_err)) { 4252da91b54SViktor Prutyanov error_propagate(errp, local_err); 4262da91b54SViktor Prutyanov return; 4272da91b54SViktor Prutyanov } 4282da91b54SViktor Prutyanov 429f5daa829SViktor Prutyanov hdr_size = x64 ? sizeof(WinDumpHeader64) : sizeof(WinDumpHeader32); 430f5daa829SViktor Prutyanov 43192d1b3d5SViktor Prutyanov /* 43292d1b3d5SViktor Prutyanov * Further access to kernel structures by virtual addresses 43392d1b3d5SViktor Prutyanov * should be made from system context. 43492d1b3d5SViktor Prutyanov */ 43592d1b3d5SViktor Prutyanov 436fb21efe9SViktor Prutyanov first_x86_cpu->env.cr[3] = WIN_DUMP_FIELD(DirectoryTableBase); 43792d1b3d5SViktor Prutyanov 438f5daa829SViktor Prutyanov check_kdbg(h, x64, &local_err); 4392da91b54SViktor Prutyanov if (local_err) { 4402da91b54SViktor Prutyanov error_propagate(errp, local_err); 44192d1b3d5SViktor Prutyanov goto out_cr3; 4422da91b54SViktor Prutyanov } 4432da91b54SViktor Prutyanov 444f5daa829SViktor Prutyanov patch_header(h, x64); 4452da91b54SViktor Prutyanov 446fb21efe9SViktor Prutyanov saved_ctx = g_new(struct saved_context, WIN_DUMP_FIELD(NumberProcessors)); 4472ad9b50fSViktor Prutyanov 4482ad9b50fSViktor Prutyanov /* 4492ad9b50fSViktor Prutyanov * Always patch context because there is no way 4502ad9b50fSViktor Prutyanov * to determine if the system-saved context is valid 4512ad9b50fSViktor Prutyanov */ 4522ad9b50fSViktor Prutyanov 453f5daa829SViktor Prutyanov patch_and_save_context(h, x64, saved_ctx, &local_err); 4542ad9b50fSViktor Prutyanov if (local_err) { 4552ad9b50fSViktor Prutyanov error_propagate(errp, local_err); 4562ad9b50fSViktor Prutyanov goto out_free; 4572ad9b50fSViktor Prutyanov } 4582ad9b50fSViktor Prutyanov 459fb21efe9SViktor Prutyanov s->total_size = WIN_DUMP_FIELD(RequiredDumpSpace); 4602da91b54SViktor Prutyanov 461f5daa829SViktor Prutyanov s->written_size = qemu_write_full(s->fd, h, hdr_size); 462f5daa829SViktor Prutyanov if (s->written_size != hdr_size) { 46321c06f57SMarkus Armbruster error_setg_errno(errp, errno, "win-dump: failed to write header"); 4642ad9b50fSViktor Prutyanov goto out_restore; 4652da91b54SViktor Prutyanov } 4662da91b54SViktor Prutyanov 467f5daa829SViktor Prutyanov write_runs(s, h, x64, &local_err); 4682da91b54SViktor Prutyanov if (local_err) { 4692da91b54SViktor Prutyanov error_propagate(errp, local_err); 4702ad9b50fSViktor Prutyanov goto out_restore; 4712da91b54SViktor Prutyanov } 47292d1b3d5SViktor Prutyanov 4732ad9b50fSViktor Prutyanov out_restore: 474f5daa829SViktor Prutyanov restore_context(h, x64, saved_ctx); 4752ad9b50fSViktor Prutyanov out_free: 4762ad9b50fSViktor Prutyanov g_free(saved_ctx); 47792d1b3d5SViktor Prutyanov out_cr3: 47892d1b3d5SViktor Prutyanov first_x86_cpu->env.cr[3] = saved_cr3; 47992d1b3d5SViktor Prutyanov 48092d1b3d5SViktor Prutyanov return; 4812da91b54SViktor Prutyanov } 482efc3146aSPhilippe Mathieu-Daudé 483efc3146aSPhilippe Mathieu-Daudé #else /* !TARGET_X86_64 */ 484efc3146aSPhilippe Mathieu-Daudé 485efc3146aSPhilippe Mathieu-Daudé bool win_dump_available(Error **errp) 486efc3146aSPhilippe Mathieu-Daudé { 487efc3146aSPhilippe Mathieu-Daudé error_setg(errp, "Windows dump is only available for x86-64"); 488efc3146aSPhilippe Mathieu-Daudé 489efc3146aSPhilippe Mathieu-Daudé return false; 490efc3146aSPhilippe Mathieu-Daudé } 491efc3146aSPhilippe Mathieu-Daudé 49297244862SPhilippe Mathieu-Daudé void create_win_dump(DumpState *s, Error **errp) 49397244862SPhilippe Mathieu-Daudé { 49497244862SPhilippe Mathieu-Daudé win_dump_available(errp); 49597244862SPhilippe Mathieu-Daudé } 49697244862SPhilippe Mathieu-Daudé 497efc3146aSPhilippe Mathieu-Daudé #endif 498