--- a/tools/libxc/xc_domain_save.c
+++ b/tools/libxc/xc_domain_save.c
@@ -215,27 +215,53 @@ static inline int outbuf_hardwrite(xc_in
 
 /* start buffering output once we've reached checkpoint mode. */
 static inline int write_buffer(xc_interface *xch,
+                               unsigned ln, int do_debug,
                                int dobuf, struct outbuf* ob, int fd, void* buf,
                                size_t len)
 {
+    int ret;
     if ( dobuf )
-        return outbuf_hardwrite(xch, ob, fd, buf, len);
+        ret = outbuf_hardwrite(xch, ob, fd, buf, len);
     else
-        return write_exact(fd, buf, len);
+        ret = write_exact(fd, buf, len);
+    if (0) /* FIXME for PTF */
+        do_debug = 0;
+    if ( do_debug ) {
+        if (len && (len & ~XC_PAGE_MASK) == 0)
+            DPRINTF("w %u p%zu", ln, len >> XC_PAGE_SHIFT);
+        else
+            DPRINTF("w %u b%zu", ln, len);
+    }
+    /* 0 == success, -1 == error */
+    return ret;
 }
 
 /* returns 0 for success, -1 for any error */
 static inline int write_uncached(xc_interface *xch,
+                                   unsigned ln, int do_debug,
                                    int dobuf, struct outbuf* ob, int fd,
                                    void* buf, size_t len)
 {
+    int ret;
     if ( dobuf )
-        return outbuf_hardwrite(xch, ob, fd, buf, len);
+        ret = outbuf_hardwrite(xch, ob, fd, buf, len);
     else
-        return noncached_write(xch, ob, fd, buf, len);
+        ret = noncached_write(xch, ob, fd, buf, len);
+    if (0) /* FIXME for PTF */
+        do_debug = 0;
+    if ( do_debug ) {
+        if (len && (len & ~XC_PAGE_MASK) == 0)
+            DPRINTF("w %u p%zu", ln, len >> XC_PAGE_SHIFT);
+        else
+            DPRINTF("w %u b%zu", ln, len);
+    }
+    /* 0 == success, -1 == error */
+    return ret;
 }
 
-static int write_compressed(xc_interface *xch, comp_ctx *compress_ctx,
+static int write_compressed(xc_interface *xch,
+                            unsigned ln, int do_debug,
+                            comp_ctx *compress_ctx,
                             int dobuf, struct outbuf* ob, int fd)
 {
     int rc = 0;
@@ -251,7 +277,8 @@ static int write_compressed(xc_interface
             if (outbuf_flush(xch, ob, fd) < 0)
             {
                 ERROR("Error when flushing outbuf intermediate");
-                return -1;
+                rc = -1;
+                goto out;
             }
         }
 
@@ -260,29 +287,36 @@ static int write_compressed(xc_interface
                                            ob->size - ob->pos - header,
                                            &compbuf_len);
         if (!rc)
-            break;
+            goto out;
 
         if (outbuf_hardwrite(xch, ob, fd, &marker, sizeof(marker)) < 0)
         {
             PERROR("Error when writing marker (errno %d)", errno);
-            return -1;
+            rc = -1;
+            goto out;
         }
 
         if (outbuf_hardwrite(xch, ob, fd, &compbuf_len, sizeof(compbuf_len)) < 0)
         {
             PERROR("Error when writing compbuf_len (errno %d)", errno);
-            return -1;
+            rc = -1;
+            goto out;
         }
 
         ob->pos += (size_t) compbuf_len;
         if (!dobuf && outbuf_flush(xch, ob, fd) < 0)
         {
             ERROR("Error when writing compressed chunk");
-            return -1;
+            rc = -1;
+            goto out;
         }
     }
 
-    return 0;
+out:
+    if (do_debug) {
+        DPRINTF("c %u rc %d", ln, rc);
+    }
+    return rc;
 }
 
 struct time_stats {
@@ -808,6 +842,36 @@ static int save_tsc_info(xc_interface *x
     return 0;
 }
 
+static const char path_pfn_debug[] = "/etc/xen/xc_domain_save_suse.pfn_debug";
+static const char path_debug[] = "/etc/xen/xc_domain_save_suse.debug";
+static void set_debug(xc_interface *xch, int *do_pfn_debug, int *debug, uint32_t flags)
+{
+    int debug_flags = 0, debug_path = 0, pfn_debug_path = 0;
+
+    *do_pfn_debug = *debug = 0;
+    if ( flags & XCFLAGS_DEBUG )
+    {
+        debug_flags = *debug = 1;
+    }
+    if ( access(path_debug, F_OK) == 0 )
+    {
+        debug_path = *debug = 1;
+    }
+    if ( access(path_pfn_debug, F_OK) == 0 )
+    {
+        pfn_debug_path = *do_pfn_debug = 1;
+    }
+    IPRINTF("xc_domain_save_suse: pfn_debug %s because '%s' does%s exist.",
+            *do_pfn_debug ? "ENABLED" : "DISABLED",
+            path_pfn_debug,
+            pfn_debug_path ? "" : " not");
+    IPRINTF("xc_domain_save_suse: debug %s because '%s' does%s exist, or debug is %s in flags.",
+            *debug ? "ENABLED" : "DISABLED",
+            path_debug,
+            debug_path ? "" : " not",
+            debug_flags ? "ENABLED" : "DISABLED");
+}
+
 int xc_domain_save_suse(xc_interface *xch, int io_fd, uint32_t dom, uint32_t max_iters,
                    uint32_t max_factor, uint32_t flags,
                    uint32_t min_remaining,
@@ -818,6 +882,8 @@ int xc_domain_save_suse(xc_interface *xc
     DECLARE_DOMCTL;
 
     int errnoval = 0;
+    int do_debug = 0;
+    int do_pfn_debug = 0;
     int rc = 1, frc, i, j, last_iter = 0, iter = 0;
     int live  = (flags & XCFLAGS_LIVE);
     int debug = (flags & XCFLAGS_DEBUG);
@@ -908,6 +974,8 @@ int xc_domain_save_suse(xc_interface *xc
 
     DPRINTF("%s: starting save of domid %u", __func__, dom);
 
+    set_debug(xch, &do_pfn_debug, &debug, flags);
+
     if ( hvm && !callbacks->switch_qemu_logdirty )
     {
         ERROR("No switch_qemu_logdirty callback provided.");
@@ -1138,16 +1206,19 @@ int xc_domain_save_suse(xc_interface *xc
     }
 
   copypages:
-#define wrexact(fd, buf, len) write_buffer(xch, last_iter, ob, (fd), (buf), (len))
-#define wruncached(fd, buf, len) write_uncached(xch, last_iter, ob, (fd), (buf), (len))
-#define wrcompressed(fd) write_compressed(xch, compress_ctx, last_iter, ob, (fd))
+#define wrexact(fd, buf, len) write_buffer(xch, __LINE__, do_debug, last_iter, ob, (fd), (buf), (len))
+#define wruncached(fd, buf, len) write_uncached(xch, __LINE__, do_debug, last_iter, ob, (fd), (buf), (len))
+#define wrcompressed(fd) write_compressed(xch, __LINE__, do_debug, compress_ctx, last_iter, ob, (fd))
 
     ob = &ob_pagebuf; /* Holds pfn_types, pages/compressed pages */
     /* Now write out each data page, canonicalising page tables as we go... */
     for ( ; ; )
     {
-        unsigned int N, batch, run;
+        unsigned long N;
+        unsigned int batch, run;
         char reportbuf[80];
+        do_debug = debug && iter < 1;
+        do_pfn_debug = do_pfn_debug && iter < 1;
 
         snprintf(reportbuf, sizeof(reportbuf),
                  "Saving memory: iter %d (last sent %u skipped %u)",
@@ -1185,18 +1256,23 @@ int xc_domain_save_suse(xc_interface *xc
                    (batch < MAX_BATCH_SIZE) && (N < dinfo->p2m_size);
                    N++ )
             {
-                int n = N;
+                unsigned long n = N;
 
-                if ( debug )
+                if ( do_pfn_debug )
                 {
-                    DPRINTF("%d pfn= %08lx mfn= %08lx %d",
-                            iter, (unsigned long)n,
-                            hvm ? 0 : pfn_to_mfn(n),
-                            test_bit(n, to_send));
-                    if ( !hvm && is_mapped(pfn_to_mfn(n)) )
-                        DPRINTF("  [mfn]= %08lx",
-                                mfn_to_pfn(pfn_to_mfn(n)&0xFFFFF));
-                    DPRINTF("\n");
+                    if ( hvm ) {
+                        DPRINTF("%d pfn=%08lx %d", iter, n, test_bit(n, to_send));
+                    } else {
+                        xen_pfn_t m = pfn_to_mfn(n);
+                        DPRINTF("%d %08lx %08lx %d%d%d%d",
+                                iter, n,
+                                m,
+                                test_bit(n, to_send),
+                                test_bit(n, to_skip),
+                                test_bit(n, to_fix),
+                                is_mapped(m)
+                               );
+                    }
                 }
 
                 if ( completed )
@@ -1262,6 +1338,8 @@ int xc_domain_save_suse(xc_interface *xc
                         ** unless its sent sooner anyhow, or it never enters
                         ** pseudo-physical map (e.g. for ballooned down doms)
                         */
+                        if ( do_pfn_debug )
+                            DPRINTF("not mapped %lx", n);
                         set_bit(n, to_fix);
                         continue;
                     }
@@ -1271,7 +1349,7 @@ int xc_domain_save_suse(xc_interface *xc
                          !test_bit(n, to_send) )
                     {
                         needed_to_fix++;
-                        DPRINTF("Fix! iter %d, pfn %x. mfn %lx\n",
+                        DPRINTF("Fix! iter %d, pfn %lx. mfn %lx\n",
                                 iter, n, pfn_type[batch]);
                     }
 
@@ -1282,7 +1360,10 @@ int xc_domain_save_suse(xc_interface *xc
             }
 
             if ( batch == 0 )
+            {
+                DPRINTF("empty batch at %lx", N);
                 goto skip; /* vanishingly unlikely... */
+            }
 
             region_base = xc_map_foreign_bulk(
                 xch, dom, PROT_READ, pfn_type, pfn_err, batch);
@@ -1339,6 +1420,7 @@ int xc_domain_save_suse(xc_interface *xc
                 pfn_type[j] |= pfn_batch[j];
                 ++run;
 
+                if ( 0 )
                 if ( debug )
                 {
                     if ( hvm )
@@ -1359,6 +1441,7 @@ int xc_domain_save_suse(xc_interface *xc
 
             if ( !run )
             {
+                DPRINTF("no run %lx", N);
                 munmap(region_base, batch*PAGE_SIZE);
                 continue; /* bail on this batch: no valid pages */
             }
@@ -1548,6 +1631,7 @@ int xc_domain_save_suse(xc_interface *xc
             DPRINTF("(of which %ld were fixups)\n", needed_to_fix  );
         }
 
+        if ( 0 )
         if ( last_iter && debug )
         {
             int id = XC_SAVE_ID_ENABLE_VERIFY_MODE;
@@ -1632,6 +1716,7 @@ int xc_domain_save_suse(xc_interface *xc
 
         }
     } /* end of infinite for loop */
+    do_debug = 1;
 
     DPRINTF("All memory is saved\n");
 
