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