tools/misc: introduce xen-mfndump.

A little development and debugging tool, useful when looking
for information about MFN to PFN mappings, MFN/PFN mappings
in a guest's PTEs, etc.

This is what it can do as of now:

$ /usr/sbin/xen-mfndump
Usage: xen-mfndump <command> [args]
Commands:
  help                      show this help
  dump-m2p                  show M2P
  dump-p2m    <domid>       show P2M of <domid>
  dump-ptes   <domid> <mfn> show the PTEs in <mfn>
  lookup-pte  <domid> <mfn> find the PTE mapping <mfn>
  memcmp-mfns <domid1> <mfn1> <domid2> <mfn2>
                            (str)compare content of <mfn1> & <mfn2>

Signed-off-by: Dario Faggioli <dario.faggioli@citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
Dario Faggioli authored and Ian Campbell committed 2013-09-13 13:10:10 +01:00
1 parent 266abb2407
commit ae763e4224
2 files changed
+430 -2

No files matched your search

+5 -2
View File
@@ -10,7 +10,7 @@ CFLAGS += $(CFLAGS_libxenstore)
HDRS = $(wildcard *.h)
TARGETS-y := xenperf xenpm xen-tmem-list-parse gtraceview gtracestat xenlockprof xenwatchdogd xencov
TARGETS-$(CONFIG_X86) += xen-detect xen-hvmctx xen-hvmcrash xen-lowmemd
TARGETS-$(CONFIG_X86) += xen-detect xen-hvmctx xen-hvmcrash xen-lowmemd xen-mfndump
TARGETS-$(CONFIG_MIGRATE) += xen-hptool
TARGETS := $(TARGETS-y)
@@ -22,7 +22,7 @@ INSTALL_BIN := $(INSTALL_BIN-y)
INSTALL_SBIN-y := xen-bugtool xen-python-path xenperf xenpm xen-tmem-list-parse gtraceview \
gtracestat xenlockprof xenwatchdogd xen-ringwatch xencov
INSTALL_SBIN-$(CONFIG_X86) += xen-hvmctx xen-hvmcrash xen-lowmemd
INSTALL_SBIN-$(CONFIG_X86) += xen-hvmctx xen-hvmcrash xen-lowmemd xen-mfndump
INSTALL_SBIN-$(CONFIG_MIGRATE) += xen-hptool
INSTALL_SBIN := $(INSTALL_SBIN-y)
@@ -75,6 +75,9 @@ xenlockprof: xenlockprof.o
xen-hptool: xen-hptool.o
$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(LDLIBS_libxenguest) $(LDLIBS_libxenstore) $(APPEND_LDFLAGS)
xen-mfndump: xen-mfndump.o
$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(LDLIBS_libxenguest) $(LDLIBS_libxenstore) $(APPEND_LDFLAGS)
xenwatchdogd: xenwatchdogd.o
$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS)
+425
View File
@@ -0,0 +1,425 @@
#include <xenctrl.h>
#include <xc_private.h>
#include <xc_core.h>
#include <errno.h>
#include <unistd.h>
#include "xg_save_restore.h"
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
static xc_interface *xch;
int help_func(int argc, char *argv[])
{
fprintf(stderr,
"Usage: xen-mfndump <command> [args]\n"
"Commands:\n"
" help show this help\n"
" dump-m2p show M2P\n"
" dump-p2m <domid> show P2M of <domid>\n"
" dump-ptes <domid> <mfn> show the PTEs in <mfn>\n"
" lookup-pte <domid> <mfn> find the PTE mapping <mfn>\n"
" memcmp-mfns <domid1> <mfn1> <domid2> <mfn2>\n"
" compare content of <mfn1> & <mfn2>\n"
);
return 0;
}
int dump_m2p_func(int argc, char *argv[])
{
unsigned long i, max_mfn;
xen_pfn_t *m2p_table;
if ( argc > 0 )
{
help_func(0, NULL);
return 1;
}
/* Map M2P and obtain gpfn */
max_mfn = xc_maximum_ram_page(xch);
if ( !(m2p_table = xc_map_m2p(xch, max_mfn, PROT_READ, NULL)) )
{
ERROR("Failed to map live M2P table");
return -1;
}
printf(" --- Dumping M2P ---\n");
printf(" Max MFN: %lu\n", max_mfn);
for ( i = 0; i < max_mfn; i++ )
{
printf(" mfn=0x%lx ==> pfn=0x%lx\n", i, m2p_table[i]);
}
printf(" --- End of M2P ---\n");
munmap(m2p_table, M2P_SIZE(max_mfn));
return 0;
}
int dump_p2m_func(int argc, char *argv[])
{
struct xc_domain_meminfo minfo;
xc_dominfo_t info;
unsigned long i;
int domid;
if ( argc < 1 )
{
help_func(0, NULL);
return 1;
}
domid = atoi(argv[0]);
if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 ||
info.domid != domid )
{
ERROR("Failed to obtain info for domain %d\n", domid);
return -1;
}
/* Retrieve all the info about the domain's memory */
memset(&minfo, 0, sizeof(minfo));
if ( xc_map_domain_meminfo(xch, domid, &minfo) )
{
ERROR("Could not map domain %d memory information\n", domid);
return -1;
}
printf(" --- Dumping P2M for domain %d ---\n", domid);
printf(" Guest Width: %u, PT Levels: %u P2M size: = %lu\n",
minfo.guest_width, minfo.pt_levels, minfo.p2m_size);
for ( i = 0; i < minfo.p2m_size; i++ )
{
unsigned long pagetype = minfo.pfn_type[i] &
XEN_DOMCTL_PFINFO_LTAB_MASK;
printf(" pfn=0x%lx ==> mfn=0x%lx (type 0x%lx)", i, minfo.p2m_table[i],
pagetype >> XEN_DOMCTL_PFINFO_LTAB_SHIFT);
if ( is_mapped(minfo.p2m_table[i]) )
printf(" [mapped]");
if ( pagetype & XEN_DOMCTL_PFINFO_LPINTAB )
printf (" [pinned]");
if ( pagetype == XEN_DOMCTL_PFINFO_XTAB )
printf(" [xtab]");
if ( pagetype == XEN_DOMCTL_PFINFO_BROKEN )
printf(" [broken]");
if ( pagetype == XEN_DOMCTL_PFINFO_XALLOC )
printf( " [xalloc]");
switch ( pagetype & XEN_DOMCTL_PFINFO_LTABTYPE_MASK )
{
case XEN_DOMCTL_PFINFO_L1TAB:
printf(" L1 table");
break;
case XEN_DOMCTL_PFINFO_L2TAB:
printf(" L2 table");
break;
case XEN_DOMCTL_PFINFO_L3TAB:
printf(" L3 table");
break;
case XEN_DOMCTL_PFINFO_L4TAB:
printf(" L4 table");
break;
}
printf("\n");
}
printf(" --- End of P2M for domain %d ---\n", domid);
xc_unmap_domain_meminfo(xch, &minfo);
return 0;
}
int dump_ptes_func(int argc, char *argv[])
{
struct xc_domain_meminfo minfo;
xc_dominfo_t info;
void *page = NULL;
unsigned long i, max_mfn;
int domid, pte_num, rc = 0;
xen_pfn_t pfn, mfn, *m2p_table;
if ( argc < 2 )
{
help_func(0, NULL);
return 1;
}
domid = atoi(argv[0]);
mfn = strtoul(argv[1], NULL, 16);
if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 ||
info.domid != domid )
{
ERROR("Failed to obtain info for domain %d\n", domid);
return -1;
}
/* Retrieve all the info about the domain's memory */
memset(&minfo, 0, sizeof(minfo));
if ( xc_map_domain_meminfo(xch, domid, &minfo) )
{
ERROR("Could not map domain %d memory information\n", domid);
return -1;
}
/* Map M2P and obtain gpfn */
max_mfn = xc_maximum_ram_page(xch);
if ( (mfn > max_mfn) ||
!(m2p_table = xc_map_m2p(xch, max_mfn, PROT_READ, NULL)) )
{
xc_unmap_domain_meminfo(xch, &minfo);
ERROR("Failed to map live M2P table");
return -1;
}
pfn = m2p_table[mfn];
if ( pfn >= minfo.p2m_size )
{
ERROR("pfn 0x%lx out of range for domain %d\n", pfn, domid);
rc = -1;
goto out;
}
if ( !(minfo.pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) )
{
ERROR("pfn 0x%lx for domain %d is not a PT\n", pfn, domid);
rc = -1;
goto out;
}
page = xc_map_foreign_range(xch, domid, PAGE_SIZE, PROT_READ,
minfo.p2m_table[pfn]);
if ( !page )
{
ERROR("Failed to map 0x%lx\n", minfo.p2m_table[pfn]);
rc = -1;
goto out;
}
pte_num = PAGE_SIZE / 8;
printf(" --- Dumping %d PTEs for domain %d ---\n", pte_num, domid);
printf(" Guest Width: %u, PT Levels: %u P2M size: = %lu\n",
minfo.guest_width, minfo.pt_levels, minfo.p2m_size);
printf(" pfn: 0x%lx, mfn: 0x%lx",
pfn, minfo.p2m_table[pfn]);
switch ( minfo.pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK )
{
case XEN_DOMCTL_PFINFO_L1TAB:
printf(", L1 table");
break;
case XEN_DOMCTL_PFINFO_L2TAB:
printf(", L2 table");
break;
case XEN_DOMCTL_PFINFO_L3TAB:
printf(", L3 table");
break;
case XEN_DOMCTL_PFINFO_L4TAB:
printf(", L4 table");
break;
}
if ( minfo.pfn_type[pfn] & XEN_DOMCTL_PFINFO_LPINTAB )
printf (" [pinned]");
if ( is_mapped(minfo.p2m_table[pfn]) )
printf(" [mapped]");
printf("\n");
for ( i = 0; i < pte_num; i++ )
printf(" pte[%lu]: 0x%lx\n", i, ((const uint64_t*)page)[i]);
printf(" --- End of PTEs for domain %d, pfn=0x%lx (mfn=0x%lx) ---\n",
domid, pfn, minfo.p2m_table[pfn]);
out:
munmap(page, PAGE_SIZE);
xc_unmap_domain_meminfo(xch, &minfo);
munmap(m2p_table, M2P_SIZE(max_mfn));
return rc;
}
int lookup_pte_func(int argc, char *argv[])
{
struct xc_domain_meminfo minfo;
xc_dominfo_t info;
void *page = NULL;
unsigned long i, j;
int domid, pte_num;
xen_pfn_t mfn;
if ( argc < 2 )
{
help_func(0, NULL);
return 1;
}
domid = atoi(argv[0]);
mfn = strtoul(argv[1], NULL, 16);
if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 ||
info.domid != domid )
{
ERROR("Failed to obtain info for domain %d\n", domid);
return -1;
}
/* Retrieve all the info about the domain's memory */
memset(&minfo, 0, sizeof(minfo));
if ( xc_map_domain_meminfo(xch, domid, &minfo) )
{
ERROR("Could not map domain %d memory information\n", domid);
return -1;
}
pte_num = PAGE_SIZE / 8;
printf(" --- Lookig for PTEs mapping mfn 0x%lx for domain %d ---\n",
mfn, domid);
printf(" Guest Width: %u, PT Levels: %u P2M size: = %lu\n",
minfo.guest_width, minfo.pt_levels, minfo.p2m_size);
for ( i = 0; i < minfo.p2m_size; i++ )
{
if ( !(minfo.pfn_type[i] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) )
continue;
page = xc_map_foreign_range(xch, domid, PAGE_SIZE, PROT_READ,
minfo.p2m_table[i]);
if ( !page )
continue;
for ( j = 0; j < pte_num; j++ )
{
uint64_t pte = ((const uint64_t*)page)[j];
#define __MADDR_BITS_X86 ((minfo.guest_width == 8) ? 52 : 44)
#define __MFN_MASK_X86 ((1ULL << (__MADDR_BITS_X86 - PAGE_SHIFT_X86)) - 1)
if ( ((pte >> PAGE_SHIFT_X86) & __MFN_MASK_X86) == mfn)
printf(" 0x%lx <-- [0x%lx][%lu]: 0x%lx\n",
mfn, minfo.p2m_table[i], j, pte);
#undef __MADDR_BITS_X86
#undef __MFN_MASK_X8
}
munmap(page, PAGE_SIZE);
page = NULL;
}
xc_unmap_domain_meminfo(xch, &minfo);
return 1;
}
int memcmp_mfns_func(int argc, char *argv[])
{
xc_dominfo_t info1, info2;
void *page1 = NULL, *page2 = NULL;
int domid1, domid2;
xen_pfn_t mfn1, mfn2;
int rc = 0;
if ( argc < 4 )
{
help_func(0, NULL);
return 1;
}
domid1 = atoi(argv[0]);
domid2 = atoi(argv[2]);
mfn1 = strtoul(argv[1], NULL, 16);
mfn2 = strtoul(argv[3], NULL, 16);
if ( xc_domain_getinfo(xch, domid1, 1, &info1) != 1 ||
xc_domain_getinfo(xch, domid2, 1, &info2) != 1 ||
info1.domid != domid1 || info2.domid != domid2)
{
ERROR("Failed to obtain info for domains\n");
return -1;
}
page1 = xc_map_foreign_range(xch, domid1, PAGE_SIZE, PROT_READ, mfn1);
page2 = xc_map_foreign_range(xch, domid2, PAGE_SIZE, PROT_READ, mfn2);
if ( !page1 || !page2 )
{
ERROR("Failed to map either 0x%lx[dom %d] or 0x%lx[dom %d]\n",
mfn1, domid1, mfn2, domid2);
rc = -1;
goto out;
}
printf(" --- Comparing the content of 2 MFNs ---\n");
printf(" 1: 0x%lx[dom %d], 2: 0x%lx[dom %d]\n",
mfn1, domid1, mfn2, domid2);
printf(" memcpy(1, 2) = %d\n", memcmp(page1, page2, PAGE_SIZE));
out:
munmap(page1, PAGE_SIZE);
munmap(page2, PAGE_SIZE);
return rc;
}
struct {
const char *name;
int (*func)(int argc, char *argv[]);
} opts[] = {
{ "help", help_func },
{ "dump-m2p", dump_m2p_func },
{ "dump-p2m", dump_p2m_func },
{ "dump-ptes", dump_ptes_func },
{ "lookup-pte", lookup_pte_func },
{ "memcmp-mfns", memcmp_mfns_func},
};
int main(int argc, char *argv[])
{
int i, ret;
if (argc < 2)
{
help_func(0, NULL);
return 1;
}
xch = xc_interface_open(0, 0, 0);
if ( !xch )
{
ERROR("Failed to open an xc handler");
return 1;
}
for ( i = 0; i < ARRAY_SIZE(opts); i++ )
{
if ( !strncmp(opts[i].name, argv[1], strlen(argv[1])) )
break;
}
if ( i == ARRAY_SIZE(opts) )
{
fprintf(stderr, "Unknown option '%s'", argv[1]);
help_func(0, NULL);
return 1;
}
ret = opts[i].func(argc - 2, argv + 2);
xc_interface_close(xch);
return !!ret;
}
/*
* Local variables:
* mode: C
* c-set-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.