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" 14*cc37d98bSRichard Henderson #include "qemu/error-report.h" 152da91b54SViktor Prutyanov #include "qapi/qmp/qerror.h" 16ac978771SPhilippe Mathieu-Daudé #include "exec/cpu-defs.h" 17ac978771SPhilippe Mathieu-Daudé #include "hw/core/cpu.h" 18ac978771SPhilippe Mathieu-Daudé #include "qemu/win_dump_defs.h" 192da91b54SViktor Prutyanov #include "win_dump.h" 20ac978771SPhilippe Mathieu-Daudé #include "cpu.h" 212da91b54SViktor Prutyanov 22efc3146aSPhilippe Mathieu-Daudé #if defined(TARGET_X86_64) 23efc3146aSPhilippe Mathieu-Daudé 24efc3146aSPhilippe Mathieu-Daudé bool win_dump_available(Error **errp) 25efc3146aSPhilippe Mathieu-Daudé { 26efc3146aSPhilippe Mathieu-Daudé return true; 27efc3146aSPhilippe Mathieu-Daudé } 28efc3146aSPhilippe Mathieu-Daudé 29f5daa829SViktor Prutyanov static size_t win_dump_ptr_size(bool x64) 30f5daa829SViktor Prutyanov { 31f5daa829SViktor Prutyanov return x64 ? sizeof(uint64_t) : sizeof(uint32_t); 32f5daa829SViktor Prutyanov } 33fb21efe9SViktor Prutyanov 34f5daa829SViktor Prutyanov #define _WIN_DUMP_FIELD(f) (x64 ? h->x64.f : h->x32.f) 35fb21efe9SViktor Prutyanov #define WIN_DUMP_FIELD(field) _WIN_DUMP_FIELD(field) 36fb21efe9SViktor Prutyanov 37f5daa829SViktor Prutyanov #define _WIN_DUMP_FIELD_PTR(f) (x64 ? (void *)&h->x64.f : (void *)&h->x32.f) 38fb21efe9SViktor Prutyanov #define WIN_DUMP_FIELD_PTR(field) _WIN_DUMP_FIELD_PTR(field) 39fb21efe9SViktor Prutyanov 40f5daa829SViktor Prutyanov #define _WIN_DUMP_FIELD_SIZE(f) (x64 ? sizeof(h->x64.f) : sizeof(h->x32.f)) 41fb21efe9SViktor Prutyanov #define WIN_DUMP_FIELD_SIZE(field) _WIN_DUMP_FIELD_SIZE(field) 42fb21efe9SViktor Prutyanov 43f5daa829SViktor Prutyanov static size_t win_dump_ctx_size(bool x64) 44f5daa829SViktor Prutyanov { 45f5daa829SViktor Prutyanov return x64 ? sizeof(WinContext64) : sizeof(WinContext32); 46f5daa829SViktor Prutyanov } 47fb21efe9SViktor Prutyanov 48fb21efe9SViktor Prutyanov static size_t write_run(uint64_t base_page, uint64_t page_count, 49fb21efe9SViktor Prutyanov int fd, Error **errp) 502da91b54SViktor Prutyanov { 512da91b54SViktor Prutyanov void *buf; 52fb21efe9SViktor Prutyanov uint64_t addr = base_page << TARGET_PAGE_BITS; 53fb21efe9SViktor Prutyanov uint64_t size = page_count << TARGET_PAGE_BITS; 547184de64SViktor Prutyanov uint64_t len, l; 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); 682da91b54SViktor Prutyanov cpu_physical_memory_unmap(buf, addr, false, len); 697184de64SViktor Prutyanov if (l != len) { 707184de64SViktor Prutyanov error_setg(errp, QERR_IO_ERROR); 717184de64SViktor Prutyanov return 0; 727184de64SViktor Prutyanov } 732da91b54SViktor Prutyanov 747184de64SViktor Prutyanov addr += l; 757184de64SViktor Prutyanov size -= l; 767184de64SViktor Prutyanov total += l; 777184de64SViktor Prutyanov } 787184de64SViktor Prutyanov 797184de64SViktor Prutyanov return total; 802da91b54SViktor Prutyanov } 812da91b54SViktor Prutyanov 82f5daa829SViktor Prutyanov static void write_runs(DumpState *s, WinDumpHeader *h, bool x64, Error **errp) 832da91b54SViktor Prutyanov { 84fb21efe9SViktor Prutyanov uint64_t BasePage, PageCount; 852da91b54SViktor Prutyanov Error *local_err = NULL; 862da91b54SViktor Prutyanov int i; 872da91b54SViktor Prutyanov 88fb21efe9SViktor Prutyanov for (i = 0; i < WIN_DUMP_FIELD(PhysicalMemoryBlock.NumberOfRuns); i++) { 89fb21efe9SViktor Prutyanov BasePage = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].BasePage); 90fb21efe9SViktor Prutyanov PageCount = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].PageCount); 91fb21efe9SViktor Prutyanov s->written_size += write_run(BasePage, PageCount, s->fd, &local_err); 922da91b54SViktor Prutyanov if (local_err) { 932da91b54SViktor Prutyanov error_propagate(errp, local_err); 942da91b54SViktor Prutyanov return; 952da91b54SViktor Prutyanov } 962da91b54SViktor Prutyanov } 972da91b54SViktor Prutyanov } 982da91b54SViktor Prutyanov 99f5daa829SViktor Prutyanov static int cpu_read_ptr(bool x64, CPUState *cpu, uint64_t addr, uint64_t *ptr) 100fb21efe9SViktor Prutyanov { 101fb21efe9SViktor Prutyanov int ret; 102f5daa829SViktor Prutyanov uint32_t ptr32; 103fb21efe9SViktor Prutyanov uint64_t ptr64; 104fb21efe9SViktor Prutyanov 105f5daa829SViktor Prutyanov ret = cpu_memory_rw_debug(cpu, addr, x64 ? (void *)&ptr64 : (void *)&ptr32, 106f5daa829SViktor Prutyanov win_dump_ptr_size(x64), 0); 107fb21efe9SViktor Prutyanov 108f5daa829SViktor Prutyanov *ptr = x64 ? ptr64 : ptr32; 109fb21efe9SViktor Prutyanov 110fb21efe9SViktor Prutyanov return ret; 111fb21efe9SViktor Prutyanov } 112fb21efe9SViktor Prutyanov 113f5daa829SViktor Prutyanov static void patch_mm_pfn_database(WinDumpHeader *h, bool x64, Error **errp) 1142da91b54SViktor Prutyanov { 1152da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 116f5daa829SViktor Prutyanov WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET, 117fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_PTR(PfnDatabase), 118fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_SIZE(PfnDatabase), 0)) { 1192da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read MmPfnDatabase"); 1202da91b54SViktor Prutyanov return; 1212da91b54SViktor Prutyanov } 1222da91b54SViktor Prutyanov } 1232da91b54SViktor Prutyanov 124f5daa829SViktor Prutyanov static void patch_bugcheck_data(WinDumpHeader *h, bool x64, Error **errp) 1252da91b54SViktor Prutyanov { 1262da91b54SViktor Prutyanov uint64_t KiBugcheckData; 1272da91b54SViktor Prutyanov 128f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 129f5daa829SViktor Prutyanov WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_KI_BUGCHECK_DATA_OFFSET, 130fb21efe9SViktor Prutyanov &KiBugcheckData)) { 1312da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read KiBugcheckData"); 1322da91b54SViktor Prutyanov return; 1332da91b54SViktor Prutyanov } 1342da91b54SViktor Prutyanov 135fb21efe9SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, KiBugcheckData, 136fb21efe9SViktor Prutyanov WIN_DUMP_FIELD(BugcheckData), 137fb21efe9SViktor Prutyanov WIN_DUMP_FIELD_SIZE(BugcheckData), 0)) { 1382da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read bugcheck data"); 1392da91b54SViktor Prutyanov return; 1402da91b54SViktor Prutyanov } 1412ad9b50fSViktor Prutyanov 1422ad9b50fSViktor Prutyanov /* 1432ad9b50fSViktor Prutyanov * If BugcheckCode wasn't saved, we consider guest OS as alive. 1442ad9b50fSViktor Prutyanov */ 1452ad9b50fSViktor Prutyanov 146fb21efe9SViktor Prutyanov if (!WIN_DUMP_FIELD(BugcheckCode)) { 147fb21efe9SViktor Prutyanov *(uint32_t *)WIN_DUMP_FIELD_PTR(BugcheckCode) = LIVE_SYSTEM_DUMP; 1482ad9b50fSViktor Prutyanov } 1492da91b54SViktor Prutyanov } 1502da91b54SViktor Prutyanov 1512da91b54SViktor Prutyanov /* 1522da91b54SViktor Prutyanov * This routine tries to correct mistakes in crashdump header. 1532da91b54SViktor Prutyanov */ 154f5daa829SViktor Prutyanov static void patch_header(WinDumpHeader *h, bool x64) 1552da91b54SViktor Prutyanov { 1562da91b54SViktor Prutyanov Error *local_err = NULL; 1572da91b54SViktor Prutyanov 158f5daa829SViktor Prutyanov if (x64) { 159f5daa829SViktor Prutyanov h->x64.RequiredDumpSpace = sizeof(WinDumpHeader64) + 160f5daa829SViktor Prutyanov (h->x64.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); 161f5daa829SViktor Prutyanov h->x64.PhysicalMemoryBlock.unused = 0; 162f5daa829SViktor Prutyanov h->x64.unused1 = 0; 163f5daa829SViktor Prutyanov } else { 164f5daa829SViktor Prutyanov h->x32.RequiredDumpSpace = sizeof(WinDumpHeader32) + 165f5daa829SViktor Prutyanov (h->x32.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS); 166f5daa829SViktor Prutyanov } 1672da91b54SViktor Prutyanov 168f5daa829SViktor Prutyanov patch_mm_pfn_database(h, x64, &local_err); 1692da91b54SViktor Prutyanov if (local_err) { 1702da91b54SViktor Prutyanov warn_report_err(local_err); 1712da91b54SViktor Prutyanov local_err = NULL; 1722da91b54SViktor Prutyanov } 173f5daa829SViktor Prutyanov patch_bugcheck_data(h, x64, &local_err); 1742da91b54SViktor Prutyanov if (local_err) { 1752da91b54SViktor Prutyanov warn_report_err(local_err); 1762da91b54SViktor Prutyanov } 1772da91b54SViktor Prutyanov } 1782da91b54SViktor Prutyanov 179f5daa829SViktor Prutyanov static bool check_header(WinDumpHeader *h, bool *x64, Error **errp) 1802da91b54SViktor Prutyanov { 1812da91b54SViktor Prutyanov const char Signature[] = "PAGE"; 1822da91b54SViktor Prutyanov 1832da91b54SViktor Prutyanov if (memcmp(h->Signature, Signature, sizeof(h->Signature))) { 1842da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid header, expected '%.4s'," 1852da91b54SViktor Prutyanov " got '%.4s'", Signature, h->Signature); 186f5daa829SViktor Prutyanov return false; 1872da91b54SViktor Prutyanov } 1882da91b54SViktor Prutyanov 189f5daa829SViktor Prutyanov if (!memcmp(h->ValidDump, "DUMP", sizeof(h->ValidDump))) { 190f5daa829SViktor Prutyanov *x64 = false; 191f5daa829SViktor Prutyanov } else if (!memcmp(h->ValidDump, "DU64", sizeof(h->ValidDump))) { 192f5daa829SViktor Prutyanov *x64 = true; 193f5daa829SViktor Prutyanov } else { 194f5daa829SViktor Prutyanov error_setg(errp, "win-dump: invalid header, expected 'DUMP' or 'DU64'," 195f5daa829SViktor Prutyanov " got '%.4s'", h->ValidDump); 196f5daa829SViktor Prutyanov return false; 1972da91b54SViktor Prutyanov } 1982da91b54SViktor Prutyanov 199f5daa829SViktor Prutyanov return true; 200f5daa829SViktor Prutyanov } 201f5daa829SViktor Prutyanov 202f5daa829SViktor Prutyanov static void check_kdbg(WinDumpHeader *h, bool x64, Error **errp) 2032da91b54SViktor Prutyanov { 2042da91b54SViktor Prutyanov const char OwnerTag[] = "KDBG"; 2052da91b54SViktor Prutyanov char read_OwnerTag[4]; 206fb21efe9SViktor Prutyanov uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock); 2072ababfccSViktor Prutyanov bool try_fallback = true; 2082da91b54SViktor Prutyanov 2092ababfccSViktor Prutyanov try_again: 2102da91b54SViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 211f5daa829SViktor Prutyanov KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET, 2122da91b54SViktor Prutyanov (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) { 2132da91b54SViktor Prutyanov error_setg(errp, "win-dump: failed to read OwnerTag"); 2142da91b54SViktor Prutyanov return; 2152da91b54SViktor Prutyanov } 2162da91b54SViktor Prutyanov 2172da91b54SViktor Prutyanov if (memcmp(read_OwnerTag, OwnerTag, sizeof(read_OwnerTag))) { 2182ababfccSViktor Prutyanov if (try_fallback) { 2192ababfccSViktor Prutyanov /* 2202ababfccSViktor Prutyanov * If attempt to use original KDBG failed 2212ababfccSViktor Prutyanov * (most likely because of its encryption), 2222ababfccSViktor Prutyanov * we try to use KDBG obtained by guest driver. 2232ababfccSViktor Prutyanov */ 2242ababfccSViktor Prutyanov 225fb21efe9SViktor Prutyanov KdDebuggerDataBlock = WIN_DUMP_FIELD(BugcheckParameter1); 2262ababfccSViktor Prutyanov try_fallback = false; 2272ababfccSViktor Prutyanov goto try_again; 2282ababfccSViktor Prutyanov } else { 2292da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid KDBG OwnerTag," 2302ababfccSViktor Prutyanov " expected '%.4s', got '%.4s'", 2312da91b54SViktor Prutyanov OwnerTag, read_OwnerTag); 2322da91b54SViktor Prutyanov return; 2332da91b54SViktor Prutyanov } 2342da91b54SViktor Prutyanov } 2352da91b54SViktor Prutyanov 236f5daa829SViktor Prutyanov if (x64) { 237f5daa829SViktor Prutyanov h->x64.KdDebuggerDataBlock = KdDebuggerDataBlock; 238f5daa829SViktor Prutyanov } else { 239f5daa829SViktor Prutyanov h->x32.KdDebuggerDataBlock = KdDebuggerDataBlock; 240f5daa829SViktor Prutyanov } 2412ababfccSViktor Prutyanov } 2422ababfccSViktor Prutyanov 2432ad9b50fSViktor Prutyanov struct saved_context { 244f5daa829SViktor Prutyanov WinContext ctx; 2452ad9b50fSViktor Prutyanov uint64_t addr; 2462ad9b50fSViktor Prutyanov }; 2472ad9b50fSViktor Prutyanov 248f5daa829SViktor Prutyanov static void patch_and_save_context(WinDumpHeader *h, bool x64, 2492ad9b50fSViktor Prutyanov struct saved_context *saved_ctx, 2502ad9b50fSViktor Prutyanov Error **errp) 2512ad9b50fSViktor Prutyanov { 252fb21efe9SViktor Prutyanov uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock); 2532ad9b50fSViktor Prutyanov uint64_t KiProcessorBlock; 2542ad9b50fSViktor Prutyanov uint16_t OffsetPrcbContext; 2552ad9b50fSViktor Prutyanov CPUState *cpu; 2562ad9b50fSViktor Prutyanov int i = 0; 2572ad9b50fSViktor Prutyanov 258f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 259f5daa829SViktor Prutyanov KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET, 260fb21efe9SViktor Prutyanov &KiProcessorBlock)) { 2612ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read KiProcessorBlock"); 2622ad9b50fSViktor Prutyanov return; 2632ad9b50fSViktor Prutyanov } 2642ad9b50fSViktor Prutyanov 2652ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, 266f5daa829SViktor Prutyanov KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET, 2672ad9b50fSViktor Prutyanov (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) { 2682ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read OffsetPrcbContext"); 2692ad9b50fSViktor Prutyanov return; 2702ad9b50fSViktor Prutyanov } 2712ad9b50fSViktor Prutyanov 2722ad9b50fSViktor Prutyanov CPU_FOREACH(cpu) { 2732ad9b50fSViktor Prutyanov X86CPU *x86_cpu = X86_CPU(cpu); 2742ad9b50fSViktor Prutyanov CPUX86State *env = &x86_cpu->env; 2752ad9b50fSViktor Prutyanov uint64_t Prcb; 2762ad9b50fSViktor Prutyanov uint64_t Context; 277f5daa829SViktor Prutyanov WinContext ctx; 2782ad9b50fSViktor Prutyanov 279e38c24cbSViktor Prutyanov if (i >= WIN_DUMP_FIELD(NumberProcessors)) { 280e38c24cbSViktor Prutyanov warn_report("win-dump: number of QEMU CPUs is bigger than" 281e38c24cbSViktor Prutyanov " NumberProcessors (%u) in guest Windows", 282e38c24cbSViktor Prutyanov WIN_DUMP_FIELD(NumberProcessors)); 283e38c24cbSViktor Prutyanov return; 284e38c24cbSViktor Prutyanov } 285e38c24cbSViktor Prutyanov 286f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 287f5daa829SViktor Prutyanov KiProcessorBlock + i * win_dump_ptr_size(x64), 288fb21efe9SViktor Prutyanov &Prcb)) { 2892ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read" 2902ad9b50fSViktor Prutyanov " CPU #%d PRCB location", i); 2912ad9b50fSViktor Prutyanov return; 2922ad9b50fSViktor Prutyanov } 2932ad9b50fSViktor Prutyanov 294f5daa829SViktor Prutyanov if (cpu_read_ptr(x64, first_cpu, 2952ad9b50fSViktor Prutyanov Prcb + OffsetPrcbContext, 296fb21efe9SViktor Prutyanov &Context)) { 2972ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to read" 2982ad9b50fSViktor Prutyanov " CPU #%d ContextFrame location", i); 2992ad9b50fSViktor Prutyanov return; 3002ad9b50fSViktor Prutyanov } 3012ad9b50fSViktor Prutyanov 3022ad9b50fSViktor Prutyanov saved_ctx[i].addr = Context; 3032ad9b50fSViktor Prutyanov 304f5daa829SViktor Prutyanov if (x64) { 305f5daa829SViktor Prutyanov ctx.x64 = (WinContext64){ 306a64b4e17SViktor Prutyanov .ContextFlags = WIN_CTX64_ALL, 3072ad9b50fSViktor Prutyanov .MxCsr = env->mxcsr, 3082ad9b50fSViktor Prutyanov 3092ad9b50fSViktor Prutyanov .SegEs = env->segs[0].selector, 3102ad9b50fSViktor Prutyanov .SegCs = env->segs[1].selector, 3112ad9b50fSViktor Prutyanov .SegSs = env->segs[2].selector, 3122ad9b50fSViktor Prutyanov .SegDs = env->segs[3].selector, 3132ad9b50fSViktor Prutyanov .SegFs = env->segs[4].selector, 3142ad9b50fSViktor Prutyanov .SegGs = env->segs[5].selector, 3152ad9b50fSViktor Prutyanov .EFlags = cpu_compute_eflags(env), 3162ad9b50fSViktor Prutyanov 3172ad9b50fSViktor Prutyanov .Dr0 = env->dr[0], 3182ad9b50fSViktor Prutyanov .Dr1 = env->dr[1], 3192ad9b50fSViktor Prutyanov .Dr2 = env->dr[2], 3202ad9b50fSViktor Prutyanov .Dr3 = env->dr[3], 3212ad9b50fSViktor Prutyanov .Dr6 = env->dr[6], 3222ad9b50fSViktor Prutyanov .Dr7 = env->dr[7], 3232ad9b50fSViktor Prutyanov 3242ad9b50fSViktor Prutyanov .Rax = env->regs[R_EAX], 3252ad9b50fSViktor Prutyanov .Rbx = env->regs[R_EBX], 3262ad9b50fSViktor Prutyanov .Rcx = env->regs[R_ECX], 3272ad9b50fSViktor Prutyanov .Rdx = env->regs[R_EDX], 3282ad9b50fSViktor Prutyanov .Rsp = env->regs[R_ESP], 3292ad9b50fSViktor Prutyanov .Rbp = env->regs[R_EBP], 3302ad9b50fSViktor Prutyanov .Rsi = env->regs[R_ESI], 3312ad9b50fSViktor Prutyanov .Rdi = env->regs[R_EDI], 3322ad9b50fSViktor Prutyanov .R8 = env->regs[8], 3332ad9b50fSViktor Prutyanov .R9 = env->regs[9], 3342ad9b50fSViktor Prutyanov .R10 = env->regs[10], 3352ad9b50fSViktor Prutyanov .R11 = env->regs[11], 3362ad9b50fSViktor Prutyanov .R12 = env->regs[12], 3372ad9b50fSViktor Prutyanov .R13 = env->regs[13], 3382ad9b50fSViktor Prutyanov .R14 = env->regs[14], 3392ad9b50fSViktor Prutyanov .R15 = env->regs[15], 3402ad9b50fSViktor Prutyanov 3412ad9b50fSViktor Prutyanov .Rip = env->eip, 3422ad9b50fSViktor Prutyanov .FltSave = { 3432ad9b50fSViktor Prutyanov .MxCsr = env->mxcsr, 3442ad9b50fSViktor Prutyanov }, 3452ad9b50fSViktor Prutyanov }; 346f5daa829SViktor Prutyanov } else { 347f5daa829SViktor Prutyanov ctx.x32 = (WinContext32){ 348f5daa829SViktor Prutyanov .ContextFlags = WIN_CTX32_FULL | WIN_CTX_DBG, 349f5daa829SViktor Prutyanov 350f5daa829SViktor Prutyanov .SegEs = env->segs[0].selector, 351f5daa829SViktor Prutyanov .SegCs = env->segs[1].selector, 352f5daa829SViktor Prutyanov .SegSs = env->segs[2].selector, 353f5daa829SViktor Prutyanov .SegDs = env->segs[3].selector, 354f5daa829SViktor Prutyanov .SegFs = env->segs[4].selector, 355f5daa829SViktor Prutyanov .SegGs = env->segs[5].selector, 356f5daa829SViktor Prutyanov .EFlags = cpu_compute_eflags(env), 357f5daa829SViktor Prutyanov 358f5daa829SViktor Prutyanov .Dr0 = env->dr[0], 359f5daa829SViktor Prutyanov .Dr1 = env->dr[1], 360f5daa829SViktor Prutyanov .Dr2 = env->dr[2], 361f5daa829SViktor Prutyanov .Dr3 = env->dr[3], 362f5daa829SViktor Prutyanov .Dr6 = env->dr[6], 363f5daa829SViktor Prutyanov .Dr7 = env->dr[7], 364f5daa829SViktor Prutyanov 365f5daa829SViktor Prutyanov .Eax = env->regs[R_EAX], 366f5daa829SViktor Prutyanov .Ebx = env->regs[R_EBX], 367f5daa829SViktor Prutyanov .Ecx = env->regs[R_ECX], 368f5daa829SViktor Prutyanov .Edx = env->regs[R_EDX], 369f5daa829SViktor Prutyanov .Esp = env->regs[R_ESP], 370f5daa829SViktor Prutyanov .Ebp = env->regs[R_EBP], 371f5daa829SViktor Prutyanov .Esi = env->regs[R_ESI], 372f5daa829SViktor Prutyanov .Edi = env->regs[R_EDI], 373f5daa829SViktor Prutyanov 374f5daa829SViktor Prutyanov .Eip = env->eip, 375f5daa829SViktor Prutyanov }; 376f5daa829SViktor Prutyanov } 3772ad9b50fSViktor Prutyanov 3782ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, Context, 379f5daa829SViktor Prutyanov &saved_ctx[i].ctx, win_dump_ctx_size(x64), 0)) { 3802ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to save CPU #%d context", i); 3812ad9b50fSViktor Prutyanov return; 3822ad9b50fSViktor Prutyanov } 3832ad9b50fSViktor Prutyanov 3842ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, Context, 385f5daa829SViktor Prutyanov &ctx, win_dump_ctx_size(x64), 1)) { 3862ad9b50fSViktor Prutyanov error_setg(errp, "win-dump: failed to write CPU #%d context", i); 3872ad9b50fSViktor Prutyanov return; 3882ad9b50fSViktor Prutyanov } 3892ad9b50fSViktor Prutyanov 3902ad9b50fSViktor Prutyanov i++; 3912ad9b50fSViktor Prutyanov } 3922ad9b50fSViktor Prutyanov } 3932ad9b50fSViktor Prutyanov 394f5daa829SViktor Prutyanov static void restore_context(WinDumpHeader *h, bool x64, 3952ad9b50fSViktor Prutyanov struct saved_context *saved_ctx) 3962ad9b50fSViktor Prutyanov { 3972ad9b50fSViktor Prutyanov int i; 3982ad9b50fSViktor Prutyanov 399fb21efe9SViktor Prutyanov for (i = 0; i < WIN_DUMP_FIELD(NumberProcessors); i++) { 4002ad9b50fSViktor Prutyanov if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr, 401f5daa829SViktor Prutyanov &saved_ctx[i].ctx, win_dump_ctx_size(x64), 1)) { 402b0e70950SVladimir Sementsov-Ogievskiy warn_report("win-dump: failed to restore CPU #%d context", i); 4032ad9b50fSViktor Prutyanov } 4042ad9b50fSViktor Prutyanov } 4052ad9b50fSViktor Prutyanov } 4062ad9b50fSViktor Prutyanov 4072da91b54SViktor Prutyanov void create_win_dump(DumpState *s, Error **errp) 4082da91b54SViktor Prutyanov { 409f5daa829SViktor Prutyanov WinDumpHeader *h = (void *)(s->guest_note + VMCOREINFO_ELF_NOTE_HDR_SIZE); 41092d1b3d5SViktor Prutyanov X86CPU *first_x86_cpu = X86_CPU(first_cpu); 41192d1b3d5SViktor Prutyanov uint64_t saved_cr3 = first_x86_cpu->env.cr[3]; 4122ad9b50fSViktor Prutyanov struct saved_context *saved_ctx = NULL; 4132da91b54SViktor Prutyanov Error *local_err = NULL; 414f5daa829SViktor Prutyanov bool x64 = true; 415f5daa829SViktor Prutyanov size_t hdr_size; 4162da91b54SViktor Prutyanov 417f5daa829SViktor Prutyanov if (s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE32 && 418f5daa829SViktor Prutyanov s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE64) { 4192da91b54SViktor Prutyanov error_setg(errp, "win-dump: invalid vmcoreinfo note size"); 4202da91b54SViktor Prutyanov return; 4212da91b54SViktor Prutyanov } 4222da91b54SViktor Prutyanov 423f5daa829SViktor Prutyanov if (!check_header(h, &x64, &local_err)) { 4242da91b54SViktor Prutyanov error_propagate(errp, local_err); 4252da91b54SViktor Prutyanov return; 4262da91b54SViktor Prutyanov } 4272da91b54SViktor Prutyanov 428f5daa829SViktor Prutyanov hdr_size = x64 ? sizeof(WinDumpHeader64) : sizeof(WinDumpHeader32); 429f5daa829SViktor Prutyanov 43092d1b3d5SViktor Prutyanov /* 43192d1b3d5SViktor Prutyanov * Further access to kernel structures by virtual addresses 43292d1b3d5SViktor Prutyanov * should be made from system context. 43392d1b3d5SViktor Prutyanov */ 43492d1b3d5SViktor Prutyanov 435fb21efe9SViktor Prutyanov first_x86_cpu->env.cr[3] = WIN_DUMP_FIELD(DirectoryTableBase); 43692d1b3d5SViktor Prutyanov 437f5daa829SViktor Prutyanov check_kdbg(h, x64, &local_err); 4382da91b54SViktor Prutyanov if (local_err) { 4392da91b54SViktor Prutyanov error_propagate(errp, local_err); 44092d1b3d5SViktor Prutyanov goto out_cr3; 4412da91b54SViktor Prutyanov } 4422da91b54SViktor Prutyanov 443f5daa829SViktor Prutyanov patch_header(h, x64); 4442da91b54SViktor Prutyanov 445fb21efe9SViktor Prutyanov saved_ctx = g_new(struct saved_context, WIN_DUMP_FIELD(NumberProcessors)); 4462ad9b50fSViktor Prutyanov 4472ad9b50fSViktor Prutyanov /* 4482ad9b50fSViktor Prutyanov * Always patch context because there is no way 4492ad9b50fSViktor Prutyanov * to determine if the system-saved context is valid 4502ad9b50fSViktor Prutyanov */ 4512ad9b50fSViktor Prutyanov 452f5daa829SViktor Prutyanov patch_and_save_context(h, x64, saved_ctx, &local_err); 4532ad9b50fSViktor Prutyanov if (local_err) { 4542ad9b50fSViktor Prutyanov error_propagate(errp, local_err); 4552ad9b50fSViktor Prutyanov goto out_free; 4562ad9b50fSViktor Prutyanov } 4572ad9b50fSViktor Prutyanov 458fb21efe9SViktor Prutyanov s->total_size = WIN_DUMP_FIELD(RequiredDumpSpace); 4592da91b54SViktor Prutyanov 460f5daa829SViktor Prutyanov s->written_size = qemu_write_full(s->fd, h, hdr_size); 461f5daa829SViktor Prutyanov if (s->written_size != hdr_size) { 4622da91b54SViktor Prutyanov error_setg(errp, QERR_IO_ERROR); 4632ad9b50fSViktor Prutyanov goto out_restore; 4642da91b54SViktor Prutyanov } 4652da91b54SViktor Prutyanov 466f5daa829SViktor Prutyanov write_runs(s, h, x64, &local_err); 4672da91b54SViktor Prutyanov if (local_err) { 4682da91b54SViktor Prutyanov error_propagate(errp, local_err); 4692ad9b50fSViktor Prutyanov goto out_restore; 4702da91b54SViktor Prutyanov } 47192d1b3d5SViktor Prutyanov 4722ad9b50fSViktor Prutyanov out_restore: 473f5daa829SViktor Prutyanov restore_context(h, x64, saved_ctx); 4742ad9b50fSViktor Prutyanov out_free: 4752ad9b50fSViktor Prutyanov g_free(saved_ctx); 47692d1b3d5SViktor Prutyanov out_cr3: 47792d1b3d5SViktor Prutyanov first_x86_cpu->env.cr[3] = saved_cr3; 47892d1b3d5SViktor Prutyanov 47992d1b3d5SViktor Prutyanov return; 4802da91b54SViktor Prutyanov } 481efc3146aSPhilippe Mathieu-Daudé 482efc3146aSPhilippe Mathieu-Daudé #else /* !TARGET_X86_64 */ 483efc3146aSPhilippe Mathieu-Daudé 484efc3146aSPhilippe Mathieu-Daudé bool win_dump_available(Error **errp) 485efc3146aSPhilippe Mathieu-Daudé { 486efc3146aSPhilippe Mathieu-Daudé error_setg(errp, "Windows dump is only available for x86-64"); 487efc3146aSPhilippe Mathieu-Daudé 488efc3146aSPhilippe Mathieu-Daudé return false; 489efc3146aSPhilippe Mathieu-Daudé } 490efc3146aSPhilippe Mathieu-Daudé 49197244862SPhilippe Mathieu-Daudé void create_win_dump(DumpState *s, Error **errp) 49297244862SPhilippe Mathieu-Daudé { 49397244862SPhilippe Mathieu-Daudé win_dump_available(errp); 49497244862SPhilippe Mathieu-Daudé } 49597244862SPhilippe Mathieu-Daudé 496efc3146aSPhilippe Mathieu-Daudé #endif 497