diff --git a/hw/virtio-9p-debug.c b/hw/virtio-9p-debug.c
index 9230659..ee222db 100644
--- a/hw/virtio-9p-debug.c
+++ b/hw/virtio-9p-debug.c
@@ -29,92 +29,121 @@ static struct iovec *get_sg(V9fsPDU *pdu, int rx)
     return pdu->elem.out_sg;
 }
 
+static int get_sg_count(V9fsPDU *pdu, int rx)
+{
+    if (rx)
+        return pdu->elem.in_num;
+    return pdu->elem.out_num;
+
+}
+
 static void pprint_int8(V9fsPDU *pdu, int rx, size_t *offsetp,
                         const char *name)
 {
-    struct iovec *sg = get_sg(pdu, rx);
+    size_t copied;
+    int count = get_sg_count(pdu, rx);
     size_t offset = *offsetp;
+    struct iovec *sg = get_sg(pdu, rx);
     int8_t value;
 
-    BUG_ON((offset + sizeof(value)) > sg[0].iov_len);
+    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
 
-    memcpy(&value, sg[0].iov_base + offset, sizeof(value));
+    BUG_ON(copied != sizeof(value));
     offset += sizeof(value);
-
     fprintf(llogfile, "%s=0x%x", name, value);
-
     *offsetp = offset;
 }
 
 static void pprint_int16(V9fsPDU *pdu, int rx, size_t *offsetp,
                         const char *name)
 {
+    size_t copied;
+    int count = get_sg_count(pdu, rx);
     struct iovec *sg = get_sg(pdu, rx);
     size_t offset = *offsetp;
     int16_t value;
 
-    BUG_ON((offset + sizeof(value)) > sg[0].iov_len);
 
-    memcpy(&value, sg[0].iov_base + offset, sizeof(value));
-    offset += sizeof(value);
+    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
 
+    BUG_ON(copied != sizeof(value));
+    offset += sizeof(value);
     fprintf(llogfile, "%s=0x%x", name, value);
-
     *offsetp = offset;
 }
 
 static void pprint_int32(V9fsPDU *pdu, int rx, size_t *offsetp,
                         const char *name)
 {
+    size_t copied;
+    int count = get_sg_count(pdu, rx);
     struct iovec *sg = get_sg(pdu, rx);
     size_t offset = *offsetp;
     int32_t value;
 
-    BUG_ON((offset + sizeof(value)) > sg[0].iov_len);
 
-    memcpy(&value, sg[0].iov_base + offset, sizeof(value));
-    offset += sizeof(value);
+    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
 
+    BUG_ON(copied != sizeof(value));
+    offset += sizeof(value);
     fprintf(llogfile, "%s=0x%x", name, value);
-
     *offsetp = offset;
 }
 
 static void pprint_int64(V9fsPDU *pdu, int rx, size_t *offsetp,
                         const char *name)
 {
+    size_t copied;
+    int count = get_sg_count(pdu, rx);
     struct iovec *sg = get_sg(pdu, rx);
     size_t offset = *offsetp;
     int64_t value;
 
-    BUG_ON((offset + sizeof(value)) > sg[0].iov_len);
 
-    memcpy(&value, sg[0].iov_base + offset, sizeof(value));
-    offset += sizeof(value);
+    copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value));
 
+    BUG_ON(copied != sizeof(value));
+    offset += sizeof(value);
     fprintf(llogfile, "%s=0x%" PRIx64, name, value);
