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 "xg_private.h"
64 #include "xc_core.h"
65 #include "xc_dom.h"
66 #include <stdlib.h>
67 #include <unistd.h>
68
69 /* number of pages to write at a time */
70 #define DUMP_INCREMENT (4 * 1024)
71
72 /* string table */
73 struct xc_core_strtab {
74 char *strings;
75 uint16_t length;
76 uint16_t max;
77 };
78
79 static struct xc_core_strtab*
xc_core_strtab_init(xc_interface * xch)80 xc_core_strtab_init(xc_interface *xch)
81 {
82 struct xc_core_strtab *strtab;
83 char *strings;
84 strtab = malloc(sizeof(*strtab));
85 if ( strtab == NULL )
86 return NULL;
87
88 strings = malloc(PAGE_SIZE);
89 if ( strings == NULL )
90 {
91 PERROR("Could not allocate string table init");
92 free(strtab);
93 return NULL;
94 }
95 strtab->strings = strings;
96 strtab->max = PAGE_SIZE;
97
98 /* index 0 represents none */
99 strtab->strings[0] = '\0';
100 strtab->length = 1;
101
102 return strtab;
103 }
104
105 static void
xc_core_strtab_free(struct xc_core_strtab * strtab)106 xc_core_strtab_free(struct xc_core_strtab *strtab)
107 {
108 free(strtab->strings);
109 free(strtab);
110 }
111
112 static uint16_t
xc_core_strtab_get(xc_interface * xch,struct xc_core_strtab * strtab,const char * name)113 xc_core_strtab_get(xc_interface *xch, struct xc_core_strtab *strtab, const char *name)
114 {
115 uint16_t ret = 0;
116 uint16_t len = strlen(name) + 1;
117
118 if ( strtab->length > UINT16_MAX - len )
119 {
120 PERROR("too long string table");
121 errno = E2BIG;
122 return ret;
123 }
124
125 if ( strtab->length + len > strtab->max )
126 {
127 char *tmp;
128 if ( strtab->max > UINT16_MAX / 2 )
129 {
130 PERROR("too long string table");
131 errno = ENOMEM;
132 return ret;
133 }
134
135 tmp = realloc(strtab->strings, strtab->max * 2);
136 if ( tmp == NULL )
137 {
138 PERROR("Could not allocate string table");
139 return ret;
140 }
141
142 strtab->strings = tmp;
143 strtab->max *= 2;
144 }
145
146 ret = strtab->length;
147 strcpy(strtab->strings + strtab->length, name);
148 strtab->length += len;
149 return ret;
150 }
151
152
153 /* section headers */
154 struct xc_core_section_headers {
155 uint16_t num;
156 uint16_t num_max;
157
158 Elf64_Shdr *shdrs;
159 };
160 #define SHDR_INIT ((uint16_t)16)
161 #define SHDR_INC ((uint16_t)4)
162
163 static struct xc_core_section_headers*
xc_core_shdr_init(xc_interface * xch)164 xc_core_shdr_init(xc_interface *xch)
165 {
166 struct xc_core_section_headers *sheaders;
167 sheaders = malloc(sizeof(*sheaders));
168 if ( sheaders == NULL )
169 return NULL;
170
171 sheaders->num = 0;
172 sheaders->num_max = SHDR_INIT;
173 sheaders->shdrs = malloc(sizeof(sheaders->shdrs[0]) * sheaders->num_max);
174 if ( sheaders->shdrs == NULL )
175 {
176 free(sheaders);
177 return NULL;
178 }
179 return sheaders;
180 }
181
182 static void
xc_core_shdr_free(struct xc_core_section_headers * sheaders)183 xc_core_shdr_free(struct xc_core_section_headers *sheaders)
184 {
185 free(sheaders->shdrs);
186 free(sheaders);
187 }
188
189 Elf64_Shdr*
xc_core_shdr_get(xc_interface * xch,struct xc_core_section_headers * sheaders)190 xc_core_shdr_get(xc_interface *xch,
191 struct xc_core_section_headers *sheaders)
192 {
193 Elf64_Shdr *shdr;
194
195 if ( sheaders->num == sheaders->num_max )
196 {
197 Elf64_Shdr *shdrs;
198 if ( sheaders->num_max > UINT16_MAX - SHDR_INC )
199 {
200 errno = E2BIG;
201 return NULL;
202 }
203 sheaders->num_max += SHDR_INC;
204 shdrs = realloc(sheaders->shdrs,
205 sizeof(sheaders->shdrs[0]) * sheaders->num_max);
206 if ( shdrs == NULL )
207 return NULL;
208 sheaders->shdrs = shdrs;
209 }
210
211 shdr = &sheaders->shdrs[sheaders->num];
212 sheaders->num++;
213 memset(shdr, 0, sizeof(*shdr));
214 return shdr;
215 }
216
217 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)218 xc_core_shdr_set(xc_interface *xch,
219 Elf64_Shdr *shdr,
220 struct xc_core_strtab *strtab,
221 const char *name, uint32_t type,
222 uint64_t offset, uint64_t size,
223 uint64_t addralign, uint64_t entsize)
224 {
225 uint64_t name_idx = xc_core_strtab_get(xch, strtab, name);
226 if ( name_idx == 0 )
227 return -1;
228
229 shdr->sh_name = name_idx;
230 shdr->sh_type = type;
231 shdr->sh_offset = offset;
232 shdr->sh_size = size;
233 shdr->sh_addralign = addralign;
234 shdr->sh_entsize = entsize;
235 return 0;
236 }
237
238 static void
xc_core_ehdr_init(Elf64_Ehdr * ehdr)239 xc_core_ehdr_init(Elf64_Ehdr *ehdr)
240 {
241 memset(ehdr, 0, sizeof(*ehdr));
242 ehdr->e_ident[EI_MAG0] = ELFMAG0;
243 ehdr->e_ident[EI_MAG1] = ELFMAG1;
244 ehdr->e_ident[EI_MAG2] = ELFMAG2;
245 ehdr->e_ident[EI_MAG3] = ELFMAG3;
246 ehdr->e_ident[EI_CLASS] = ELFCLASS64;
247 ehdr->e_ident[EI_DATA] = ELF_ARCH_DATA;
248 ehdr->e_ident[EI_VERSION] = EV_CURRENT;
249 ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
250 ehdr->e_ident[EI_ABIVERSION] = EV_CURRENT;
251
252 ehdr->e_type = ET_CORE;
253 /* e_machine will be filled in later */
254 ehdr->e_version = EV_CURRENT;
255 ehdr->e_entry = 0;
256 ehdr->e_phoff = 0;
257 ehdr->e_shoff = sizeof(*ehdr);
258 ehdr->e_flags = ELF_CORE_EFLAGS;
259 ehdr->e_ehsize = sizeof(*ehdr);
260 ehdr->e_phentsize = sizeof(Elf64_Phdr);
261 ehdr->e_phnum = 0;
262 ehdr->e_shentsize = sizeof(Elf64_Shdr);
263 /* ehdr->e_shnum and ehdr->e_shstrndx aren't known here yet.
264 * fill it later */
265 }
266
267 static int
elfnote_fill_xen_version(xc_interface * xch,struct xen_dumpcore_elfnote_xen_version_desc * xen_version)268 elfnote_fill_xen_version(xc_interface *xch,
269 struct xen_dumpcore_elfnote_xen_version_desc
270 *xen_version)
271 {
272 int rc;
273 memset(xen_version, 0, sizeof(*xen_version));
274
275 rc = xc_version(xch, XENVER_version, NULL);
276 if ( rc < 0 )
277 return rc;
278 xen_version->major_version = rc >> 16;
279 xen_version->minor_version = rc & ((1 << 16) - 1);
280
281 rc = xc_version(xch, XENVER_extraversion,
282 &xen_version->extra_version);
283 if ( rc < 0 )
284 return rc;
285
286 rc = xc_version(xch, XENVER_compile_info,
287 &xen_version->compile_info);
288 if ( rc < 0 )
289 return rc;
290
291 rc = xc_version(xch,
292 XENVER_capabilities, &xen_version->capabilities);
293 if ( rc < 0 )
294 return rc;
295
296 rc = xc_version(xch, XENVER_changeset, &xen_version->changeset);
297 if ( rc < 0 )
298 return rc;
299
300 rc = xc_version(xch, XENVER_platform_parameters,
301 &xen_version->platform_parameters);
302 if ( rc < 0 )
303 return rc;
304
305 rc = xc_version(xch, XENVER_pagesize, NULL);
306 if ( rc < 0 )
307 return rc;
308 xen_version->pagesize = rc;
309
310 return 0;
311 }
312
313 static void
elfnote_fill_format_version(struct xen_dumpcore_elfnote_format_version_desc * format_version)314 elfnote_fill_format_version(struct xen_dumpcore_elfnote_format_version_desc
315 *format_version)
316 {
317 format_version->version = XEN_DUMPCORE_FORMAT_VERSION_CURRENT;
318 }
319
320 static void
elfnote_init(struct elfnote * elfnote)321 elfnote_init(struct elfnote *elfnote)
322 {
323 /* elf note section */
324 memset(elfnote, 0, sizeof(*elfnote));
325 elfnote->namesz = strlen(XEN_DUMPCORE_ELFNOTE_NAME) + 1;
326 strncpy(elfnote->name, XEN_DUMPCORE_ELFNOTE_NAME, sizeof(elfnote->name));
327 }
328
329 static int
elfnote_dump_none(xc_interface * xch,void * args,dumpcore_rtn_t dump_rtn)330 elfnote_dump_none(xc_interface *xch, void *args, dumpcore_rtn_t dump_rtn)
331 {
332 int sts;
333 struct elfnote elfnote;
334 struct xen_dumpcore_elfnote_none_desc none;
335
336 elfnote_init(&elfnote);
337 /* Avoid compile warning about constant-zero-sized memset(). */
338 /*memset(&none, 0, sizeof(none));*/
339
340 elfnote.descsz = sizeof(none);
341 elfnote.type = XEN_ELFNOTE_DUMPCORE_NONE;
342 sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote));
343 if ( sts != 0 )
344 return sts;
345 return dump_rtn(xch, args, (char*)&none, sizeof(none));
346 }
347
348 static int
elfnote_dump_core_header(xc_interface * xch,void * args,dumpcore_rtn_t dump_rtn,const xc_dominfo_t * info,int nr_vcpus,unsigned long nr_pages)349 elfnote_dump_core_header(
350 xc_interface *xch,
351 void *args, dumpcore_rtn_t dump_rtn, const xc_dominfo_t *info,
352 int nr_vcpus, unsigned long nr_pages)
353 {
354 int sts;
355 struct elfnote elfnote;
356 struct xen_dumpcore_elfnote_header_desc header;
357
358 elfnote_init(&elfnote);
359 memset(&header, 0, sizeof(header));
360
361 elfnote.descsz = sizeof(header);
362 elfnote.type = XEN_ELFNOTE_DUMPCORE_HEADER;
363 header.xch_magic = info->hvm ? XC_CORE_MAGIC_HVM : XC_CORE_MAGIC;
364 header.xch_nr_vcpus = nr_vcpus;
365 header.xch_nr_pages = nr_pages;
366 header.xch_page_size = PAGE_SIZE;
367 sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote));
368 if ( sts != 0 )
369 return sts;
370 return dump_rtn(xch, args, (char*)&header, sizeof(header));
371 }
372
373 static int
elfnote_dump_xen_version(xc_interface * xch,void * args,dumpcore_rtn_t dump_rtn,unsigned int guest_width)374 elfnote_dump_xen_version(xc_interface *xch, void *args,
375 dumpcore_rtn_t dump_rtn, unsigned int guest_width)
376 {
377 int sts;
378 struct elfnote elfnote;
379 struct xen_dumpcore_elfnote_xen_version_desc xen_version;
380
381 elfnote_init(&elfnote);
382 memset(&xen_version, 0, sizeof(xen_version));
383
384 elfnote.descsz = sizeof(xen_version);
385 elfnote.type = XEN_ELFNOTE_DUMPCORE_XEN_VERSION;
386 elfnote_fill_xen_version(xch, &xen_version);
387 if (guest_width < sizeof(unsigned long))
388 {
389 // 32 bit elf file format differs in pagesize's alignment
390 char *p = (char *)&xen_version.pagesize;
391 memmove(p - 4, p, sizeof(xen_version.pagesize));
392 }
393 sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote));
394 if ( sts != 0 )
395 return sts;
396 return dump_rtn(xch, args, (char*)&xen_version, sizeof(xen_version));
397 }
398
399 static int
elfnote_dump_format_version(xc_interface * xch,void * args,dumpcore_rtn_t dump_rtn)400 elfnote_dump_format_version(xc_interface *xch,
401 void *args, dumpcore_rtn_t dump_rtn)
402 {
403 int sts;
404 struct elfnote elfnote;
405 struct xen_dumpcore_elfnote_format_version_desc format_version;
406
407 elfnote_init(&elfnote);
408 memset(&format_version, 0, sizeof(format_version));
409
410 elfnote.descsz = sizeof(format_version);
411 elfnote.type = XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION;
412 elfnote_fill_format_version(&format_version);
413 sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote));
414 if ( sts != 0 )
415 return sts;
416 return dump_rtn(xch, args, (char*)&format_version, sizeof(format_version));
417 }
418
419 int
xc_domain_dumpcore_via_callback(xc_interface * xch,uint32_t domid,void * args,dumpcore_rtn_t dump_rtn)420 xc_domain_dumpcore_via_callback(xc_interface *xch,
421 uint32_t domid,
422 void *args,
423 dumpcore_rtn_t dump_rtn)
424 {
425 xc_dominfo_t info;
426 shared_info_any_t *live_shinfo = NULL;
427 struct domain_info_context _dinfo = {};
428 struct domain_info_context *dinfo = &_dinfo;
429
430 int nr_vcpus = 0;
431 char *dump_mem, *dump_mem_start = NULL;
432 vcpu_guest_context_any_t *ctxt = NULL;
433 struct xc_core_arch_context arch_ctxt;
434 char dummy[PAGE_SIZE];
435 int dummy_len;
436 int sts = -1;
437
438 unsigned long i;
439 unsigned long j;
440 unsigned long nr_pages;
441
442 xc_core_memory_map_t *memory_map = NULL;
443 unsigned int nr_memory_map;
444 unsigned int map_idx;
445
446 int auto_translated_physmap;
447 xen_pfn_t *p2m = NULL;
448 struct xen_dumpcore_p2m *p2m_array = NULL;
449
450 uint64_t *pfn_array = NULL;
451
452 Elf64_Ehdr ehdr;
453 uint64_t filesz;
454 uint64_t offset;
455 uint64_t fixup;
456
457 struct xc_core_strtab *strtab = NULL;
458 uint16_t strtab_idx;
459 struct xc_core_section_headers *sheaders = NULL;
460 Elf64_Shdr *shdr;
461
462 xc_core_arch_context_init(&arch_ctxt);
463 if ( (dump_mem_start = malloc(DUMP_INCREMENT*PAGE_SIZE)) == NULL )
464 {
465 PERROR("Could not allocate dump_mem");
466 goto out;
467 }
468
469 if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 )
470 {
471 PERROR("Could not get info for domain");
472 goto out;
473 }
474 /* Map the shared info frame */
475 live_shinfo = xc_map_foreign_range(xch, domid, PAGE_SIZE,
476 PROT_READ, info.shared_info_frame);
477 if ( !live_shinfo && !info.hvm )
478 {
479 PERROR("Couldn't map live_shinfo");
480 goto out;
481 }
482 auto_translated_physmap = xc_core_arch_auto_translated_physmap(&info);
483
484 if ( !auto_translated_physmap )
485
486 {
487 if ( xc_domain_get_guest_width(xch, domid, &dinfo->guest_width) != 0 )
488 {
489 PERROR("Could not get address size for domain");
490 goto out;
491 }
492 }
493 else
494 {
495 /*
496 * Autotranslated guest never sets guest width in the first
497 * place. Force guest_width to be sizeof(unsigned long) so
498 * code below functions properly.
499 *
500 * Here is why this is correct.
501 *
502 * 1. Before f969bc9fc, xc_domain_get_guest_width for HVM (x86
503 * and ARM) always returned hypervisor's idea of
504 * sizeof(unsigned long).
505 *
506 * 2. There has never been a situation in which hypervisor's
507 * word width is smaller than toolstack domain's (i.e. no
508 * 32bit hypervisor + 64bit toolstack).
509 *
510 * Predicates in code test guest_width against toolstack
511 * domain's sizeof(unsigned long), so setting guest_width to
512 * toolstack domain's idea of sizeof(unsigned long) matches
513 * the original behaviour for HVM guests.
514 */
515 dinfo->guest_width = sizeof(unsigned long);
516 }
517
518 if ( domid != info.domid )
519 {
520 PERROR("Domain %d does not exist", domid);
521 goto out;
522 }
523
524 ctxt = calloc(sizeof(*ctxt), info.max_vcpu_id + 1);
525 if ( !ctxt )
526 {
527 PERROR("Could not allocate vcpu context array");
528 goto out;
529 }
530
531 for ( i = 0; i <= info.max_vcpu_id; i++ )
532 {
533 if ( xc_vcpu_getcontext(xch, domid, i, &ctxt[nr_vcpus]) == 0 )
534 {
535 if ( xc_core_arch_context_get(&arch_ctxt, &ctxt[nr_vcpus],
536 xch, domid) )
537 continue;
538 nr_vcpus++;
539 }
540 }
541 if ( nr_vcpus == 0 )
542 {
543 PERROR("No VCPU context could be grabbed");
544 goto out;
545 }
546
547 /* obtain memory map */
548 sts = xc_core_arch_memory_map_get(xch, &arch_ctxt, &info,
549 live_shinfo, &memory_map,
550 &nr_memory_map);
551 if ( sts != 0 )
552 goto out;
553
554 /*
555 * Note: this is the *current* number of pages and may change under
556 * a live dump-core. We'll just take this value, and if more pages
557 * exist, we'll skip them. If there's less, then we'll just not use
558 * all the array...
559 *
560 * We don't want to use the total potential size of the memory map
561 * since that is usually much higher than info.nr_pages.
562 */
563 nr_pages = info.nr_pages;
564
565 if ( !auto_translated_physmap )
566 {
567 /* obtain p2m table */
568 p2m_array = malloc(nr_pages * sizeof(p2m_array[0]));
569 if ( p2m_array == NULL )
570 {
571 PERROR("Could not allocate p2m array");
572 goto out;
573 }
574
575 sts = xc_core_arch_map_p2m(xch, dinfo->guest_width, &info, live_shinfo,
576 &p2m, &dinfo->p2m_size);
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 ( j >= nr_pages )
822 {
823 /*
824 * When live dump-mode (-L option) is specified,
825 * guest domain may increase memory.
826 */
827 IPRINTF("exceeded nr_pages (%ld) losing pages", nr_pages);
828 goto copy_done;
829 }
830
831 if ( !auto_translated_physmap )
832 {
833 if ( dinfo->guest_width >= sizeof(unsigned long) )
834 {
835 if ( dinfo->guest_width == sizeof(unsigned long) )
836 gmfn = p2m[i];
837 else
838 gmfn = ((uint64_t *)p2m)[i];
839 if ( gmfn == INVALID_PFN )
840 continue;
841 }
842 else
843 {
844 gmfn = ((uint32_t *)p2m)[i];
845 if ( gmfn == (uint32_t)INVALID_PFN )
846 continue;
847 }
848
849 p2m_array[j].pfn = i;
850 p2m_array[j].gmfn = gmfn;
851 }
852 else
853 {
854 if ( !xc_core_arch_gpfn_may_present(&arch_ctxt, i) )
855 continue;
856
857 gmfn = i;
858 pfn_array[j] = i;
859 }
860
861 vaddr = xc_map_foreign_range(
862 xch, domid, PAGE_SIZE, PROT_READ, gmfn);
863 if ( vaddr == NULL )
864 continue;
865 memcpy(dump_mem, vaddr, PAGE_SIZE);
866 munmap(vaddr, PAGE_SIZE);
867 dump_mem += PAGE_SIZE;
868 if ( (j + 1) % DUMP_INCREMENT == 0 )
869 {
870 sts = dump_rtn(
871 xch, args, dump_mem_start, dump_mem - dump_mem_start);
872 if ( sts != 0 )
873 goto out;
874 dump_mem = dump_mem_start;
875 }
876
877 j++;
878 }
879 }
880
881 copy_done:
882 sts = dump_rtn(xch, args, dump_mem_start, dump_mem - dump_mem_start);
883 if ( sts != 0 )
884 goto out;
885 if ( j < nr_pages )
886 {
887 /* When live dump-mode (-L option) is specified,
888 * guest domain may reduce memory. pad with zero pages.
889 */
890 DPRINTF("j (%ld) != nr_pages (%ld)", j, nr_pages);
891 memset(dump_mem_start, 0, PAGE_SIZE);
892 for (; j < nr_pages; j++) {
893 sts = dump_rtn(xch, args, dump_mem_start, PAGE_SIZE);
894 if ( sts != 0 )
895 goto out;
896 if ( !auto_translated_physmap )
897 {
898 p2m_array[j].pfn = XC_CORE_INVALID_PFN;
899 p2m_array[j].gmfn = XC_CORE_INVALID_GMFN;
900 }
901 else
902 pfn_array[j] = XC_CORE_INVALID_PFN;
903 }
904 }
905
906 /* p2m/pfn table: .xen_p2m/.xen_pfn */
907 if ( !auto_translated_physmap )
908 sts = dump_rtn(
909 xch, args, (char *)p2m_array, sizeof(p2m_array[0]) * nr_pages);
910 else
911 sts = dump_rtn(
912 xch, args, (char *)pfn_array, sizeof(pfn_array[0]) * nr_pages);
913 if ( sts != 0 )
914 goto out;
915
916 /* elf section header string table: .shstrtab */
917 sts = dump_rtn(xch, args, strtab->strings, strtab->length);
918 if ( sts != 0 )
919 goto out;
920
921 sts = 0;
922
923 out:
924 if ( memory_map != NULL )
925 free(memory_map);
926 if ( p2m != NULL )
927 munmap(p2m, PAGE_SIZE * P2M_FL_ENTRIES);
928 if ( p2m_array != NULL )
929 free(p2m_array);
930 if ( pfn_array != NULL )
931 free(pfn_array);
932 if ( sheaders != NULL )
933 xc_core_shdr_free(sheaders);
934 if ( strtab != NULL )
935 xc_core_strtab_free(strtab);
936 if ( ctxt != NULL )
937 free(ctxt);
938 if ( dump_mem_start != NULL )
939 free(dump_mem_start);
940 if ( live_shinfo != NULL )
941 munmap(live_shinfo, PAGE_SIZE);
942 xc_core_arch_context_free(&arch_ctxt);
943
944 return sts;
945 }
946
947 /* Callback args for writing to a local dump file. */
948 struct dump_args {
949 int fd;
950 };
951
952 /* Callback routine for writing to a local dump file. */
local_file_dump(xc_interface * xch,void * args,char * buffer,unsigned int length)953 static int local_file_dump(xc_interface *xch,
954 void *args, char *buffer, unsigned int length)
955 {
956 struct dump_args *da = args;
957
958 if ( write_exact(da->fd, buffer, length) == -1 )
959 {
960 PERROR("Failed to write buffer");
961 return -errno;
962 }
963
964 if ( length >= (DUMP_INCREMENT * PAGE_SIZE) )
965 {
966 // Now dumping pages -- make sure we discard clean pages from
967 // the cache after each write
968 discard_file_cache(xch, da->fd, 0 /* no flush */);
969 }
970
971 return 0;
972 }
973
974 int
xc_domain_dumpcore(xc_interface * xch,uint32_t domid,const char * corename)975 xc_domain_dumpcore(xc_interface *xch,
976 uint32_t domid,
977 const char *corename)
978 {
979 struct dump_args da;
980 int sts;
981
982 if ( (da.fd = open(corename, O_CREAT|O_RDWR|O_TRUNC, S_IWUSR|S_IRUSR)) < 0 )
983 {
984 PERROR("Could not open corefile %s", corename);
985 return -errno;
986 }
987
988 sts = xc_domain_dumpcore_via_callback(
989 xch, domid, &da, &local_file_dump);
990
991 /* flush and discard any remaining portion of the file from cache */
992 discard_file_cache(xch, da.fd, 1/* flush first*/);
993
994 close(da.fd);
995
996 return sts;
997 }
998
999 /*
1000 * Local variables:
1001 * mode: C
1002 * c-file-style: "BSD"
1003 * c-basic-offset: 4
1004 * tab-width: 4
1005 * indent-tabs-mode: nil
1006 * End:
1007 */
1008