1 /*
2 * Elf format, (pfn, gmfn) table, IA64 support.
3 * Copyright (c) 2007 Isaku Yamahata <yamahata at valinux co jp>
4 * VA Linux Systems Japan K.K.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation;
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
21 * xen dump-core file format follows ELF format specification.
22 * Analisys tools shouldn't depends on the order of sections.
23 * They should follow elf header and check section names.
24 *
25 * +--------------------------------------------------------+
26 * |ELF header |
27 * +--------------------------------------------------------+
28 * |section headers |
29 * | null section header |
30 * | .shstrtab |
31 * | .note.Xen |
32 * | .xen_prstatus |
33 * | .xen_shared_info if present |
34 * | .xen_pages |
35 * | .xen_p2m or .xen_pfn |
36 * +--------------------------------------------------------+
37 * |.note.Xen:note section |
38 * | "Xen" is used as note name, |
39 * | types are defined in xen/include/public/elfnote.h |
40 * | and descriptors are defined in xc_core.h. |
41 * | dumpcore none |
42 * | dumpcore header |
43 * | dumpcore xen version |
44 * | dumpcore format version |
45 * +--------------------------------------------------------+
46 * |.xen_prstatus |
47 * | vcpu_guest_context_t[nr_vcpus] |
48 * +--------------------------------------------------------+
49 * |.xen_shared_info if possible |
50 * +--------------------------------------------------------+
51 * |.xen_pages |
52 * | page * nr_pages |
53 * +--------------------------------------------------------+
54 * |.xen_p2m or .xen_pfn |
55 * | .xen_p2m: struct xen_dumpcore_p2m[nr_pages] |
56 * | .xen_pfn: uint64_t[nr_pages] |
57 * +--------------------------------------------------------+
58 * |.shstrtab: section header string table |
59 * +--------------------------------------------------------+
60 *
61 */
62
63 #include "xc_private.h"
64 #include "xg_core.h"
65 #include <stdlib.h>
66 #include <unistd.h>
67
68 #include <xen/libelf/libelf.h>
69
70 /* number of pages to write at a time */
71 #define DUMP_INCREMENT (4 * 1024)
72
73 /* string table */
74 struct xc_core_strtab {
75 char *strings;
76 uint16_t length;
77 uint16_t max;
78 };
79
80 static struct xc_core_strtab*
xc_core_strtab_init(xc_interface * xch)81 xc_core_strtab_init(xc_interface *xch)
82 {
83 struct xc_core_strtab *strtab;
84 char *strings;
85 strtab = malloc(sizeof(*strtab));
86 if ( strtab == NULL )
87 return NULL;
88
89 strings = malloc(PAGE_SIZE);
90 if ( strings == NULL )
91 {
92 PERROR("Could not allocate string table init");
93 free(strtab);
94 return NULL;
95 }
96 strtab->strings = strings;
97 strtab->max = PAGE_SIZE;
98
99 /* index 0 represents none */
100 strtab->strings[0] = '\0';
101 strtab->length = 1;
102
103 return strtab;
104 }
105
106 static void
xc_core_strtab_free(struct xc_core_strtab * strtab)107 xc_core_strtab_free(struct xc_core_strtab *strtab)
108 {
109 free(strtab->strings);
110 free(strtab);
111 }
112
113 static uint16_t
xc_core_strtab_get(xc_interface * xch,struct xc_core_strtab * strtab,const char * name)114 xc_core_strtab_get(xc_interface *xch, struct xc_core_strtab *strtab, const char *name)
115 {
116 uint16_t ret = 0;
117 uint16_t len = strlen(name) + 1;
118
119 if ( strtab->length > UINT16_MAX - len )
120 {
121 PERROR("too long string table");
122 errno = E2BIG;
123 return ret;
124 }
125
126 if ( strtab->length + len > strtab->max )
127 {
128 char *tmp;
129 if ( strtab->max > UINT16_MAX / 2 )
130 {
131 PERROR("too long string table");
132 errno = ENOMEM;
133 return ret;
134 }
135
136 tmp = realloc(strtab->strings, strtab->max * 2);
137 if ( tmp == NULL )
138 {
139 PERROR("Could not allocate string table");
140 return ret;
141 }
142
143 strtab->strings = tmp;
144 strtab->max *= 2;
145 }
146
147 ret = strtab->length;
148 strcpy(strtab->strings + strtab->length, name);
149 strtab->length += len;
150 return ret;
151 }
152
153
154 /* section headers */
155 struct xc_core_section_headers {
156 uint16_t num;
157 uint16_t num_max;
158
159 Elf64_Shdr *shdrs;
160 };
161 #define SHDR_INIT ((uint16_t)16)
162 #define SHDR_INC ((uint16_t)4)
163
164 static struct xc_core_section_headers*
xc_core_shdr_init(xc_interface * xch)165 xc_core_shdr_init(xc_interface *xch)
166 {
167 struct xc_core_section_headers *sheaders;
168 sheaders = malloc(sizeof(*sheaders));
169 if ( sheaders == NULL )
170 return NULL;
171
172 sheaders->num = 0;
173 sheaders->num_max = SHDR_INIT;
174 sheaders->shdrs = malloc(sizeof(sheaders->shdrs[0]) * sheaders->num_max);
175 if ( sheaders->shdrs == NULL )
176 {
177 free(sheaders);
178 return NULL;
179 }
180 return sheaders;
181 }
182
183 static void
xc_core_shdr_free(struct xc_core_section_headers * sheaders)184 xc_core_shdr_free(struct xc_core_section_headers *sheaders)
185 {
186 free(sheaders->shdrs);
187 free(sheaders);
188 }
189
190 Elf64_Shdr*
xc_core_shdr_get(xc_interface * xch,struct xc_core_section_headers * sheaders)191 xc_core_shdr_get(xc_interface *xch,
192 struct xc_core_section_headers *sheaders)
193 {
194 Elf64_Shdr *shdr;
195
196 if ( sheaders->num == sheaders->num_max )
197 {
198 Elf64_Shdr *shdrs;
199 if ( sheaders->num_max > UINT16_MAX - SHDR_INC )
200 {
201 errno = E2BIG;
202 return NULL;
203 }
204 sheaders->num_max += SHDR_INC;
205 shdrs = realloc(sheaders->shdrs,
206 sizeof(sheaders->shdrs[0]) * sheaders->num_max);
207 if ( shdrs == NULL )
208 return NULL;
209 sheaders->shdrs = shdrs;
210 }
211
212 shdr = &sheaders->shdrs[sheaders->num];
213 sheaders->num++;
214 memset(shdr, 0, sizeof(*shdr));
215 return shdr;
216 }
217
218 int
xc_core_shdr_set(xc_interface * xch,Elf64_Shdr * shdr,struct xc_core_strtab * strtab,const char * name,uint32_t type,uint64_t offset,uint64_t size,uint64_t addralign,uint64_t entsize)219 xc_core_shdr_set(xc_interface *xch,
220 Elf64_Shdr *shdr,
221 struct xc_core_strtab *strtab,
222 const char *name, uint32_t type,
223 uint64_t offset, uint64_t size,
224 uint64_t addralign, uint64_t entsize)
225 {
226 uint64_t name_idx = xc_core_strtab_get(xch, strtab, name);
227 if ( name_idx == 0 )
228 return -1;
229
230 shdr->sh_name = name_idx;
231 shdr->sh_type = type;
232 shdr->sh_offset = offset;
233 shdr->sh_size = size;
234 shdr->sh_addralign = addralign;
235 shdr->sh_entsize = entsize;
236 return 0;
237 }
238
239 static void
xc_core_ehdr_init(Elf64_Ehdr * ehdr)240 xc_core_ehdr_init(Elf64_Ehdr *ehdr)
241 {
242 memset(ehdr, 0, sizeof(*ehdr));
243 ehdr->e_ident[EI_MAG0] = ELFMAG0;
244 ehdr->e_ident[EI_MAG1] = ELFMAG1;
245 ehdr->e_ident[EI_MAG2] = ELFMAG2;
246 ehdr->e_ident[EI_MAG3] = ELFMAG3;
247 ehdr->e_ident[EI_CLASS] = ELFCLASS64;
248 ehdr->e_ident[EI_DATA] = ELF_ARCH_DATA;
249 ehdr->e_ident[EI_VERSION] = EV_CURRENT;
250 ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
251 ehdr->e_ident[EI_ABIVERSION] = EV_CURRENT;
252
253 ehdr->e_type = ET_CORE;
254 /* e_machine will be filled in later */
255 ehdr->e_version = EV_CURRENT;
256 ehdr->e_entry = 0;
257 ehdr->e_phoff = 0;
258 ehdr->e_shoff = sizeof(*ehdr);
259 ehdr->e_flags = ELF_CORE_EFLAGS;
260 ehdr->e_ehsize = sizeof(*ehdr);
261 ehdr->e_phentsize = sizeof(Elf64_Phdr);
262 ehdr->e_phnum = 0;
263 ehdr->e_shentsize = sizeof(Elf64_Shdr);
264 /* ehdr->e_shnum and ehdr->e_shstrndx aren't known here yet.
265 * fill it later */
266 }
267
268 static int
elfnote_fill_xen_version(xc_interface * xch,struct xen_dumpcore_elfnote_xen_version_desc * xen_version)269 elfnote_fill_xen_version(xc_interface *xch,
270 struct xen_dumpcore_elfnote_xen_version_desc
271 *xen_version)
272 {
273 int rc;
274 memset(xen_version, 0, sizeof(*xen_version));
275
276 rc = xc_version(xch, XENVER_version, NULL);
277 if ( rc < 0 )
278 return rc;
279 xen_version->major_version = rc >> 16;
280 xen_version->minor_version = rc & ((1 << 16) - 1);
281
282 rc = xc_version(xch, XENVER_extraversion,
283 &xen_version->extra_version);
284 if ( rc < 0 )
285 return rc;
286
287 rc = xc_version(xch, XENVER_compile_info,
288 &xen_version->compile_info);
289 if ( rc < 0 )
290 return rc;
291
292 rc = xc_version(xch,
293 XENVER_capabilities, &xen_version->capabilities);
294 if ( rc < 0 )
295 return rc;
296
297 rc = xc_version(xch, XENVER_changeset, &xen_version->changeset);
298 if ( rc < 0 )
299 return rc;
300
301 rc = xc_version(xch, XENVER_platform_parameters,
302 &xen_version->platform_parameters);
303 if ( rc < 0 )
304 return rc;
305
306 rc = xc_version(xch, XENVER_pagesize, NULL);
307 if ( rc < 0 )
308 return rc;
309 xen_version->pagesize = rc;
310
311 return 0;
312 }
313
314 static void
elfnote_fill_format_version(struct xen_dumpcore_elfnote_format_version_desc * format_version)315 elfnote_fill_format_version(struct xen_dumpcore_elfnote_format_version_desc
316 *format_version)
317 {
318 format_version->version = XEN_DUMPCORE_FORMAT_VERSION_CURRENT;
319 }
320
321 static void
elfnote_init(struct elfnote * elfnote)322 elfnote_init(struct elfnote *elfnote)
323 {
324 /* elf note section */
325 memset(elfnote, 0, sizeof(*elfnote));
326 elfnote->namesz = strlen(XEN_DUMPCORE_ELFNOTE_NAME) + 1;
327 strncpy(elfnote->name, XEN_DUMPCORE_ELFNOTE_NAME, sizeof(elfnote->name));
328 }
329
330 static int
elfnote_dump_none(xc_interface * xch,void * args,dumpcore_rtn_t dump_rtn)331 elfnote_dump_none(xc_interface *xch, void *args, dumpcore_rtn_t dump_rtn)
332 {
333 int sts;
334 struct elfnote elfnote;
335 struct xen_dumpcore_elfnote_none_desc none;
336
337 elfnote_init(&elfnote);
338 /* Avoid compile warning about constant-zero-sized memset(). */
339 /*memset(&none, 0, sizeof(none));*/
340
341 elfnote.descsz = sizeof(none);
342 elfnote.type = XEN_ELFNOTE_DUMPCORE_NONE;
343 sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote));
344 if ( sts != 0 )
345 return sts;
346 return dump_rtn(xch, args, (char*)&none, sizeof(none));
347 }
348
349 static int
elfnote_dump_core_header(xc_interface * xch,void * args,dumpcore_rtn_t dump_rtn,const xc_domaininfo_t * info,int nr_vcpus,unsigned long nr_pages)350 elfnote_dump_core_header(
351 xc_interface *xch,
352 void *args, dumpcore_rtn_t dump_rtn, const xc_domaininfo_t *info,
353 int nr_vcpus, unsigned long nr_pages)
354 {
355 int sts;
356 struct elfnote elfnote;
357 struct xen_dumpcore_elfnote_header_desc header;
358
359 elfnote_init(&elfnote);
360 memset(&header, 0, sizeof(header));
361
362 elfnote.descsz = sizeof(header);
363 elfnote.type = XEN_ELFNOTE_DUMPCORE_HEADER;
364 header.xch_magic = (info->flags & XEN_DOMINF_hvm_guest) ? XC_CORE_MAGIC_HVM
365 : XC_CORE_MAGIC;
366 header.xch_nr_vcpus = nr_vcpus;
367 header.xch_nr_pages = nr_pages;
368 header.xch_page_size = PAGE_SIZE;
369 sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote));
370 if ( sts != 0 )
371 return sts;
372 return dump_rtn(xch, args, (char*)&header, sizeof(header));
373 }
374
375 static int
elfnote_dump_xen_version(xc_interface * xch,void * args,dumpcore_rtn_t dump_rtn,unsigned int guest_width)376 elfnote_dump_xen_version(xc_interface *xch, void *args,
377 dumpcore_rtn_t dump_rtn, unsigned int guest_width)
378 {
379 int sts;
380 struct elfnote elfnote;
381 struct xen_dumpcore_elfnote_xen_version_desc xen_version;
382
383 elfnote_init(&elfnote);
384 memset(&xen_version, 0, sizeof(xen_version));
385
386 elfnote.descsz = sizeof(xen_version);
387 elfnote.type = XEN_ELFNOTE_DUMPCORE_XEN_VERSION;
388 elfnote_fill_xen_version(xch, &xen_version);
389 if (guest_width < sizeof(unsigned long))
390 {
391 // 32 bit elf file format differs in pagesize's alignment
392 char *p = (char *)&xen_version.pagesize;
393 memmove(p - 4, p, sizeof(xen_version.pagesize));
394 }
395 sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote));
396 if ( sts != 0 )
397 return sts;
398 return dump_rtn(xch, args, (char*)&xen_version, sizeof(xen_version));
399 }
400
401 static int
elfnote_dump_format_version(xc_interface * xch,void * args,dumpcore_rtn_t dump_rtn)402 elfnote_dump_format_version(xc_interface *xch,
403 void *args, dumpcore_rtn_t dump_rtn)
404 {
405 int sts;
406 struct elfnote elfnote;
407 struct xen_dumpcore_elfnote_format_version_desc format_version;
408
409 elfnote_init(&elfnote);
410 memset(&format_version, 0, sizeof(format_version));
411
412 elfnote.descsz = sizeof(format_version);
413 elfnote.type = XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION;
414 elfnote_fill_format_version(&format_version);
415 sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote));
416 if ( sts != 0 )
417 return sts;
418 return dump_rtn(xch, args, (char*)&format_version, sizeof(format_version));
419 }
420
421 int
xc_domain_dumpcore_via_callback(xc_interface * xch,uint32_t domid,void * args,dumpcore_rtn_t dump_rtn)422 xc_domain_dumpcore_via_callback(xc_interface *xch,
423 uint32_t domid,
424 void *args,
425 dumpcore_rtn_t dump_rtn)
426 {
427 xc_domaininfo_t info;
428 shared_info_any_t *live_shinfo = NULL;
429 struct domain_info_context _dinfo = {};
430 struct domain_info_context *dinfo = &_dinfo;
431
432 int nr_vcpus = 0;
433 char *dump_mem, *dump_mem_start = NULL;
434 vcpu_guest_context_any_t *ctxt = NULL;
435 struct xc_core_arch_context arch_ctxt;
436 char dummy[PAGE_SIZE];
437 int dummy_len;
438 int sts = -1;
439
440 unsigned long i;
441 unsigned long j;
442 unsigned long nr_pages;
443 unsigned long max_mfn;
444
445 xc_core_memory_map_t *memory_map = NULL;
446 unsigned int nr_memory_map;
447 unsigned int map_idx;
448
449 int auto_translated_physmap;
450 xen_pfn_t *p2m = NULL;
451 struct xen_dumpcore_p2m *p2m_array = NULL;
452
453 uint64_t *pfn_array = NULL;
454
455 Elf64_Ehdr ehdr;
456 uint64_t filesz;
457 uint64_t offset;
458 uint64_t fixup;
459
460 struct xc_core_strtab *strtab = NULL;
461 uint16_t strtab_idx;
462 struct xc_core_section_headers *sheaders = NULL;
463 Elf64_Shdr *shdr;
464
465 xc_core_arch_context_init(&arch_ctxt);
466 if ( (dump_mem_start = malloc(DUMP_INCREMENT*PAGE_SIZE)) == NULL )
467 {
468 PERROR("Could not allocate dump_mem");
469 goto out;
470 }
471
472 if ( xc_domain_getinfo_single(xch, domid, &info) < 0 )
473 {
474 PERROR("Could not get info for dom%u", domid);
475 goto out;
476 }
477 /* Map the shared info frame */
478 live_shinfo = xc_map_foreign_range(xch, domid, PAGE_SIZE,
479 PROT_READ, info.shared_info_frame);
480 if ( !live_shinfo && !(info.flags & XEN_DOMINF_hvm_guest) )
481 {
482 PERROR("Couldn't map live_shinfo");
483 goto out;
484 }
485 auto_translated_physmap = xc_core_arch_auto_translated_physmap(&info);
486
487 if ( !auto_translated_physmap )
488
489 {
490 if ( xc_domain_get_guest_width(xch, domid, &dinfo->guest_width) != 0 )
491 {
492 PERROR("Could not get address size for domain");
493 goto out;
494 }
495 }
496 else
497 {
498 /*
499 * Autotranslated guest never sets guest width in the first
500 * place. Force guest_width to be sizeof(unsigned long) so
501 * code below functions properly.
502 *
503 * Here is why this is correct.
504 *
505 * 1. Before f969bc9fc, xc_domain_get_guest_width for HVM (x86
506 * and ARM) always returned hypervisor's idea of
507 * sizeof(unsigned long).
508 *
509 * 2. There has never been a situation in which hypervisor's
510 * word width is smaller than toolstack domain's (i.e. no
511 * 32bit hypervisor + 64bit toolstack).
512 *
513 * Predicates in code test guest_width against toolstack
514 * domain's sizeof(unsigned long), so setting guest_width to
515 * toolstack domain's idea of sizeof(unsigned long) matches
516 * the original behaviour for HVM guests.
517 */
518 dinfo->guest_width = sizeof(unsigned long);
519 }
520
521 ctxt = calloc(sizeof(*ctxt), info.max_vcpu_id + 1);
522 if ( !ctxt )
523 {
524 PERROR("Could not allocate vcpu context array");
525 goto out;
526 }
527
528 for ( i = 0; i <= info.max_vcpu_id; i++ )
529 {
530 if ( xc_vcpu_getcontext(xch, domid, i, &ctxt[nr_vcpus]) == 0 )
531 {
532 if ( xc_core_arch_context_get(&arch_ctxt, &ctxt[nr_vcpus],
533 xch, domid) )
534 continue;
535 nr_vcpus++;
536 }
537 }
538 if ( nr_vcpus == 0 )
539 {
540 PERROR("No VCPU context could be grabbed");
541 goto out;
542 }
543
544 /* obtain memory map */
545 sts = xc_core_arch_memory_map_get(xch, &arch_ctxt, &info,
546 live_shinfo, &memory_map,
547 &nr_memory_map);
548 if ( sts != 0 )
549 goto out;
550
551 /*
552 * Note: this is the *current* number of pages and may change under
553 * a live dump-core. We'll just take this value, and if more pages
554 * exist, we'll skip them. If there's less, then we'll just not use
555 * all the array...
556 *
557 * We don't want to use the total potential size of the memory map
558 * since that is usually much higher than info.tot_pages.
559 */
560 nr_pages = info.tot_pages;
561
562 if ( !auto_translated_physmap )
563 {
564 /* obtain p2m table */
565 p2m_array = malloc(nr_pages * sizeof(p2m_array[0]));
566 if ( p2m_array == NULL )
567 {
568 PERROR("Could not allocate p2m array");
569 goto out;
570 }
571
572 sts = xc_core_arch_map_p2m(xch, dinfo, &info, live_shinfo, &p2m);
573 if ( sts != 0 )
574 goto out;
575
576 sts = xc_maximum_ram_page(xch, &max_mfn);
577 if ( sts != 0 )
578 goto out;
579 }
580 else
581 {
582 pfn_array = malloc(nr_pages * sizeof(pfn_array[0]));
583 if ( pfn_array == NULL )
584 {
585 PERROR("Could not allocate pfn array");
586 goto out;
587 }
588 }
589
590 /* ehdr.e_shnum and ehdr.e_shstrndx aren't known here yet. fill it later*/
591 xc_core_ehdr_init(&ehdr);
592
593 /* create section header */
594 strtab = xc_core_strtab_init(xch);
595 if ( strtab == NULL )
596 {
597 PERROR("Could not allocate string table");
598 goto out;
599 }
600 sheaders = xc_core_shdr_init(xch);
601 if ( sheaders == NULL )
602 {
603 PERROR("Could not allocate section headers");
604 goto out;
605 }
606 /* null section */
607 shdr = xc_core_shdr_get(xch,sheaders);
608 if ( shdr == NULL )
609 {
610 PERROR("Could not get section header for null section");
611 goto out;
612 }
613
614 /* .shstrtab */
615 shdr = xc_core_shdr_get(xch,sheaders);
616 if ( shdr == NULL )
617 {
618 PERROR("Could not get section header for shstrtab");
619 goto out;
620 }
621 strtab_idx = shdr - sheaders->shdrs;
622 /* strtab_shdr.sh_offset, strtab_shdr.sh_size aren't unknown.
623 * fill it later
624 */
625 sts = xc_core_shdr_set(xch, shdr, strtab, ELF_SHSTRTAB, SHT_STRTAB, 0, 0, 0, 0);
626 if ( sts != 0 )
627 goto out;
628
629 /* elf note section */
630 /* here the number of section header is unknown. fix up offset later. */
631 offset = sizeof(ehdr);
632 filesz =
633 sizeof(struct xen_dumpcore_elfnote_none) + /* none */
634 sizeof(struct xen_dumpcore_elfnote_header) + /* core header */
635 sizeof(struct xen_dumpcore_elfnote_xen_version) + /* xen version */
636 sizeof(struct xen_dumpcore_elfnote_format_version);/* format version */
637 shdr = xc_core_shdr_get(xch,sheaders);
638 if ( shdr == NULL )
639 {
640 PERROR("Could not get section header for note section");
641 goto out;
642 }
643 sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_NOTE, SHT_NOTE,
644 offset, filesz, 0, 0);
645 if ( sts != 0 )
646 goto out;
647 offset += filesz;
648
649 /* prstatus */
650 shdr = xc_core_shdr_get(xch,sheaders);
651 if ( shdr == NULL )
652 {
653 PERROR("Could not get section header for .xen_prstatus");
654 goto out;
655 }
656 filesz = sizeof(*ctxt) * nr_vcpus;
657 sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_PRSTATUS,
658 SHT_PROGBITS, offset, filesz,
659 __alignof__(*ctxt), sizeof(*ctxt));
660 if ( sts != 0 )
661 goto out;
662 offset += filesz;
663
664 /* arch context */
665 sts = xc_core_arch_context_get_shdr(xch, &arch_ctxt, sheaders, strtab,
666 &filesz, offset);
667 if ( sts != 0 )
668 goto out;
669 offset += filesz;
670
671 /* shared_info */
672 if ( live_shinfo != NULL )
673 {
674 shdr = xc_core_shdr_get(xch,sheaders);
675 if ( shdr == NULL )
676 {
677 PERROR("Could not get section header for .xen_shared_info");
678 goto out;
679 }
680 filesz = PAGE_SIZE;
681 sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_SHARED_INFO,
682 SHT_PROGBITS, offset, filesz,
683 __alignof__(*live_shinfo), PAGE_SIZE);
684 if ( sts != 0 )
685 goto out;
686 offset += filesz;
687 }
688
689 /*
690 * pages and p2m/pfn are the last section to allocate section headers
691 * so that we know the number of section headers here.
692 * 2 = pages section and p2m/pfn table section
693 */
694 fixup = (sheaders->num + 2) * sizeof(*shdr);
695 /* zeroth section should have zero offset */
696 for ( i = 1; i < sheaders->num; i++ )
697 sheaders->shdrs[i].sh_offset += fixup;
698 offset += fixup;
699 dummy_len = ROUNDUP(offset, PAGE_SHIFT) - offset; /* padding length */
700 offset += dummy_len;
701
702 /* pages */
703 shdr = xc_core_shdr_get(xch,sheaders);
704 if ( shdr == NULL )
705 {
706 PERROR("could not get section headers for .xen_pages");
707 goto out;
708 }
709 filesz = (uint64_t)nr_pages * PAGE_SIZE;
710 sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_PAGES, SHT_PROGBITS,
711 offset, filesz, PAGE_SIZE, PAGE_SIZE);
712 if ( sts != 0 )
713 goto out;
714 offset += filesz;
715
716 /* p2m/pfn table */
717 shdr = xc_core_shdr_get(xch,sheaders);
718 if ( shdr == NULL )
719 {
720 PERROR("Could not get section header for .xen_{p2m, pfn} table");
721 goto out;
722 }
723 if ( !auto_translated_physmap )
724 {
725 filesz = (uint64_t)nr_pages * sizeof(p2m_array[0]);
726 sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_P2M,
727 SHT_PROGBITS,
728 offset, filesz, __alignof__(p2m_array[0]),
729 sizeof(p2m_array[0]));
730 }
731 else
732 {
733 filesz = (uint64_t)nr_pages * sizeof(pfn_array[0]);
734 sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_PFN,
735 SHT_PROGBITS,
736 offset, filesz, __alignof__(pfn_array[0]),
737 sizeof(pfn_array[0]));
738 }
739 if ( sts != 0 )
740 goto out;
741 offset += filesz;
742
743 /* fixing up section header string table section header */
744 filesz = strtab->length;
745 sheaders->shdrs[strtab_idx].sh_offset = offset;
746 sheaders->shdrs[strtab_idx].sh_size = filesz;
747
748 /* write out elf header */
749 ehdr.e_shnum = sheaders->num;
750 ehdr.e_shstrndx = strtab_idx;
751 ehdr.e_machine = ELF_ARCH_MACHINE;
752 sts = dump_rtn(xch, args, (char*)&ehdr, sizeof(ehdr));
753 if ( sts != 0 )
754 goto out;
755
756 /* section headers */
757 sts = dump_rtn(xch, args, (char*)sheaders->shdrs,
758 sheaders->num * sizeof(sheaders->shdrs[0]));
759 if ( sts != 0 )
760 goto out;
761
762 /* elf note section: xen core header */
763 sts = elfnote_dump_none(xch, args, dump_rtn);
764 if ( sts != 0 )
765 goto out;
766
767 /* elf note section: xen core header */
768 sts = elfnote_dump_core_header(xch, args, dump_rtn, &info, nr_vcpus, nr_pages);
769 if ( sts != 0 )
770 goto out;
771
772 /* elf note section: xen version */
773 sts = elfnote_dump_xen_version(xch, args, dump_rtn, dinfo->guest_width);
774 if ( sts != 0 )
775 goto out;
776
777 /* elf note section: format version */
778 sts = elfnote_dump_format_version(xch, args, dump_rtn);
779 if ( sts != 0 )
780 goto out;
781
782 /* prstatus: .xen_prstatus */
783 sts = dump_rtn(xch, args, (char *)ctxt, sizeof(*ctxt) * nr_vcpus);
784 if ( sts != 0 )
785 goto out;
786
787 if ( live_shinfo != NULL )
788 {
789 /* shared_info: .xen_shared_info */
790 sts = dump_rtn(xch, args, (char*)live_shinfo, PAGE_SIZE);
791 if ( sts != 0 )
792 goto out;
793 }
794
795 /* arch specific context */
796 sts = xc_core_arch_context_dump(xch, &arch_ctxt, args, dump_rtn);
797 if ( sts != 0 )
798 goto out;
799
800 /* Pad the output data to page alignment. */
801 memset(dummy, 0, PAGE_SIZE);
802 sts = dump_rtn(xch, args, dummy, dummy_len);
803 if ( sts != 0 )
804 goto out;
805
806 /* dump pages: .xen_pages */
807 j = 0;
808 dump_mem = dump_mem_start;
809 for ( map_idx = 0; map_idx < nr_memory_map; map_idx++ )
810 {
811 uint64_t pfn_start;
812 uint64_t pfn_end;
813
814 pfn_start = memory_map[map_idx].addr >> PAGE_SHIFT;
815 pfn_end = pfn_start + (memory_map[map_idx].size >> PAGE_SHIFT);
816 for ( i = pfn_start; i < pfn_end; i++ )
817 {
818 uint64_t gmfn;
819 void *vaddr;
820
821 if ( !auto_translated_physmap )
822 {
823 if ( i >= dinfo->p2m_size )
824 break;
825
826 if ( dinfo->guest_width >= sizeof(unsigned long) )
827 {
828 if ( dinfo->guest_width == sizeof(unsigned long) )
829 gmfn = p2m[i];
830 else
831 gmfn = ((uint64_t *)p2m)[i];
832 if ( gmfn == INVALID_PFN )
833 continue;
834 }
835 else
836 {
837 gmfn = ((uint32_t *)p2m)[i];
838 if ( gmfn == (uint32_t)INVALID_PFN )
839 continue;
840 }
841 if ( gmfn > max_mfn )
842 continue;
843
844 if ( j >= nr_pages )
845 {
846 j++;
847 continue;
848 }
849
850 p2m_array[j].pfn = i;
851 p2m_array[j].gmfn = gmfn;
852 }
853 else
854 {
855 if ( !xc_core_arch_gpfn_may_present(&arch_ctxt, i) )
856 continue;
857
858 if ( j >= nr_pages )
859 {
860 j++;
861 continue;
862 }
863
864 gmfn = i;
865 pfn_array[j] = i;
866 }
867
868 vaddr = xc_map_foreign_range(
869 xch, domid, PAGE_SIZE, PROT_READ, gmfn);
870 if ( vaddr == NULL )
871 continue;
872 memcpy(dump_mem, vaddr, PAGE_SIZE);
873 munmap(vaddr, PAGE_SIZE);
874 dump_mem += PAGE_SIZE;
875 if ( (j + 1) % DUMP_INCREMENT == 0 )
876 {
877 sts = dump_rtn(
878 xch, args, dump_mem_start, dump_mem - dump_mem_start);
879 if ( sts != 0 )
880 goto out;
881 dump_mem = dump_mem_start;
882 }
883
884 j++;
885 }
886 }
887
888 if ( j > nr_pages )
889 {
890 /*
891 * When live dump-mode (-L option) is specified,
892 * guest domain may increase memory.
893 */
894 IPRINTF("exceeded nr_pages (%ld) losing %ld pages", nr_pages, j - nr_pages);
895 }
896
897 sts = dump_rtn(xch, args, dump_mem_start, dump_mem - dump_mem_start);
898 if ( sts != 0 )
899 goto out;
900 if ( j < nr_pages )
901 {
902 /* When live dump-mode (-L option) is specified,
903 * guest domain may reduce memory. pad with zero pages.
904 */
905 DPRINTF("j (%ld) != nr_pages (%ld)", j, nr_pages);
906 memset(dump_mem_start, 0, PAGE_SIZE);
907 for (; j < nr_pages; j++) {
908 sts = dump_rtn(xch, args, dump_mem_start, PAGE_SIZE);
909 if ( sts != 0 )
910 goto out;
911 if ( !auto_translated_physmap )
912 {
913 p2m_array[j].pfn = XC_CORE_INVALID_PFN;
914 p2m_array[j].gmfn = XC_CORE_INVALID_GMFN;
915 }
916 else
917 pfn_array[j] = XC_CORE_INVALID_PFN;
918 }
919 }
920
921 /* p2m/pfn table: .xen_p2m/.xen_pfn */
922 if ( !auto_translated_physmap )
923 sts = dump_rtn(
924 xch, args, (char *)p2m_array, sizeof(p2m_array[0]) * nr_pages);
925 else
926 sts = dump_rtn(
927 xch, args, (char *)pfn_array, sizeof(pfn_array[0]) * nr_pages);
928 if ( sts != 0 )
929 goto out;
930
931 /* elf section header string table: .shstrtab */
932 sts = dump_rtn(xch, args, strtab->strings, strtab->length);
933 if ( sts != 0 )
934 goto out;
935
936 sts = 0;
937
938 out:
939 if ( memory_map != NULL )
940 free(memory_map);
941 if ( p2m != NULL )
942 munmap(p2m, PAGE_SIZE * dinfo->p2m_frames);
943 if ( p2m_array != NULL )
944 free(p2m_array);
945 if ( pfn_array != NULL )
946 free(pfn_array);
947 if ( sheaders != NULL )
948 xc_core_shdr_free(sheaders);
949 if ( strtab != NULL )
950 xc_core_strtab_free(strtab);
951 if ( ctxt != NULL )
952 free(ctxt);
953 if ( dump_mem_start != NULL )
954 free(dump_mem_start);
955 if ( live_shinfo != NULL )
956 munmap(live_shinfo, PAGE_SIZE);
957 xc_core_arch_context_free(&arch_ctxt);
958
959 return sts;
960 }
961
962 /* Callback args for writing to a local dump file. */
963 struct dump_args {
964 int fd;
965 };
966
967 /* Callback routine for writing to a local dump file. */
local_file_dump(xc_interface * xch,void * args,char * buffer,unsigned int length)968 static int local_file_dump(xc_interface *xch,
969 void *args, char *buffer, unsigned int length)
970 {
971 struct dump_args *da = args;
972
973 if ( write_exact(da->fd, buffer, length) == -1 )
974 {
975 PERROR("Failed to write buffer");
976 return -errno;
977 }
978
979 if ( length >= (DUMP_INCREMENT * PAGE_SIZE) )
980 {
981 // Now dumping pages -- make sure we discard clean pages from
982 // the cache after each write
983 discard_file_cache(xch, da->fd, 0 /* no flush */);
984 }
985
986 return 0;
987 }
988
989 int
xc_domain_dumpcore(xc_interface * xch,uint32_t domid,const char * corename)990 xc_domain_dumpcore(xc_interface *xch,
991 uint32_t domid,
992 const char *corename)
993 {
994 struct dump_args da;
995 int sts;
996
997 if ( (da.fd = open(corename, O_CREAT|O_RDWR|O_TRUNC, S_IWUSR|S_IRUSR)) < 0 )
998 {
999 PERROR("Could not open corefile %s", corename);
1000 return -errno;
1001 }
1002
1003 sts = xc_domain_dumpcore_via_callback(
1004 xch, domid, &da, &local_file_dump);
1005
1006 /* flush and discard any remaining portion of the file from cache */
1007 discard_file_cache(xch, da.fd, 1/* flush first*/);
1008
1009 close(da.fd);
1010
1011 return sts;
1012 }
1013
1014 /*
1015 * Local variables:
1016 * mode: C
1017 * c-file-style: "BSD"
1018 * c-basic-offset: 4
1019 * tab-width: 4
1020 * indent-tabs-mode: nil
1021 * End:
1022 */
1023