-
     *offsetp = offset;
 }
 
 static void pprint_str(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
 {
+    int sg_count = get_sg_count(pdu, rx);
     struct iovec *sg = get_sg(pdu, rx);
     size_t offset = *offsetp;
-    int16_t size;
+    uint16_t tmp_size, size;
     size_t result;
+    size_t copied = 0;
+    int i = 0;
 
-    BUG_ON((offset + 2) > sg[0].iov_len);
-    memcpy(&size, sg[0].iov_base + offset, 2);
-    offset += 2;
+    /* get the size */
+    copied = do_pdu_unpack(&tmp_size, sg, sg_count, offset, sizeof(tmp_size));
+    BUG_ON(copied != sizeof(tmp_size));
+    size = le16_to_cpupu(&tmp_size);
+    offset += copied;
 
-    BUG_ON((offset + size) > sg[0].iov_len);
     fprintf(llogfile, "%s=", name);
-    result = fwrite(sg[0].iov_base + offset, 1, size, llogfile);
-    BUG_ON(result != size);
-    offset += size;
-
-    *offsetp = offset;
+    for (i = 0; size && i < sg_count; i++) {
+        size_t len;
+        if (offset >= sg[i].iov_len) {
+            /* skip this sg */
+            offset -= sg[i].iov_len;
+            continue;
+        } else {
+            len = MIN(sg[i].iov_len - offset, size);
+            result = fwrite(sg[i].iov_base + offset, 1, len, llogfile);
+            BUG_ON(result != len);
+            size -= len;
+            copied += len;
+            if (size) {
+                offset = 0;
+                continue;
+            }
+        }
+    }
+    *offsetp += copied;
 }
 
 static void pprint_qid(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c
index 3a5b3f0..1237bac 100644
--- a/hw/virtio-9p.c
+++ b/hw/virtio-9p.c
@@ -351,42 +351,51 @@ static void free_pdu(V9fsState *s, V9fsPDU *pdu)
     }
 }
 
-static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
-{
-    struct iovec *sg = pdu->elem.out_sg;
-    BUG_ON((offset + size) > sg[0].iov_len);
-    memcpy(dst, sg[0].iov_base + offset, size);
-    return size;
-}
-
-/* FIXME i can do this with less variables */
-static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
-							size_t size)
+size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
+                        size_t offset, size_t size, int pack)
 {
-    struct iovec *sg = pdu->elem.in_sg;
-    size_t off = 0;
-    size_t copied = 0;
     int i = 0;
+    size_t copied = 0;
 
-    for (i = 0; size && i < pdu->elem.in_num; i++) {
+    for (i = 0; size && i < sg_count; i++) {
         size_t len;
+        if (offset >= sg[i].iov_len) {
+            /* skip this sg */
+            offset -= sg[i].iov_len;
+            continue;
+        } else {
 
-        if (offset >= off && offset < (off + sg[i].iov_len)) {
-            len = MIN(sg[i].iov_len - (offset - off), size);
-            memcpy(sg[i].iov_base + (offset - off), src, len);
+            len = MIN(sg[i].iov_len - offset, size);
+            if (pack) {
+                memcpy(sg[i].iov_base + offset, addr, len);
+            } else {
+                memcpy(addr, sg[i].iov_base + offset, len);
+            }
             size -= len;
-            offset += len;
-            off = offset;
             copied += len;
-            src += len;
-        } else {
-            off += sg[i].iov_len;
+            addr += len;
+            if (size) {
+                offset = 0;
+                continue;
+            }
         }
     }
-
     return copied;
 }
 
+static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
+{
+    return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
+                         offset, size, 0);
+}
+
+static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
+							size_t size)
+{
+    return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
+                             offset, size, 1);
+}
+
 static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
 {
     size_t pos = 0;
diff --git a/hw/virtio-9p.h b/hw/virtio-9p.h
index da0aa64..81c2c59 100644
--- a/hw/virtio-9p.h
+++ b/hw/virtio-9p.h
@@ -187,5 +187,14 @@ typedef struct V9fsPosixFileOpertions
 } V9fsPosixFileOperations;
 
 V9fsPosixFileOperations *virtio_9p_init_local(const char *path);
+extern size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
+                            size_t offset, size_t size, int pack);
+
+static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
+                        size_t offset, size_t size)
+{
+    return pdu_packunpack(dst, sg, sg_count, offset, size, 0);
+}
+
 
 #endif
