]> git.proxmox.com Git - mirror_qemu.git/blame - dump.c
dump: add support for lzo/snappy
[mirror_qemu.git] / dump.c
CommitLineData
783e9b48
WC
1/*
2 * QEMU dump
3 *
4 * Copyright Fujitsu, Corp. 2011, 2012
5 *
6 * Authors:
7 * Wen Congyang <wency@cn.fujitsu.com>
8 *
352666e2
SW
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
783e9b48
WC
11 *
12 */
13
14#include "qemu-common.h"
783e9b48 15#include "elf.h"
783e9b48 16#include "cpu.h"
022c62cb
PB
17#include "exec/cpu-all.h"
18#include "exec/hwaddr.h"
83c9089e 19#include "monitor/monitor.h"
9c17d615
PB
20#include "sysemu/kvm.h"
21#include "sysemu/dump.h"
22#include "sysemu/sysemu.h"
23#include "sysemu/memory_mapping.h"
1b3509ca 24#include "sysemu/cpus.h"
7b1b5d19 25#include "qapi/error.h"
783e9b48 26#include "qmp-commands.h"
783e9b48 27
783e9b48
WC
28static uint16_t cpu_convert_to_target16(uint16_t val, int endian)
29{
30 if (endian == ELFDATA2LSB) {
31 val = cpu_to_le16(val);
32 } else {
33 val = cpu_to_be16(val);
34 }
35
36 return val;
37}
38
39static uint32_t cpu_convert_to_target32(uint32_t val, int endian)
40{
41 if (endian == ELFDATA2LSB) {
42 val = cpu_to_le32(val);
43 } else {
44 val = cpu_to_be32(val);
45 }
46
47 return val;
48}
49
50static uint64_t cpu_convert_to_target64(uint64_t val, int endian)
51{
52 if (endian == ELFDATA2LSB) {
53 val = cpu_to_le64(val);
54 } else {
55 val = cpu_to_be64(val);
56 }
57
58 return val;
59}
60
61typedef struct DumpState {
5ee163e8 62 GuestPhysBlockList guest_phys_blocks;
783e9b48
WC
63 ArchDumpInfo dump_info;
64 MemoryMappingList list;
65 uint16_t phdr_num;
66 uint32_t sh_info;
67 bool have_section;
68 bool resume;
bb6b6843 69 ssize_t note_size;
a8170e5e 70 hwaddr memory_offset;
783e9b48
WC
71 int fd;
72
56c4bfb3 73 GuestPhysBlock *next_block;
783e9b48
WC
74 ram_addr_t start;
75 bool has_filter;
76 int64_t begin;
77 int64_t length;
78 Error **errp;
4835ef77
QN
79
80 uint8_t *note_buf; /* buffer for notes */
81 size_t note_buf_offset; /* the writing place in note_buf */
783e9b48
WC
82} DumpState;
83
84static int dump_cleanup(DumpState *s)
85{
86 int ret = 0;
87
5ee163e8 88 guest_phys_blocks_free(&s->guest_phys_blocks);
783e9b48
WC
89 memory_mapping_list_free(&s->list);
90 if (s->fd != -1) {
91 close(s->fd);
92 }
93 if (s->resume) {
94 vm_start();
95 }
96
97 return ret;
98}
99
100static void dump_error(DumpState *s, const char *reason)
101{
102 dump_cleanup(s);
103}
104
b5ba1cc6 105static int fd_write_vmcore(const void *buf, size_t size, void *opaque)
783e9b48
WC
106{
107 DumpState *s = opaque;
2f61652d
LC
108 size_t written_size;
109
110 written_size = qemu_write_full(s->fd, buf, size);
111 if (written_size != size) {
112 return -1;
783e9b48
WC
113 }
114
115 return 0;
116}
117
118static int write_elf64_header(DumpState *s)
119{
120 Elf64_Ehdr elf_header;
121 int ret;
122 int endian = s->dump_info.d_endian;
123
124 memset(&elf_header, 0, sizeof(Elf64_Ehdr));
125 memcpy(&elf_header, ELFMAG, SELFMAG);
126 elf_header.e_ident[EI_CLASS] = ELFCLASS64;
127 elf_header.e_ident[EI_DATA] = s->dump_info.d_endian;
128 elf_header.e_ident[EI_VERSION] = EV_CURRENT;
129 elf_header.e_type = cpu_convert_to_target16(ET_CORE, endian);
130 elf_header.e_machine = cpu_convert_to_target16(s->dump_info.d_machine,
131 endian);
132 elf_header.e_version = cpu_convert_to_target32(EV_CURRENT, endian);
133 elf_header.e_ehsize = cpu_convert_to_target16(sizeof(elf_header), endian);
134 elf_header.e_phoff = cpu_convert_to_target64(sizeof(Elf64_Ehdr), endian);
135 elf_header.e_phentsize = cpu_convert_to_target16(sizeof(Elf64_Phdr),
136 endian);
137 elf_header.e_phnum = cpu_convert_to_target16(s->phdr_num, endian);
138 if (s->have_section) {
139 uint64_t shoff = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * s->sh_info;
140
141 elf_header.e_shoff = cpu_convert_to_target64(shoff, endian);
142 elf_header.e_shentsize = cpu_convert_to_target16(sizeof(Elf64_Shdr),
143 endian);
144 elf_header.e_shnum = cpu_convert_to_target16(1, endian);
145 }
146
147 ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
148 if (ret < 0) {
149 dump_error(s, "dump: failed to write elf header.\n");
150 return -1;
151 }
152
153 return 0;
154}
155
156static int write_elf32_header(DumpState *s)
157{
158 Elf32_Ehdr elf_header;
159 int ret;
160 int endian = s->dump_info.d_endian;
161
162 memset(&elf_header, 0, sizeof(Elf32_Ehdr));
163 memcpy(&elf_header, ELFMAG, SELFMAG);
164 elf_header.e_ident[EI_CLASS] = ELFCLASS32;
165 elf_header.e_ident[EI_DATA] = endian;
166 elf_header.e_ident[EI_VERSION] = EV_CURRENT;
167 elf_header.e_type = cpu_convert_to_target16(ET_CORE, endian);
168 elf_header.e_machine = cpu_convert_to_target16(s->dump_info.d_machine,
169 endian);
170 elf_header.e_version = cpu_convert_to_target32(EV_CURRENT, endian);
171 elf_header.e_ehsize = cpu_convert_to_target16(sizeof(elf_header), endian);
172 elf_header.e_phoff = cpu_convert_to_target32(sizeof(Elf32_Ehdr), endian);
173 elf_header.e_phentsize = cpu_convert_to_target16(sizeof(Elf32_Phdr),
174 endian);
175 elf_header.e_phnum = cpu_convert_to_target16(s->phdr_num, endian);
176 if (s->have_section) {
177 uint32_t shoff = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * s->sh_info;
178
179 elf_header.e_shoff = cpu_convert_to_target32(shoff, endian);
180 elf_header.e_shentsize = cpu_convert_to_target16(sizeof(Elf32_Shdr),
181 endian);
182 elf_header.e_shnum = cpu_convert_to_target16(1, endian);
183 }
184
185 ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
186 if (ret < 0) {
187 dump_error(s, "dump: failed to write elf header.\n");
188 return -1;
189 }
190
191 return 0;
192}
193
194static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
2cac2607
LE
195 int phdr_index, hwaddr offset,
196 hwaddr filesz)
783e9b48
WC
197{
198 Elf64_Phdr phdr;
199 int ret;
200 int endian = s->dump_info.d_endian;
201
202 memset(&phdr, 0, sizeof(Elf64_Phdr));
203 phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian);
204 phdr.p_offset = cpu_convert_to_target64(offset, endian);
205 phdr.p_paddr = cpu_convert_to_target64(memory_mapping->phys_addr, endian);
2cac2607 206 phdr.p_filesz = cpu_convert_to_target64(filesz, endian);
783e9b48
WC
207 phdr.p_memsz = cpu_convert_to_target64(memory_mapping->length, endian);
208 phdr.p_vaddr = cpu_convert_to_target64(memory_mapping->virt_addr, endian);
209
2cac2607
LE
210 assert(memory_mapping->length >= filesz);
211
783e9b48
WC
212 ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
213 if (ret < 0) {
214 dump_error(s, "dump: failed to write program header table.\n");
215 return -1;
216 }
217
218 return 0;
219}
220
221static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
2cac2607
LE
222 int phdr_index, hwaddr offset,
223 hwaddr filesz)
783e9b48
WC
224{
225 Elf32_Phdr phdr;
226 int ret;
227 int endian = s->dump_info.d_endian;
228
229 memset(&phdr, 0, sizeof(Elf32_Phdr));
230 phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian);
231 phdr.p_offset = cpu_convert_to_target32(offset, endian);
232 phdr.p_paddr = cpu_convert_to_target32(memory_mapping->phys_addr, endian);
2cac2607 233 phdr.p_filesz = cpu_convert_to_target32(filesz, endian);
783e9b48
WC
234 phdr.p_memsz = cpu_convert_to_target32(memory_mapping->length, endian);
235 phdr.p_vaddr = cpu_convert_to_target32(memory_mapping->virt_addr, endian);
236
2cac2607
LE
237 assert(memory_mapping->length >= filesz);
238
783e9b48
WC
239 ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
240 if (ret < 0) {
241 dump_error(s, "dump: failed to write program header table.\n");
242 return -1;
243 }
244
245 return 0;
246}
247
248static int write_elf64_note(DumpState *s)
249{
250 Elf64_Phdr phdr;
251 int endian = s->dump_info.d_endian;
a8170e5e 252 hwaddr begin = s->memory_offset - s->note_size;
783e9b48
WC
253 int ret;
254
255 memset(&phdr, 0, sizeof(Elf64_Phdr));
256 phdr.p_type = cpu_convert_to_target32(PT_NOTE, endian);
257 phdr.p_offset = cpu_convert_to_target64(begin, endian);
258 phdr.p_paddr = 0;
259 phdr.p_filesz = cpu_convert_to_target64(s->note_size, endian);
260 phdr.p_memsz = cpu_convert_to_target64(s->note_size, endian);
261 phdr.p_vaddr = 0;
262
263 ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
264 if (ret < 0) {
265 dump_error(s, "dump: failed to write program header table.\n");
266 return -1;
267 }
268
269 return 0;
270}
271
0bc3cd62
PB
272static inline int cpu_index(CPUState *cpu)
273{
274 return cpu->cpu_index + 1;
275}
276
6a519918 277static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s)
783e9b48 278{
0d34282f 279 CPUState *cpu;
783e9b48
WC
280 int ret;
281 int id;
282
bdc44640 283 CPU_FOREACH(cpu) {
0d34282f 284 id = cpu_index(cpu);
6a519918 285 ret = cpu_write_elf64_note(f, cpu, id, s);
783e9b48
WC
286 if (ret < 0) {
287 dump_error(s, "dump: failed to write elf notes.\n");
288 return -1;
289 }
290 }
291
bdc44640 292 CPU_FOREACH(cpu) {
6a519918 293 ret = cpu_write_elf64_qemunote(f, cpu, s);
783e9b48
WC
294 if (ret < 0) {
295 dump_error(s, "dump: failed to write CPU status.\n");
296 return -1;
297 }
298 }
299
300 return 0;
301}
302
303static int write_elf32_note(DumpState *s)
304{
a8170e5e 305 hwaddr begin = s->memory_offset - s->note_size;
783e9b48
WC
306 Elf32_Phdr phdr;
307 int endian = s->dump_info.d_endian;
308 int ret;
309
310 memset(&phdr, 0, sizeof(Elf32_Phdr));
311 phdr.p_type = cpu_convert_to_target32(PT_NOTE, endian);
312 phdr.p_offset = cpu_convert_to_target32(begin, endian);
313 phdr.p_paddr = 0;
314 phdr.p_filesz = cpu_convert_to_target32(s->note_size, endian);
315 phdr.p_memsz = cpu_convert_to_target32(s->note_size, endian);
316 phdr.p_vaddr = 0;
317
318 ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
319 if (ret < 0) {
320 dump_error(s, "dump: failed to write program header table.\n");
321 return -1;
322 }
323
324 return 0;
325}
326
6a519918 327static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s)
783e9b48 328{
0d34282f 329 CPUState *cpu;
783e9b48
WC
330 int ret;
331 int id;
332
bdc44640 333 CPU_FOREACH(cpu) {
0d34282f 334 id = cpu_index(cpu);
6a519918 335 ret = cpu_write_elf32_note(f, cpu, id, s);
783e9b48
WC
336 if (ret < 0) {
337 dump_error(s, "dump: failed to write elf notes.\n");
338 return -1;
339 }
340 }
341
bdc44640 342 CPU_FOREACH(cpu) {
6a519918 343 ret = cpu_write_elf32_qemunote(f, cpu, s);
783e9b48
WC
344 if (ret < 0) {
345 dump_error(s, "dump: failed to write CPU status.\n");
346 return -1;
347 }
348 }
349
350 return 0;
351}
352
353static int write_elf_section(DumpState *s, int type)
354{
355 Elf32_Shdr shdr32;
356 Elf64_Shdr shdr64;
357 int endian = s->dump_info.d_endian;
358 int shdr_size;
359 void *shdr;
360 int ret;
361
362 if (type == 0) {
363 shdr_size = sizeof(Elf32_Shdr);
364 memset(&shdr32, 0, shdr_size);
365 shdr32.sh_info = cpu_convert_to_target32(s->sh_info, endian);
366 shdr = &shdr32;
367 } else {
368 shdr_size = sizeof(Elf64_Shdr);
369 memset(&shdr64, 0, shdr_size);
370 shdr64.sh_info = cpu_convert_to_target32(s->sh_info, endian);
371 shdr = &shdr64;
372 }
373
374 ret = fd_write_vmcore(&shdr, shdr_size, s);
375 if (ret < 0) {
376 dump_error(s, "dump: failed to write section header table.\n");
377 return -1;
378 }
379
380 return 0;
381}
382
383static int write_data(DumpState *s, void *buf, int length)
384{
385 int ret;
386
387 ret = fd_write_vmcore(buf, length, s);
388 if (ret < 0) {
389 dump_error(s, "dump: failed to save memory.\n");
390 return -1;
391 }
392
393 return 0;
394}
395
396/* write the memroy to vmcore. 1 page per I/O. */
56c4bfb3 397static int write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start,
783e9b48
WC
398 int64_t size)
399{
400 int64_t i;
401 int ret;
402
403 for (i = 0; i < size / TARGET_PAGE_SIZE; i++) {
56c4bfb3 404 ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
783e9b48
WC
405 TARGET_PAGE_SIZE);
406 if (ret < 0) {
407 return ret;
408 }
409 }
410
411 if ((size % TARGET_PAGE_SIZE) != 0) {
56c4bfb3 412 ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
783e9b48
WC
413 size % TARGET_PAGE_SIZE);
414 if (ret < 0) {
415 return ret;
416 }
417 }
418
419 return 0;
420}
421
2cac2607
LE
422/* get the memory's offset and size in the vmcore */
423static void get_offset_range(hwaddr phys_addr,
424 ram_addr_t mapping_length,
425 DumpState *s,
426 hwaddr *p_offset,
427 hwaddr *p_filesz)
783e9b48 428{
56c4bfb3 429 GuestPhysBlock *block;
a8170e5e 430 hwaddr offset = s->memory_offset;
783e9b48
WC
431 int64_t size_in_block, start;
432
2cac2607
LE
433 /* When the memory is not stored into vmcore, offset will be -1 */
434 *p_offset = -1;
435 *p_filesz = 0;
436
783e9b48
WC
437 if (s->has_filter) {
438 if (phys_addr < s->begin || phys_addr >= s->begin + s->length) {
2cac2607 439 return;
783e9b48
WC
440 }
441 }
442
56c4bfb3 443 QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
783e9b48 444 if (s->has_filter) {
56c4bfb3
LE
445 if (block->target_start >= s->begin + s->length ||
446 block->target_end <= s->begin) {
783e9b48
WC
447 /* This block is out of the range */
448 continue;
449 }
450
56c4bfb3
LE
451 if (s->begin <= block->target_start) {
452 start = block->target_start;
783e9b48
WC
453 } else {
454 start = s->begin;
455 }
456
56c4bfb3
LE
457 size_in_block = block->target_end - start;
458 if (s->begin + s->length < block->target_end) {
459 size_in_block -= block->target_end - (s->begin + s->length);
783e9b48
WC
460 }
461 } else {
56c4bfb3
LE
462 start = block->target_start;
463 size_in_block = block->target_end - block->target_start;
783e9b48
WC
464 }
465
466 if (phys_addr >= start && phys_addr < start + size_in_block) {
2cac2607
LE
467 *p_offset = phys_addr - start + offset;
468
469 /* The offset range mapped from the vmcore file must not spill over
56c4bfb3 470 * the GuestPhysBlock, clamp it. The rest of the mapping will be
2cac2607
LE
471 * zero-filled in memory at load time; see
472 * <http://refspecs.linuxbase.org/elf/gabi4+/ch5.pheader.html>.
473 */
474 *p_filesz = phys_addr + mapping_length <= start + size_in_block ?
475 mapping_length :
476 size_in_block - (phys_addr - start);
477 return;
783e9b48
WC
478 }
479
480 offset += size_in_block;
481 }
783e9b48
WC
482}
483
484static int write_elf_loads(DumpState *s)
485{
2cac2607 486 hwaddr offset, filesz;
783e9b48
WC
487 MemoryMapping *memory_mapping;
488 uint32_t phdr_index = 1;
489 int ret;
490 uint32_t max_index;
491
492 if (s->have_section) {
493 max_index = s->sh_info;
494 } else {
495 max_index = s->phdr_num;
496 }
497
498 QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
2cac2607
LE
499 get_offset_range(memory_mapping->phys_addr,
500 memory_mapping->length,
501 s, &offset, &filesz);
783e9b48 502 if (s->dump_info.d_class == ELFCLASS64) {
2cac2607
LE
503 ret = write_elf64_load(s, memory_mapping, phdr_index++, offset,
504 filesz);
783e9b48 505 } else {
2cac2607
LE
506 ret = write_elf32_load(s, memory_mapping, phdr_index++, offset,
507 filesz);
783e9b48
WC
508 }
509
510 if (ret < 0) {
511 return -1;
512 }
513
514 if (phdr_index >= max_index) {
515 break;
516 }
517 }
518
519 return 0;
520}
521
522/* write elf header, PT_NOTE and elf note to vmcore. */
523static int dump_begin(DumpState *s)
524{
525 int ret;
526
527 /*
528 * the vmcore's format is:
529 * --------------
530 * | elf header |
531 * --------------
532 * | PT_NOTE |
533 * --------------
534 * | PT_LOAD |
535 * --------------
536 * | ...... |
537 * --------------
538 * | PT_LOAD |
539 * --------------
540 * | sec_hdr |
541 * --------------
542 * | elf note |
543 * --------------
544 * | memory |
545 * --------------
546 *
547 * we only know where the memory is saved after we write elf note into
548 * vmcore.
549 */
550
551 /* write elf header to vmcore */
552 if (s->dump_info.d_class == ELFCLASS64) {
553 ret = write_elf64_header(s);
554 } else {
555 ret = write_elf32_header(s);
556 }
557 if (ret < 0) {
558 return -1;
559 }
560
561 if (s->dump_info.d_class == ELFCLASS64) {
562 /* write PT_NOTE to vmcore */
563 if (write_elf64_note(s) < 0) {
564 return -1;
565 }
566
567 /* write all PT_LOAD to vmcore */
568 if (write_elf_loads(s) < 0) {
569 return -1;
570 }
571
572 /* write section to vmcore */
573 if (s->have_section) {
574 if (write_elf_section(s, 1) < 0) {
575 return -1;
576 }
577 }
578
579 /* write notes to vmcore */
6a519918 580 if (write_elf64_notes(fd_write_vmcore, s) < 0) {
783e9b48
WC
581 return -1;
582 }
583
584 } else {
585 /* write PT_NOTE to vmcore */
586 if (write_elf32_note(s) < 0) {
587 return -1;
588 }
589
590 /* write all PT_LOAD to vmcore */
591 if (write_elf_loads(s) < 0) {
592 return -1;
593 }
594
595 /* write section to vmcore */
596 if (s->have_section) {
597 if (write_elf_section(s, 0) < 0) {
598 return -1;
599 }
600 }
601
602 /* write notes to vmcore */
6a519918 603 if (write_elf32_notes(fd_write_vmcore, s) < 0) {
783e9b48
WC
604 return -1;
605 }
606 }
607
608 return 0;
609}
610
611/* write PT_LOAD to vmcore */
612static int dump_completed(DumpState *s)
613{
614 dump_cleanup(s);
615 return 0;
616}
617
56c4bfb3 618static int get_next_block(DumpState *s, GuestPhysBlock *block)
783e9b48
WC
619{
620 while (1) {
a3161038 621 block = QTAILQ_NEXT(block, next);
783e9b48
WC
622 if (!block) {
623 /* no more block */
624 return 1;
625 }
626
627 s->start = 0;
56c4bfb3 628 s->next_block = block;
783e9b48 629 if (s->has_filter) {
56c4bfb3
LE
630 if (block->target_start >= s->begin + s->length ||
631 block->target_end <= s->begin) {
783e9b48
WC
632 /* This block is out of the range */
633 continue;
634 }
635
56c4bfb3
LE
636 if (s->begin > block->target_start) {
637 s->start = s->begin - block->target_start;
783e9b48
WC
638 }
639 }
640
641 return 0;
642 }
643}
644
645/* write all memory to vmcore */
646static int dump_iterate(DumpState *s)
647{
56c4bfb3 648 GuestPhysBlock *block;
783e9b48
WC
649 int64_t size;
650 int ret;
651
652 while (1) {
56c4bfb3 653 block = s->next_block;
783e9b48 654
56c4bfb3 655 size = block->target_end - block->target_start;
783e9b48
WC
656 if (s->has_filter) {
657 size -= s->start;
56c4bfb3
LE
658 if (s->begin + s->length < block->target_end) {
659 size -= block->target_end - (s->begin + s->length);
783e9b48
WC
660 }
661 }
662 ret = write_memory(s, block, s->start, size);
663 if (ret == -1) {
664 return ret;
665 }
666
667 ret = get_next_block(s, block);
668 if (ret == 1) {
669 dump_completed(s);
670 return 0;
671 }
672 }
673}
674
675static int create_vmcore(DumpState *s)
676{
677 int ret;
678
679 ret = dump_begin(s);
680 if (ret < 0) {
681 return -1;
682 }
683
684 ret = dump_iterate(s);
685 if (ret < 0) {
686 return -1;
687 }
688
689 return 0;
690}
691
fda05387
QN
692static int write_start_flat_header(int fd)
693{
694 uint8_t *buf;
695 MakedumpfileHeader mh;
696 int ret = 0;
697
698 memset(&mh, 0, sizeof(mh));
699 strncpy(mh.signature, MAKEDUMPFILE_SIGNATURE,
700 strlen(MAKEDUMPFILE_SIGNATURE));
701
702 mh.type = cpu_to_be64(TYPE_FLAT_HEADER);
703 mh.version = cpu_to_be64(VERSION_FLAT_HEADER);
704
705 buf = g_malloc0(MAX_SIZE_MDF_HEADER);
706 memcpy(buf, &mh, sizeof(mh));
707
708 size_t written_size;
709 written_size = qemu_write_full(fd, buf, MAX_SIZE_MDF_HEADER);
710 if (written_size != MAX_SIZE_MDF_HEADER) {
711 ret = -1;
712 }
713
714 g_free(buf);
715 return ret;
716}
717
718static int write_end_flat_header(int fd)
719{
720 MakedumpfileDataHeader mdh;
721
722 mdh.offset = END_FLAG_FLAT_HEADER;
723 mdh.buf_size = END_FLAG_FLAT_HEADER;
724
725 size_t written_size;
726 written_size = qemu_write_full(fd, &mdh, sizeof(mdh));
727 if (written_size != sizeof(mdh)) {
728 return -1;
729 }
730
731 return 0;
732}
733
5d31babe
QN
734static int write_buffer(int fd, off_t offset, const void *buf, size_t size)
735{
736 size_t written_size;
737 MakedumpfileDataHeader mdh;
738
739 mdh.offset = cpu_to_be64(offset);
740 mdh.buf_size = cpu_to_be64(size);
741
742 written_size = qemu_write_full(fd, &mdh, sizeof(mdh));
743 if (written_size != sizeof(mdh)) {
744 return -1;
745 }
746
747 written_size = qemu_write_full(fd, buf, size);
748 if (written_size != size) {
749 return -1;
750 }
751
752 return 0;
753}
754
4835ef77
QN
755static int buf_write_note(const void *buf, size_t size, void *opaque)
756{
757 DumpState *s = opaque;
758
759 /* note_buf is not enough */
760 if (s->note_buf_offset + size > s->note_size) {
761 return -1;
762 }
763
764 memcpy(s->note_buf + s->note_buf_offset, buf, size);
765
766 s->note_buf_offset += size;
767
768 return 0;
769}
770
783e9b48
WC
771static ram_addr_t get_start_block(DumpState *s)
772{
56c4bfb3 773 GuestPhysBlock *block;
783e9b48
WC
774
775 if (!s->has_filter) {
56c4bfb3 776 s->next_block = QTAILQ_FIRST(&s->guest_phys_blocks.head);
783e9b48
WC
777 return 0;
778 }
779
56c4bfb3
LE
780 QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
781 if (block->target_start >= s->begin + s->length ||
782 block->target_end <= s->begin) {
783e9b48
WC
783 /* This block is out of the range */
784 continue;
785 }
786
56c4bfb3
LE
787 s->next_block = block;
788 if (s->begin > block->target_start) {
789 s->start = s->begin - block->target_start;
783e9b48
WC
790 } else {
791 s->start = 0;
792 }
793 return s->start;
794 }
795
796 return -1;
797}
798
799static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
800 int64_t begin, int64_t length, Error **errp)
801{
182735ef 802 CPUState *cpu;
783e9b48 803 int nr_cpus;
11ed09cf 804 Error *err = NULL;
783e9b48
WC
805 int ret;
806
807 if (runstate_is_running()) {
808 vm_stop(RUN_STATE_SAVE_VM);
809 s->resume = true;
810 } else {
811 s->resume = false;
812 }
813
5ee163e8
LE
814 /* If we use KVM, we should synchronize the registers before we get dump
815 * info or physmap info.
816 */
817 cpu_synchronize_all_states();
818 nr_cpus = 0;
bdc44640 819 CPU_FOREACH(cpu) {
5ee163e8
LE
820 nr_cpus++;
821 }
822
783e9b48
WC
823 s->errp = errp;
824 s->fd = fd;
825 s->has_filter = has_filter;
826 s->begin = begin;
827 s->length = length;
5ee163e8
LE
828
829 guest_phys_blocks_init(&s->guest_phys_blocks);
c5d7f60f 830 guest_phys_blocks_append(&s->guest_phys_blocks);
5ee163e8 831
783e9b48
WC
832 s->start = get_start_block(s);
833 if (s->start == -1) {
834 error_set(errp, QERR_INVALID_PARAMETER, "begin");
835 goto cleanup;
836 }
837
5ee163e8 838 /* get dump info: endian, class and architecture.
783e9b48
WC
839 * If the target architecture is not supported, cpu_get_dump_info() will
840 * return -1.
783e9b48 841 */
56c4bfb3 842 ret = cpu_get_dump_info(&s->dump_info, &s->guest_phys_blocks);
783e9b48
WC
843 if (ret < 0) {
844 error_set(errp, QERR_UNSUPPORTED);
845 goto cleanup;
846 }
847
4720bd05
PB
848 s->note_size = cpu_get_note_size(s->dump_info.d_class,
849 s->dump_info.d_machine, nr_cpus);
bb6b6843 850 if (s->note_size < 0) {
4720bd05
PB
851 error_set(errp, QERR_UNSUPPORTED);
852 goto cleanup;
853 }
854
783e9b48
WC
855 /* get memory mapping */
856 memory_mapping_list_init(&s->list);
857 if (paging) {
56c4bfb3 858 qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err);
11ed09cf
AF
859 if (err != NULL) {
860 error_propagate(errp, err);
861 goto cleanup;
862 }
783e9b48 863 } else {
56c4bfb3 864 qemu_get_guest_simple_memory_mapping(&s->list, &s->guest_phys_blocks);
783e9b48
WC
865 }
866
867 if (s->has_filter) {
868 memory_mapping_filter(&s->list, s->begin, s->length);
869 }
870
871 /*
872 * calculate phdr_num
873 *
874 * the type of ehdr->e_phnum is uint16_t, so we should avoid overflow
875 */
876 s->phdr_num = 1; /* PT_NOTE */
877 if (s->list.num < UINT16_MAX - 2) {
878 s->phdr_num += s->list.num;
879 s->have_section = false;
880 } else {
881 s->have_section = true;
882 s->phdr_num = PN_XNUM;
883 s->sh_info = 1; /* PT_NOTE */
884
885 /* the type of shdr->sh_info is uint32_t, so we should avoid overflow */
886 if (s->list.num <= UINT32_MAX - 1) {
887 s->sh_info += s->list.num;
888 } else {
889 s->sh_info = UINT32_MAX;
890 }
891 }
892
783e9b48
WC
893 if (s->dump_info.d_class == ELFCLASS64) {
894 if (s->have_section) {
895 s->memory_offset = sizeof(Elf64_Ehdr) +
896 sizeof(Elf64_Phdr) * s->sh_info +
897 sizeof(Elf64_Shdr) + s->note_size;
898 } else {
899 s->memory_offset = sizeof(Elf64_Ehdr) +
900 sizeof(Elf64_Phdr) * s->phdr_num + s->note_size;
901 }
902 } else {
903 if (s->have_section) {
904 s->memory_offset = sizeof(Elf32_Ehdr) +
905 sizeof(Elf32_Phdr) * s->sh_info +
906 sizeof(Elf32_Shdr) + s->note_size;
907 } else {
908 s->memory_offset = sizeof(Elf32_Ehdr) +
909 sizeof(Elf32_Phdr) * s->phdr_num + s->note_size;
910 }
911 }
912
913 return 0;
914
915cleanup:
5ee163e8
LE
916 guest_phys_blocks_free(&s->guest_phys_blocks);
917
783e9b48
WC
918 if (s->resume) {
919 vm_start();
920 }
921
922 return -1;
923}
924
925void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
926 int64_t begin, bool has_length, int64_t length,
927 Error **errp)
928{
929 const char *p;
930 int fd = -1;
931 DumpState *s;
932 int ret;
933
934 if (has_begin && !has_length) {
935 error_set(errp, QERR_MISSING_PARAMETER, "length");
936 return;
937 }
938 if (!has_begin && has_length) {
939 error_set(errp, QERR_MISSING_PARAMETER, "begin");
940 return;
941 }
942
943#if !defined(WIN32)
944 if (strstart(file, "fd:", &p)) {
a9940fc4 945 fd = monitor_get_fd(cur_mon, p, errp);
783e9b48 946 if (fd == -1) {
783e9b48
WC
947 return;
948 }
949 }
950#endif
951
952 if (strstart(file, "file:", &p)) {
953 fd = qemu_open(p, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR);
954 if (fd < 0) {
7581766b 955 error_setg_file_open(errp, errno, p);
783e9b48
WC
956 return;
957 }
958 }
959
960 if (fd == -1) {
961 error_set(errp, QERR_INVALID_PARAMETER, "protocol");
962 return;
963 }
964
5ee163e8 965 s = g_malloc0(sizeof(DumpState));
783e9b48
WC
966
967 ret = dump_init(s, fd, paging, has_begin, begin, length, errp);
968 if (ret < 0) {
969 g_free(s);
970 return;
971 }
972
973 if (create_vmcore(s) < 0 && !error_is_set(s->errp)) {
974 error_set(errp, QERR_IO_ERROR);
975 }
976
977 g_free(s);
978}