+struct saved_context {
+ WinContext ctx;
+ uint64_t addr;
+};
+
+static void patch_and_save_context(WinDumpHeader64 *h,
+ struct saved_context *saved_ctx,
+ Error **errp)
+{
+ uint64_t KiProcessorBlock;
+ uint16_t OffsetPrcbContext;
+ CPUState *cpu;
+ int i = 0;
+
+ if (cpu_memory_rw_debug(first_cpu,
+ h->KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET64,
+ (uint8_t *)&KiProcessorBlock, sizeof(KiProcessorBlock), 0)) {
+ error_setg(errp, "win-dump: failed to read KiProcessorBlock");
+ return;
+ }
+
+ if (cpu_memory_rw_debug(first_cpu,
+ h->KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET64,
+ (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) {
+ error_setg(errp, "win-dump: failed to read OffsetPrcbContext");
+ return;
+ }
+
+ CPU_FOREACH(cpu) {
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ uint64_t Prcb;
+ uint64_t Context;
+ WinContext ctx;
+
+ if (cpu_memory_rw_debug(first_cpu,
+ KiProcessorBlock + i * sizeof(uint64_t),
+ (uint8_t *)&Prcb, sizeof(Prcb), 0)) {
+ error_setg(errp, "win-dump: failed to read"
+ " CPU #%d PRCB location", i);
+ return;
+ }
+
+ if (cpu_memory_rw_debug(first_cpu,
+ Prcb + OffsetPrcbContext,
+ (uint8_t *)&Context, sizeof(Context), 0)) {
+ error_setg(errp, "win-dump: failed to read"
+ " CPU #%d ContextFrame location", i);
+ return;
+ }
+
+ saved_ctx[i].addr = Context;
+
+ ctx = (WinContext){
+ .ContextFlags = WIN_CTX_ALL,
+ .MxCsr = env->mxcsr,
+
+ .SegEs = env->segs[0].selector,
+ .SegCs = env->segs[1].selector,
+ .SegSs = env->segs[2].selector,
+ .SegDs = env->segs[3].selector,
+ .SegFs = env->segs[4].selector,
+ .SegGs = env->segs[5].selector,
+ .EFlags = cpu_compute_eflags(env),
+
+ .Dr0 = env->dr[0],
+ .Dr1 = env->dr[1],
+ .Dr2 = env->dr[2],
+ .Dr3 = env->dr[3],
+ .Dr6 = env->dr[6],
+ .Dr7 = env->dr[7],
+
+ .Rax = env->regs[R_EAX],
+ .Rbx = env->regs[R_EBX],
+ .Rcx = env->regs[R_ECX],
+ .Rdx = env->regs[R_EDX],
+ .Rsp = env->regs[R_ESP],
+ .Rbp = env->regs[R_EBP],
+ .Rsi = env->regs[R_ESI],
+ .Rdi = env->regs[R_EDI],
+ .R8 = env->regs[8],
+ .R9 = env->regs[9],
+ .R10 = env->regs[10],
+ .R11 = env->regs[11],
+ .R12 = env->regs[12],
+ .R13 = env->regs[13],
+ .R14 = env->regs[14],
+ .R15 = env->regs[15],
+
+ .Rip = env->eip,
+ .FltSave = {
+ .MxCsr = env->mxcsr,
+ },
+ };
+
+ if (cpu_memory_rw_debug(first_cpu, Context,
+ (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 0)) {
+ error_setg(errp, "win-dump: failed to save CPU #%d context", i);
+ return;
+ }
+
+ if (cpu_memory_rw_debug(first_cpu, Context,
+ (uint8_t *)&ctx, sizeof(WinContext), 1)) {
+ error_setg(errp, "win-dump: failed to write CPU #%d context", i);
+ return;
+ }
+
+ i++;
+ }
+}
+
+static void restore_context(WinDumpHeader64 *h,
+ struct saved_context *saved_ctx)
+{
+ int i;
+ Error *err = NULL;
+
+ for (i = 0; i < h->NumberProcessors; i++) {
+ if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr,
+ (uint8_t *)&saved_ctx[i].ctx, sizeof(WinContext), 1)) {
+ error_setg(&err, "win-dump: failed to restore CPU #%d context", i);
+ warn_report_err(err);
+ }
+ }
+}
+