win_dump.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /*
  2. * Windows crashdump (target specific implementations)
  3. *
  4. * Copyright (c) 2018 Virtuozzo International GmbH
  5. *
  6. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  7. * See the COPYING file in the top-level directory.
  8. *
  9. */
  10. #include "qemu/osdep.h"
  11. #include "system/dump.h"
  12. #include "qapi/error.h"
  13. #include "qemu/error-report.h"
  14. #include "exec/cpu-defs.h"
  15. #include "hw/core/cpu.h"
  16. #include "qemu/win_dump_defs.h"
  17. #include "win_dump.h"
  18. #include "cpu.h"
  19. #if defined(TARGET_X86_64)
  20. bool win_dump_available(Error **errp)
  21. {
  22. return true;
  23. }
  24. static size_t win_dump_ptr_size(bool x64)
  25. {
  26. return x64 ? sizeof(uint64_t) : sizeof(uint32_t);
  27. }
  28. #define _WIN_DUMP_FIELD(f) (x64 ? h->x64.f : h->x32.f)
  29. #define WIN_DUMP_FIELD(field) _WIN_DUMP_FIELD(field)
  30. #define _WIN_DUMP_FIELD_PTR(f) (x64 ? (void *)&h->x64.f : (void *)&h->x32.f)
  31. #define WIN_DUMP_FIELD_PTR(field) _WIN_DUMP_FIELD_PTR(field)
  32. #define _WIN_DUMP_FIELD_SIZE(f) (x64 ? sizeof(h->x64.f) : sizeof(h->x32.f))
  33. #define WIN_DUMP_FIELD_SIZE(field) _WIN_DUMP_FIELD_SIZE(field)
  34. static size_t win_dump_ctx_size(bool x64)
  35. {
  36. return x64 ? sizeof(WinContext64) : sizeof(WinContext32);
  37. }
  38. static size_t write_run(uint64_t base_page, uint64_t page_count,
  39. int fd, Error **errp)
  40. {
  41. void *buf;
  42. uint64_t addr = base_page << TARGET_PAGE_BITS;
  43. uint64_t size = page_count << TARGET_PAGE_BITS;
  44. uint64_t len, l;
  45. int eno;
  46. size_t total = 0;
  47. while (size) {
  48. len = size;
  49. buf = cpu_physical_memory_map(addr, &len, false);
  50. if (!buf) {
  51. error_setg(errp, "win-dump: failed to map physical range"
  52. " 0x%016" PRIx64 "-0x%016" PRIx64, addr, addr + size - 1);
  53. return 0;
  54. }
  55. l = qemu_write_full(fd, buf, len);
  56. eno = errno;
  57. cpu_physical_memory_unmap(buf, addr, false, len);
  58. if (l != len) {
  59. error_setg_errno(errp, eno, "win-dump: failed to save memory");
  60. return 0;
  61. }
  62. addr += l;
  63. size -= l;
  64. total += l;
  65. }
  66. return total;
  67. }
  68. static void write_runs(DumpState *s, WinDumpHeader *h, bool x64, Error **errp)
  69. {
  70. uint64_t BasePage, PageCount;
  71. Error *local_err = NULL;
  72. int i;
  73. for (i = 0; i < WIN_DUMP_FIELD(PhysicalMemoryBlock.NumberOfRuns); i++) {
  74. BasePage = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].BasePage);
  75. PageCount = WIN_DUMP_FIELD(PhysicalMemoryBlock.Run[i].PageCount);
  76. s->written_size += write_run(BasePage, PageCount, s->fd, &local_err);
  77. if (local_err) {
  78. error_propagate(errp, local_err);
  79. return;
  80. }
  81. }
  82. }
  83. static int cpu_read_ptr(bool x64, CPUState *cpu, uint64_t addr, uint64_t *ptr)
  84. {
  85. int ret;
  86. uint32_t ptr32;
  87. uint64_t ptr64;
  88. ret = cpu_memory_rw_debug(cpu, addr, x64 ? (void *)&ptr64 : (void *)&ptr32,
  89. win_dump_ptr_size(x64), 0);
  90. *ptr = x64 ? ptr64 : ptr32;
  91. return ret;
  92. }
  93. static void patch_mm_pfn_database(WinDumpHeader *h, bool x64, Error **errp)
  94. {
  95. if (cpu_memory_rw_debug(first_cpu,
  96. WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_MM_PFN_DATABASE_OFFSET,
  97. WIN_DUMP_FIELD_PTR(PfnDatabase),
  98. WIN_DUMP_FIELD_SIZE(PfnDatabase), 0)) {
  99. error_setg(errp, "win-dump: failed to read MmPfnDatabase");
  100. return;
  101. }
  102. }
  103. static void patch_bugcheck_data(WinDumpHeader *h, bool x64, Error **errp)
  104. {
  105. uint64_t KiBugcheckData;
  106. if (cpu_read_ptr(x64, first_cpu,
  107. WIN_DUMP_FIELD(KdDebuggerDataBlock) + KDBG_KI_BUGCHECK_DATA_OFFSET,
  108. &KiBugcheckData)) {
  109. error_setg(errp, "win-dump: failed to read KiBugcheckData");
  110. return;
  111. }
  112. if (cpu_memory_rw_debug(first_cpu, KiBugcheckData,
  113. WIN_DUMP_FIELD(BugcheckData),
  114. WIN_DUMP_FIELD_SIZE(BugcheckData), 0)) {
  115. error_setg(errp, "win-dump: failed to read bugcheck data");
  116. return;
  117. }
  118. /*
  119. * If BugcheckCode wasn't saved, we consider guest OS as alive.
  120. */
  121. if (!WIN_DUMP_FIELD(BugcheckCode)) {
  122. *(uint32_t *)WIN_DUMP_FIELD_PTR(BugcheckCode) = LIVE_SYSTEM_DUMP;
  123. }
  124. }
  125. /*
  126. * This routine tries to correct mistakes in crashdump header.
  127. */
  128. static void patch_header(WinDumpHeader *h, bool x64)
  129. {
  130. Error *local_err = NULL;
  131. if (x64) {
  132. h->x64.RequiredDumpSpace = sizeof(WinDumpHeader64) +
  133. (h->x64.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
  134. h->x64.PhysicalMemoryBlock.unused = 0;
  135. h->x64.unused1 = 0;
  136. } else {
  137. h->x32.RequiredDumpSpace = sizeof(WinDumpHeader32) +
  138. (h->x32.PhysicalMemoryBlock.NumberOfPages << TARGET_PAGE_BITS);
  139. }
  140. patch_mm_pfn_database(h, x64, &local_err);
  141. if (local_err) {
  142. warn_report_err(local_err);
  143. local_err = NULL;
  144. }
  145. patch_bugcheck_data(h, x64, &local_err);
  146. if (local_err) {
  147. warn_report_err(local_err);
  148. }
  149. }
  150. static bool check_header(WinDumpHeader *h, bool *x64, Error **errp)
  151. {
  152. const char Signature[] = "PAGE";
  153. if (memcmp(h->Signature, Signature, sizeof(h->Signature))) {
  154. error_setg(errp, "win-dump: invalid header, expected '%.4s',"
  155. " got '%.4s'", Signature, h->Signature);
  156. return false;
  157. }
  158. if (!memcmp(h->ValidDump, "DUMP", sizeof(h->ValidDump))) {
  159. *x64 = false;
  160. } else if (!memcmp(h->ValidDump, "DU64", sizeof(h->ValidDump))) {
  161. *x64 = true;
  162. } else {
  163. error_setg(errp, "win-dump: invalid header, expected 'DUMP' or 'DU64',"
  164. " got '%.4s'", h->ValidDump);
  165. return false;
  166. }
  167. return true;
  168. }
  169. static void check_kdbg(WinDumpHeader *h, bool x64, Error **errp)
  170. {
  171. const char OwnerTag[] = "KDBG";
  172. char read_OwnerTag[4];
  173. uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock);
  174. bool try_fallback = true;
  175. try_again:
  176. if (cpu_memory_rw_debug(first_cpu,
  177. KdDebuggerDataBlock + KDBG_OWNER_TAG_OFFSET,
  178. (uint8_t *)&read_OwnerTag, sizeof(read_OwnerTag), 0)) {
  179. error_setg(errp, "win-dump: failed to read OwnerTag");
  180. return;
  181. }
  182. if (memcmp(read_OwnerTag, OwnerTag, sizeof(read_OwnerTag))) {
  183. if (try_fallback) {
  184. /*
  185. * If attempt to use original KDBG failed
  186. * (most likely because of its encryption),
  187. * we try to use KDBG obtained by guest driver.
  188. */
  189. KdDebuggerDataBlock = WIN_DUMP_FIELD(BugcheckParameter1);
  190. try_fallback = false;
  191. goto try_again;
  192. } else {
  193. error_setg(errp, "win-dump: invalid KDBG OwnerTag,"
  194. " expected '%.4s', got '%.4s'",
  195. OwnerTag, read_OwnerTag);
  196. return;
  197. }
  198. }
  199. if (x64) {
  200. h->x64.KdDebuggerDataBlock = KdDebuggerDataBlock;
  201. } else {
  202. h->x32.KdDebuggerDataBlock = KdDebuggerDataBlock;
  203. }
  204. }
  205. struct saved_context {
  206. WinContext ctx;
  207. uint64_t addr;
  208. };
  209. static void patch_and_save_context(WinDumpHeader *h, bool x64,
  210. struct saved_context *saved_ctx,
  211. Error **errp)
  212. {
  213. uint64_t KdDebuggerDataBlock = WIN_DUMP_FIELD(KdDebuggerDataBlock);
  214. uint64_t KiProcessorBlock;
  215. uint16_t OffsetPrcbContext;
  216. CPUState *cpu;
  217. int i = 0;
  218. if (cpu_read_ptr(x64, first_cpu,
  219. KdDebuggerDataBlock + KDBG_KI_PROCESSOR_BLOCK_OFFSET,
  220. &KiProcessorBlock)) {
  221. error_setg(errp, "win-dump: failed to read KiProcessorBlock");
  222. return;
  223. }
  224. if (cpu_memory_rw_debug(first_cpu,
  225. KdDebuggerDataBlock + KDBG_OFFSET_PRCB_CONTEXT_OFFSET,
  226. (uint8_t *)&OffsetPrcbContext, sizeof(OffsetPrcbContext), 0)) {
  227. error_setg(errp, "win-dump: failed to read OffsetPrcbContext");
  228. return;
  229. }
  230. CPU_FOREACH(cpu) {
  231. X86CPU *x86_cpu = X86_CPU(cpu);
  232. CPUX86State *env = &x86_cpu->env;
  233. uint64_t Prcb;
  234. uint64_t Context;
  235. WinContext ctx;
  236. if (i >= WIN_DUMP_FIELD(NumberProcessors)) {
  237. warn_report("win-dump: number of QEMU CPUs is bigger than"
  238. " NumberProcessors (%u) in guest Windows",
  239. WIN_DUMP_FIELD(NumberProcessors));
  240. return;
  241. }
  242. if (cpu_read_ptr(x64, first_cpu,
  243. KiProcessorBlock + i * win_dump_ptr_size(x64),
  244. &Prcb)) {
  245. error_setg(errp, "win-dump: failed to read"
  246. " CPU #%d PRCB location", i);
  247. return;
  248. }
  249. if (cpu_read_ptr(x64, first_cpu,
  250. Prcb + OffsetPrcbContext,
  251. &Context)) {
  252. error_setg(errp, "win-dump: failed to read"
  253. " CPU #%d ContextFrame location", i);
  254. return;
  255. }
  256. saved_ctx[i].addr = Context;
  257. if (x64) {
  258. ctx.x64 = (WinContext64){
  259. .ContextFlags = WIN_CTX64_ALL,
  260. .MxCsr = env->mxcsr,
  261. .SegEs = env->segs[0].selector,
  262. .SegCs = env->segs[1].selector,
  263. .SegSs = env->segs[2].selector,
  264. .SegDs = env->segs[3].selector,
  265. .SegFs = env->segs[4].selector,
  266. .SegGs = env->segs[5].selector,
  267. .EFlags = cpu_compute_eflags(env),
  268. .Dr0 = env->dr[0],
  269. .Dr1 = env->dr[1],
  270. .Dr2 = env->dr[2],
  271. .Dr3 = env->dr[3],
  272. .Dr6 = env->dr[6],
  273. .Dr7 = env->dr[7],
  274. .Rax = env->regs[R_EAX],
  275. .Rbx = env->regs[R_EBX],
  276. .Rcx = env->regs[R_ECX],
  277. .Rdx = env->regs[R_EDX],
  278. .Rsp = env->regs[R_ESP],
  279. .Rbp = env->regs[R_EBP],
  280. .Rsi = env->regs[R_ESI],
  281. .Rdi = env->regs[R_EDI],
  282. .R8 = env->regs[8],
  283. .R9 = env->regs[9],
  284. .R10 = env->regs[10],
  285. .R11 = env->regs[11],
  286. .R12 = env->regs[12],
  287. .R13 = env->regs[13],
  288. .R14 = env->regs[14],
  289. .R15 = env->regs[15],
  290. .Rip = env->eip,
  291. .FltSave = {
  292. .MxCsr = env->mxcsr,
  293. },
  294. };
  295. } else {
  296. ctx.x32 = (WinContext32){
  297. .ContextFlags = WIN_CTX32_FULL | WIN_CTX_DBG,
  298. .SegEs = env->segs[0].selector,
  299. .SegCs = env->segs[1].selector,
  300. .SegSs = env->segs[2].selector,
  301. .SegDs = env->segs[3].selector,
  302. .SegFs = env->segs[4].selector,
  303. .SegGs = env->segs[5].selector,
  304. .EFlags = cpu_compute_eflags(env),
  305. .Dr0 = env->dr[0],
  306. .Dr1 = env->dr[1],
  307. .Dr2 = env->dr[2],
  308. .Dr3 = env->dr[3],
  309. .Dr6 = env->dr[6],
  310. .Dr7 = env->dr[7],
  311. .Eax = env->regs[R_EAX],
  312. .Ebx = env->regs[R_EBX],
  313. .Ecx = env->regs[R_ECX],
  314. .Edx = env->regs[R_EDX],
  315. .Esp = env->regs[R_ESP],
  316. .Ebp = env->regs[R_EBP],
  317. .Esi = env->regs[R_ESI],
  318. .Edi = env->regs[R_EDI],
  319. .Eip = env->eip,
  320. };
  321. }
  322. if (cpu_memory_rw_debug(first_cpu, Context,
  323. &saved_ctx[i].ctx, win_dump_ctx_size(x64), 0)) {
  324. error_setg(errp, "win-dump: failed to save CPU #%d context", i);
  325. return;
  326. }
  327. if (cpu_memory_rw_debug(first_cpu, Context,
  328. &ctx, win_dump_ctx_size(x64), 1)) {
  329. error_setg(errp, "win-dump: failed to write CPU #%d context", i);
  330. return;
  331. }
  332. i++;
  333. }
  334. }
  335. static void restore_context(WinDumpHeader *h, bool x64,
  336. struct saved_context *saved_ctx)
  337. {
  338. int i;
  339. for (i = 0; i < WIN_DUMP_FIELD(NumberProcessors); i++) {
  340. if (cpu_memory_rw_debug(first_cpu, saved_ctx[i].addr,
  341. &saved_ctx[i].ctx, win_dump_ctx_size(x64), 1)) {
  342. warn_report("win-dump: failed to restore CPU #%d context", i);
  343. }
  344. }
  345. }
  346. void create_win_dump(DumpState *s, Error **errp)
  347. {
  348. WinDumpHeader *h = (void *)(s->guest_note + VMCOREINFO_ELF_NOTE_HDR_SIZE);
  349. X86CPU *first_x86_cpu = X86_CPU(first_cpu);
  350. uint64_t saved_cr3 = first_x86_cpu->env.cr[3];
  351. struct saved_context *saved_ctx = NULL;
  352. Error *local_err = NULL;
  353. bool x64 = true;
  354. size_t hdr_size;
  355. if (s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE32 &&
  356. s->guest_note_size != VMCOREINFO_WIN_DUMP_NOTE_SIZE64) {
  357. error_setg(errp, "win-dump: invalid vmcoreinfo note size");
  358. return;
  359. }
  360. if (!check_header(h, &x64, &local_err)) {
  361. error_propagate(errp, local_err);
  362. return;
  363. }
  364. hdr_size = x64 ? sizeof(WinDumpHeader64) : sizeof(WinDumpHeader32);
  365. /*
  366. * Further access to kernel structures by virtual addresses
  367. * should be made from system context.
  368. */
  369. first_x86_cpu->env.cr[3] = WIN_DUMP_FIELD(DirectoryTableBase);
  370. check_kdbg(h, x64, &local_err);
  371. if (local_err) {
  372. error_propagate(errp, local_err);
  373. goto out_cr3;
  374. }
  375. patch_header(h, x64);
  376. saved_ctx = g_new(struct saved_context, WIN_DUMP_FIELD(NumberProcessors));
  377. /*
  378. * Always patch context because there is no way
  379. * to determine if the system-saved context is valid
  380. */
  381. patch_and_save_context(h, x64, saved_ctx, &local_err);
  382. if (local_err) {
  383. error_propagate(errp, local_err);
  384. goto out_free;
  385. }
  386. s->total_size = WIN_DUMP_FIELD(RequiredDumpSpace);
  387. s->written_size = qemu_write_full(s->fd, h, hdr_size);
  388. if (s->written_size != hdr_size) {
  389. error_setg_errno(errp, errno, "win-dump: failed to write header");
  390. goto out_restore;
  391. }
  392. write_runs(s, h, x64, &local_err);
  393. if (local_err) {
  394. error_propagate(errp, local_err);
  395. goto out_restore;
  396. }
  397. out_restore:
  398. restore_context(h, x64, saved_ctx);
  399. out_free:
  400. g_free(saved_ctx);
  401. out_cr3:
  402. first_x86_cpu->env.cr[3] = saved_cr3;
  403. return;
  404. }
  405. #else /* !TARGET_X86_64 */
  406. bool win_dump_available(Error **errp)
  407. {
  408. error_setg(errp, "Windows dump is only available for x86-64");
  409. return false;
  410. }
  411. void create_win_dump(DumpState *s, Error **errp)
  412. {
  413. win_dump_available(errp);
  414. }
  415. #endif