392 lines
14 KiB
Diff
392 lines
14 KiB
Diff
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1232023062 0
|
|
# Node ID ecf603780f560095c4316169c9473d040f216dfc
|
|
# Parent f6a455c9f01db586832c0eb98c14965c045e07ac
|
|
libxc: Support cross-bitness guest when core-dumping
|
|
|
|
This patch allows core-dumping to work on a cross-bit host/guest
|
|
configuration, whereas previously that was not supported. It supports
|
|
both PV and FV guests. The core file format generated by the host,
|
|
needs to match that of the guest, so an alignment issue is addressed,
|
|
along with the p2m frame list handling being done according to the
|
|
guest size.
|
|
|
|
Signed-off-by: Bruce Rogers <brogers@novell.com>
|
|
|
|
Index: xen-3.3.1-testing/tools/libxc/xc_core.c
|
|
===================================================================
|
|
--- xen-3.3.1-testing.orig/tools/libxc/xc_core.c
|
|
+++ xen-3.3.1-testing/tools/libxc/xc_core.c
|
|
@@ -58,9 +58,6 @@
|
|
/* number of pages to write at a time */
|
|
#define DUMP_INCREMENT (4 * 1024)
|
|
|
|
-/* Don't yet support cross-address-size core dump */
|
|
-#define guest_width (sizeof (unsigned long))
|
|
-
|
|
/* string table */
|
|
struct xc_core_strtab {
|
|
char *strings;
|
|
@@ -240,7 +237,7 @@ xc_core_ehdr_init(Elf64_Ehdr *ehdr)
|
|
ehdr->e_ident[EI_ABIVERSION] = EV_CURRENT;
|
|
|
|
ehdr->e_type = ET_CORE;
|
|
- ehdr->e_machine = ELF_ARCH_MACHINE;
|
|
+ /* e_machine will be filled in later */
|
|
ehdr->e_version = EV_CURRENT;
|
|
ehdr->e_entry = 0;
|
|
ehdr->e_phoff = 0;
|
|
@@ -359,7 +356,8 @@ elfnote_dump_core_header(
|
|
}
|
|
|
|
static int
|
|
-elfnote_dump_xen_version(void *args, dumpcore_rtn_t dump_rtn, int xc_handle)
|
|
+elfnote_dump_xen_version(void *args, dumpcore_rtn_t dump_rtn, int xc_handle,
|
|
+ unsigned int guest_width)
|
|
{
|
|
int sts;
|
|
struct elfnote elfnote;
|
|
@@ -371,6 +369,12 @@ elfnote_dump_xen_version(void *args, dum
|
|
elfnote.descsz = sizeof(xen_version);
|
|
elfnote.type = XEN_ELFNOTE_DUMPCORE_XEN_VERSION;
|
|
elfnote_fill_xen_version(xc_handle, &xen_version);
|
|
+ if (guest_width < sizeof(unsigned long))
|
|
+ {
|
|
+ // 32 bit elf file format differs in pagesize's alignment
|
|
+ char *p = (char *)&xen_version.pagesize;
|
|
+ memmove(p - 4, p, sizeof(xen_version.pagesize));
|
|
+ }
|
|
sts = dump_rtn(args, (char*)&elfnote, sizeof(elfnote));
|
|
if ( sts != 0 )
|
|
return sts;
|
|
@@ -396,6 +400,24 @@ elfnote_dump_format_version(void *args,
|
|
return dump_rtn(args, (char*)&format_version, sizeof(format_version));
|
|
}
|
|
|
|
+static int
|
|
+get_guest_width(int xc_handle,
|
|
+ uint32_t domid,
|
|
+ unsigned int *guest_width)
|
|
+{
|
|
+ DECLARE_DOMCTL;
|
|
+
|
|
+ memset(&domctl, 0, sizeof(domctl));
|
|
+ domctl.domain = domid;
|
|
+ domctl.cmd = XEN_DOMCTL_get_address_size;
|
|
+
|
|
+ if ( do_domctl(xc_handle, &domctl) != 0 )
|
|
+ return 1;
|
|
+
|
|
+ *guest_width = domctl.u.address_size.size / 8;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int
|
|
xc_domain_dumpcore_via_callback(int xc_handle,
|
|
uint32_t domid,
|
|
@@ -403,7 +425,8 @@ xc_domain_dumpcore_via_callback(int xc_h
|
|
dumpcore_rtn_t dump_rtn)
|
|
{
|
|
xc_dominfo_t info;
|
|
- shared_info_t *live_shinfo = NULL;
|
|
+ shared_info_any_t *live_shinfo = NULL;
|
|
+ unsigned int guest_width;
|
|
|
|
int nr_vcpus = 0;
|
|
char *dump_mem, *dump_mem_start = NULL;
|
|
@@ -437,6 +460,12 @@ xc_domain_dumpcore_via_callback(int xc_h
|
|
uint16_t strtab_idx;
|
|
struct xc_core_section_headers *sheaders = NULL;
|
|
Elf64_Shdr *shdr;
|
|
+
|
|
+ if ( get_guest_width(xc_handle, domid, &guest_width) != 0 )
|
|
+ {
|
|
+ PERROR("Could not get address size for domain");
|
|
+ return sts;
|
|
+ }
|
|
|
|
xc_core_arch_context_init(&arch_ctxt);
|
|
if ( (dump_mem_start = malloc(DUMP_INCREMENT*PAGE_SIZE)) == NULL )
|
|
@@ -500,7 +529,7 @@ xc_domain_dumpcore_via_callback(int xc_h
|
|
goto out;
|
|
}
|
|
|
|
- sts = xc_core_arch_map_p2m(xc_handle, &info, live_shinfo,
|
|
+ sts = xc_core_arch_map_p2m(xc_handle, guest_width, &info, live_shinfo,
|
|
&p2m, &p2m_size);
|
|
if ( sts != 0 )
|
|
goto out;
|
|
@@ -676,6 +705,7 @@ xc_domain_dumpcore_via_callback(int xc_h
|
|
/* write out elf header */
|
|
ehdr.e_shnum = sheaders->num;
|
|
ehdr.e_shstrndx = strtab_idx;
|
|
+ ehdr.e_machine = ELF_ARCH_MACHINE;
|
|
sts = dump_rtn(args, (char*)&ehdr, sizeof(ehdr));
|
|
if ( sts != 0 )
|
|
goto out;
|
|
@@ -697,7 +727,7 @@ xc_domain_dumpcore_via_callback(int xc_h
|
|
goto out;
|
|
|
|
/* elf note section: xen version */
|
|
- sts = elfnote_dump_xen_version(args, dump_rtn, xc_handle);
|
|
+ sts = elfnote_dump_xen_version(args, dump_rtn, xc_handle, guest_width);
|
|
if ( sts != 0 )
|
|
goto out;
|
|
|
|
@@ -757,9 +787,21 @@ xc_domain_dumpcore_via_callback(int xc_h
|
|
|
|
if ( !auto_translated_physmap )
|
|
{
|
|
- gmfn = p2m[i];
|
|
- if ( gmfn == INVALID_P2M_ENTRY )
|
|
- continue;
|
|
+ if ( guest_width >= sizeof(unsigned long) )
|
|
+ {
|
|
+ if ( guest_width == sizeof(unsigned long) )
|
|
+ gmfn = p2m[i];
|
|
+ else
|
|
+ gmfn = ((uint64_t *)p2m)[i];
|
|
+ if ( gmfn == INVALID_P2M_ENTRY )
|
|
+ continue;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ gmfn = ((uint32_t *)p2m)[i];
|
|
+ if ( gmfn == (uint32_t)INVALID_P2M_ENTRY )
|
|
+ continue;
|
|
+ }
|
|
|
|
p2m_array[j].pfn = i;
|
|
p2m_array[j].gmfn = gmfn;
|
|
@@ -802,7 +844,7 @@ copy_done:
|
|
/* When live dump-mode (-L option) is specified,
|
|
* guest domain may reduce memory. pad with zero pages.
|
|
*/
|
|
- IPRINTF("j (%ld) != nr_pages (%ld)", j , nr_pages);
|
|
+ IPRINTF("j (%ld) != nr_pages (%ld)", j, nr_pages);
|
|
memset(dump_mem_start, 0, PAGE_SIZE);
|
|
for (; j < nr_pages; j++) {
|
|
sts = dump_rtn(args, dump_mem_start, PAGE_SIZE);
|
|
@@ -891,7 +933,7 @@ xc_domain_dumpcore(int xc_handle,
|
|
struct dump_args da;
|
|
int sts;
|
|
|
|
- if ( (da.fd = open(corename, O_CREAT|O_RDWR, S_IWUSR|S_IRUSR)) < 0 )
|
|
+ if ( (da.fd = open(corename, O_CREAT|O_RDWR|O_TRUNC, S_IWUSR|S_IRUSR)) < 0 )
|
|
{
|
|
PERROR("Could not open corefile %s", corename);
|
|
return -errno;
|
|
Index: xen-3.3.1-testing/tools/libxc/xc_core.h
|
|
===================================================================
|
|
--- xen-3.3.1-testing.orig/tools/libxc/xc_core.h
|
|
+++ xen-3.3.1-testing/tools/libxc/xc_core.h
|
|
@@ -136,12 +136,12 @@ int xc_core_arch_auto_translated_physmap
|
|
struct xc_core_arch_context;
|
|
int xc_core_arch_memory_map_get(int xc_handle,
|
|
struct xc_core_arch_context *arch_ctxt,
|
|
- xc_dominfo_t *info, shared_info_t *live_shinfo,
|
|
+ xc_dominfo_t *info, shared_info_any_t *live_shinfo,
|
|
xc_core_memory_map_t **mapp,
|
|
unsigned int *nr_entries);
|
|
-int xc_core_arch_map_p2m(int xc_handle, xc_dominfo_t *info,
|
|
- shared_info_t *live_shinfo, xen_pfn_t **live_p2m,
|
|
- unsigned long *pfnp);
|
|
+int xc_core_arch_map_p2m(int xc_handle, unsigned int guest_width,
|
|
+ xc_dominfo_t *info, shared_info_any_t *live_shinfo,
|
|
+ xen_pfn_t **live_p2m, unsigned long *pfnp);
|
|
|
|
|
|
#if defined (__i386__) || defined (__x86_64__)
|
|
Index: xen-3.3.1-testing/tools/libxc/xc_core_ia64.c
|
|
===================================================================
|
|
--- xen-3.3.1-testing.orig/tools/libxc/xc_core_ia64.c
|
|
+++ xen-3.3.1-testing/tools/libxc/xc_core_ia64.c
|
|
@@ -270,7 +270,7 @@ old:
|
|
}
|
|
|
|
int
|
|
-xc_core_arch_map_p2m(int xc_handle, xc_dominfo_t *info,
|
|
+xc_core_arch_map_p2m(int xc_handle, unsigned int guest_width, xc_dominfo_t *info,
|
|
shared_info_t *live_shinfo, xen_pfn_t **live_p2m,
|
|
unsigned long *pfnp)
|
|
{
|
|
Index: xen-3.3.1-testing/tools/libxc/xc_core_x86.c
|
|
===================================================================
|
|
--- xen-3.3.1-testing.orig/tools/libxc/xc_core_x86.c
|
|
+++ xen-3.3.1-testing/tools/libxc/xc_core_x86.c
|
|
@@ -20,9 +20,25 @@
|
|
|
|
#include "xg_private.h"
|
|
#include "xc_core.h"
|
|
+#include "xc_e820.h"
|
|
+
|
|
+#define GET_FIELD(_p, _f) ((guest_width==8) ? ((_p)->x64._f) : ((_p)->x32._f))
|
|
+
|
|
+#ifndef MAX
|
|
+#define MAX(_a, _b) ((_a) >= (_b) ? (_a) : (_b))
|
|
+#endif
|
|
+
|
|
+int
|
|
+xc_core_arch_gpfn_may_present(struct xc_core_arch_context *arch_ctxt,
|
|
+ unsigned long pfn)
|
|
+{
|
|
+ if ((pfn >= 0xa0 && pfn < 0xc0) /* VGA hole */
|
|
+ || (pfn >= (HVM_BELOW_4G_MMIO_START >> PAGE_SHIFT)
|
|
+ && pfn < (1ULL<<32) >> PAGE_SHIFT)) /* MMIO */
|
|
+ return 0;
|
|
+ return 1;
|
|
+}
|
|
|
|
-/* Don't yet support cross-address-size core dump */
|
|
-#define guest_width (sizeof (unsigned long))
|
|
|
|
static int nr_gpfns(int xc_handle, domid_t domid)
|
|
{
|
|
@@ -37,7 +53,7 @@ xc_core_arch_auto_translated_physmap(con
|
|
|
|
int
|
|
xc_core_arch_memory_map_get(int xc_handle, struct xc_core_arch_context *unused,
|
|
- xc_dominfo_t *info, shared_info_t *live_shinfo,
|
|
+ xc_dominfo_t *info, shared_info_any_t *live_shinfo,
|
|
xc_core_memory_map_t **mapp,
|
|
unsigned int *nr_entries)
|
|
{
|
|
@@ -60,17 +76,22 @@ xc_core_arch_memory_map_get(int xc_handl
|
|
}
|
|
|
|
int
|
|
-xc_core_arch_map_p2m(int xc_handle, xc_dominfo_t *info,
|
|
- shared_info_t *live_shinfo, xen_pfn_t **live_p2m,
|
|
+xc_core_arch_map_p2m(int xc_handle, unsigned int guest_width, xc_dominfo_t *info,
|
|
+ shared_info_any_t *live_shinfo, xen_pfn_t **live_p2m,
|
|
unsigned long *pfnp)
|
|
{
|
|
/* Double and single indirect references to the live P2M table */
|
|
xen_pfn_t *live_p2m_frame_list_list = NULL;
|
|
xen_pfn_t *live_p2m_frame_list = NULL;
|
|
+ /* Copies of the above. */
|
|
+ xen_pfn_t *p2m_frame_list_list = NULL;
|
|
+ xen_pfn_t *p2m_frame_list = NULL;
|
|
+
|
|
uint32_t dom = info->domid;
|
|
unsigned long p2m_size = nr_gpfns(xc_handle, info->domid);
|
|
int ret = -1;
|
|
int err;
|
|
+ int i;
|
|
|
|
if ( p2m_size < info->nr_pages )
|
|
{
|
|
@@ -80,7 +101,7 @@ xc_core_arch_map_p2m(int xc_handle, xc_d
|
|
|
|
live_p2m_frame_list_list =
|
|
xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ,
|
|
- live_shinfo->arch.pfn_to_mfn_frame_list_list);
|
|
+ GET_FIELD(live_shinfo, arch.pfn_to_mfn_frame_list_list));
|
|
|
|
if ( !live_p2m_frame_list_list )
|
|
{
|
|
@@ -88,9 +109,28 @@ xc_core_arch_map_p2m(int xc_handle, xc_d
|
|
goto out;
|
|
}
|
|
|
|
+ /* Get a local copy of the live_P2M_frame_list_list */
|
|
+ if ( !(p2m_frame_list_list = malloc(PAGE_SIZE)) )
|
|
+ {
|
|
+ ERROR("Couldn't allocate p2m_frame_list_list array");
|
|
+ goto out;
|
|
+ }
|
|
+ memcpy(p2m_frame_list_list, live_p2m_frame_list_list, PAGE_SIZE);
|
|
+
|
|
+ /* Canonicalize guest's unsigned long vs ours */
|
|
+ if ( guest_width > sizeof(unsigned long) )
|
|
+ for ( i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++ )
|
|
+ if ( i < PAGE_SIZE/guest_width )
|
|
+ p2m_frame_list_list[i] = ((uint64_t *)p2m_frame_list_list)[i];
|
|
+ else
|
|
+ p2m_frame_list_list[i] = 0;
|
|
+ else if ( guest_width < sizeof(unsigned long) )
|
|
+ for ( i = PAGE_SIZE/sizeof(unsigned long) - 1; i >= 0; i-- )
|
|
+ p2m_frame_list_list[i] = ((uint32_t *)p2m_frame_list_list)[i];
|
|
+
|
|
live_p2m_frame_list =
|
|
xc_map_foreign_pages(xc_handle, dom, PROT_READ,
|
|
- live_p2m_frame_list_list,
|
|
+ p2m_frame_list_list,
|
|
P2M_FLL_ENTRIES);
|
|
|
|
if ( !live_p2m_frame_list )
|
|
@@ -99,8 +139,25 @@ xc_core_arch_map_p2m(int xc_handle, xc_d
|
|
goto out;
|
|
}
|
|
|
|
+ /* Get a local copy of the live_P2M_frame_list */
|
|
+ if ( !(p2m_frame_list = malloc(P2M_TOOLS_FL_SIZE)) )
|
|
+ {
|
|
+ ERROR("Couldn't allocate p2m_frame_list array");
|
|
+ goto out;
|
|
+ }
|
|
+ memset(p2m_frame_list, 0, P2M_TOOLS_FL_SIZE);
|
|
+ memcpy(p2m_frame_list, live_p2m_frame_list, P2M_GUEST_FL_SIZE);
|
|
+
|
|
+ /* Canonicalize guest's unsigned long vs ours */
|
|
+ if ( guest_width > sizeof(unsigned long) )
|
|
+ for ( i = 0; i < P2M_FL_ENTRIES; i++ )
|
|
+ p2m_frame_list[i] = ((uint64_t *)p2m_frame_list)[i];
|
|
+ else if ( guest_width < sizeof(unsigned long) )
|
|
+ for ( i = P2M_FL_ENTRIES - 1; i >= 0; i-- )
|
|
+ p2m_frame_list[i] = ((uint32_t *)p2m_frame_list)[i];
|
|
+
|
|
*live_p2m = xc_map_foreign_pages(xc_handle, dom, PROT_READ,
|
|
- live_p2m_frame_list,
|
|
+ p2m_frame_list,
|
|
P2M_FL_ENTRIES);
|
|
|
|
if ( !*live_p2m )
|
|
@@ -122,6 +179,12 @@ out:
|
|
if ( live_p2m_frame_list )
|
|
munmap(live_p2m_frame_list, P2M_FLL_ENTRIES * PAGE_SIZE);
|
|
|
|
+ if ( p2m_frame_list_list )
|
|
+ free(p2m_frame_list_list);
|
|
+
|
|
+ if ( p2m_frame_list )
|
|
+ free(p2m_frame_list);
|
|
+
|
|
errno = err;
|
|
return ret;
|
|
}
|
|
Index: xen-3.3.1-testing/tools/libxc/xc_core_x86.h
|
|
===================================================================
|
|
--- xen-3.3.1-testing.orig/tools/libxc/xc_core_x86.h
|
|
+++ xen-3.3.1-testing/tools/libxc/xc_core_x86.h
|
|
@@ -21,15 +21,8 @@
|
|
#ifndef XC_CORE_X86_H
|
|
#define XC_CORE_X86_H
|
|
|
|
-#if defined(__i386__) || defined(__x86_64__)
|
|
#define ELF_ARCH_DATA ELFDATA2LSB
|
|
-#if defined (__i386__)
|
|
-# define ELF_ARCH_MACHINE EM_386
|
|
-#else
|
|
-# define ELF_ARCH_MACHINE EM_X86_64
|
|
-#endif
|
|
-#endif /* __i386__ or __x86_64__ */
|
|
-
|
|
+#define ELF_ARCH_MACHINE (guest_width == 8 ? EM_X86_64 : EM_386)
|
|
|
|
struct xc_core_arch_context {
|
|
/* nothing */
|
|
@@ -40,8 +33,10 @@ struct xc_core_arch_context {
|
|
#define xc_core_arch_context_get(arch_ctxt, ctxt, xc_handle, domid) \
|
|
(0)
|
|
#define xc_core_arch_context_dump(arch_ctxt, args, dump_rtn) (0)
|
|
-#define xc_core_arch_gpfn_may_present(arch_ctxt, i) (1)
|
|
|
|
+int
|
|
+xc_core_arch_gpfn_may_present(struct xc_core_arch_context *arch_ctxt,
|
|
+ unsigned long pfn);
|
|
static inline int
|
|
xc_core_arch_context_get_shdr(struct xc_core_arch_context *arch_ctxt,
|
|
struct xc_core_section_headers *sheaders,
|