diff mbox

[RFC,14/14,v9] allow user to dump a fraction of the memory

Message ID 4F5FFEDE.8060606@cn.fujitsu.com
State New
Headers show

Commit Message

Wen Congyang March 14, 2012, 2:13 a.m. UTC
This API allows the user to limit how much memory to be dumped,
rather than forcing the user to dump all memory at once.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 dump.c           |  186 +++++++++++++++++++++++++++++++++++++++++++++---------
 hmp-commands.hx  |   14 +++-
 hmp.c            |   13 ++++-
 memory_mapping.c |   27 ++++++++
 memory_mapping.h |    3 +
 qapi-schema.json |    6 ++-
 qmp-commands.hx  |    8 ++-
 7 files changed, 220 insertions(+), 37 deletions(-)

Comments

Luiz Capitulino March 14, 2012, 5:20 p.m. UTC | #1
On Wed, 14 Mar 2012 10:13:50 +0800
Wen Congyang <wency@cn.fujitsu.com> wrote:

> This API allows the user to limit how much memory to be dumped,
> rather than forcing the user to dump all memory at once.
> 
> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
> ---
>  dump.c           |  186 +++++++++++++++++++++++++++++++++++++++++++++---------
>  hmp-commands.hx  |   14 +++-
>  hmp.c            |   13 ++++-
>  memory_mapping.c |   27 ++++++++
>  memory_mapping.h |    3 +
>  qapi-schema.json |    6 ++-
>  qmp-commands.hx  |    8 ++-
>  7 files changed, 220 insertions(+), 37 deletions(-)
> 
> diff --git a/dump.c b/dump.c
> index 7f9ea09..cd65488 100644
> --- a/dump.c
> +++ b/dump.c
> @@ -83,6 +83,12 @@ typedef struct DumpState {
>      write_core_dump_function f;
>      void (*cleanup)(void *opaque);
>      void *opaque;
> +
> +    RAMBlock *block;
> +    ram_addr_t start;
> +    bool has_filter;
> +    int64_t begin;
> +    int64_t length;
>  } DumpState;
>  
>  static DumpState *dump_get_current(void)
> @@ -389,24 +395,30 @@ static int write_data(DumpState *s, void *buf, int length,
>  }
>  
>  /* write the memroy to vmcore. 1 page per I/O. */
> -static int write_memory(DumpState *s, RAMBlock *block,
> -                        target_phys_addr_t *offset)
> +static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start,
> +                        target_phys_addr_t *offset, int64_t *size)
>  {
>      int i, ret;
> +    int64_t writen_size = 0;
>  
> -    for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
> -        ret = write_data(s, block->host + i * TARGET_PAGE_SIZE,
> +    *size = block->length - start;
> +    for (i = 0; i < *size / TARGET_PAGE_SIZE; i++) {
> +        ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE,
>                           TARGET_PAGE_SIZE, offset);
>          if (ret < 0) {
> -            return -1;
> +            *size = writen_size;
> +            return ret;
>          }
> +
> +        writen_size += TARGET_PAGE_SIZE;
>      }
>  
> -    if ((block->length % TARGET_PAGE_SIZE) != 0) {
> -        ret = write_data(s, block->host + i * TARGET_PAGE_SIZE,
> -                         block->length % TARGET_PAGE_SIZE, offset);
> +    if ((*size % TARGET_PAGE_SIZE) != 0) {
> +        ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE,
> +                         *size % TARGET_PAGE_SIZE, offset);
>          if (ret < 0) {
> -            return -1;
> +            *size = writen_size;
> +            return ret;
>          }
>      }
>  
> @@ -415,17 +427,47 @@ static int write_memory(DumpState *s, RAMBlock *block,
>  
>  /* get the memory's offset in the vmcore */
>  static target_phys_addr_t get_offset(target_phys_addr_t phys_addr,
> -                                     target_phys_addr_t memory_offset)
> +                                     DumpState *s)
>  {
>      RAMBlock *block;
> -    target_phys_addr_t offset = memory_offset;
> +    target_phys_addr_t offset = s->memory_offset;
> +    int64_t size_in_block, start;
> +
> +    if (s->has_filter) {
> +        if (phys_addr < s->begin || phys_addr >= s->begin + s->length) {
> +            return -1;
> +        }
> +    }
>  
>      QLIST_FOREACH(block, &ram_list.blocks, next) {
> -        if (phys_addr >= block->offset &&
> -            phys_addr < block->offset + block->length) {
> -            return phys_addr - block->offset + offset;
> +        if (s->has_filter) {
> +            if (block->offset >= s->begin + s->length ||
> +                block->offset + block->length <= s->begin) {
> +                /* This block is out of the range */
> +                continue;
> +            }
> +
> +            if (s->begin <= block->offset) {
> +                start = block->offset;
> +            } else {
> +                start = s->begin;
> +            }
> +
> +            size_in_block = block->length - (start - block->offset);
> +            if (s->begin + s->length < block->offset + block->length) {
> +                size_in_block -= block->offset + block->length -
> +                                 (s->begin + s->length);
> +            }
> +        } else {
> +            start = block->offset;
> +            size_in_block = block->length;
>          }
> -        offset += block->length;
> +
> +        if (phys_addr >= start && phys_addr < start + size_in_block) {
> +            return phys_addr - start + offset;
> +        }
> +
> +        offset += size_in_block;
>      }
>  
>      return -1;
> @@ -512,7 +554,7 @@ static int dump_completed(DumpState *s)
>      int phdr_index = 1, ret;
>  
>      QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
> -        offset = get_offset(memory_mapping->phys_addr, s->memory_offset);
> +        offset = get_offset(memory_mapping->phys_addr, s);
>          if (s->dump_info.d_class == ELFCLASS64) {
>              ret = write_elf64_load(s, memory_mapping, phdr_index++, offset);
>          } else {
> @@ -528,22 +570,55 @@ static int dump_completed(DumpState *s)
>      return 0;
>  }
>  
> +static int get_next_block(DumpState *s, RAMBlock *block)
> +{
> +    while (1) {
> +        block = QLIST_NEXT(block, next);
> +        if (!block) {
> +            /* no more block */
> +            return 1;
> +        }
> +
> +        s->start = 0;
> +        s->block = block;
> +        if (s->has_filter) {
> +            if (block->offset >= s->begin + s->length ||
> +                block->offset + block->length <= s->begin) {
> +                /* This block is out of the range */
> +                continue;
> +            }
> +
> +            if (s->begin > block->offset) {
> +                s->start = s->begin - block->offset;
> +            }
> +        }
> +
> +        return 0;
> +    }
> +}
> +
>  /* write all memory to vmcore */
> -static int dump_iterate(DumpState *s)
> +static int dump_iterate(void *opaque)
>  {
> +    DumpState *s = opaque;
>      RAMBlock *block;
>      target_phys_addr_t offset = s->memory_offset;
> +    int64_t size;
>      int ret;
>  
> -    /* write all memory to vmcore */
> -    QLIST_FOREACH(block, &ram_list.blocks, next) {
> -        ret = write_memory(s, block, &offset);
> -        if (ret < 0) {
> -            return -1;
> +    while(1) {
> +        block = s->block;
> +        ret = write_memory(s, block, s->start, &offset, &size);
> +        if (ret == -1) {
> +            return ret;
>          }
> -    }
>  
> -    return dump_completed(s);
> +        ret = get_next_block(s, block);
> +        if (ret == 1) {
> +            dump_completed(s);
> +            return 0;
> +        }
> +    }
>  }
>  
>  static int create_vmcore(DumpState *s)
> @@ -563,7 +638,36 @@ static int create_vmcore(DumpState *s)
>      return 0;
>  }
>  
> -static DumpState *dump_init(bool paging, Error **errp)
> +static ram_addr_t get_start_block(DumpState *s)
> +{
> +    RAMBlock *block;
> +
> +    if (!s->has_filter) {
> +        s->block = QLIST_FIRST(&ram_list.blocks);
> +        return 0;
> +    }
> +
> +    QLIST_FOREACH(block, &ram_list.blocks, next) {
> +        if (block->offset >= s->begin + s->length ||
> +            block->offset + block->length <= s->begin) {
> +            /* This block is out of the range */
> +            continue;
> +        }
> +
> +        s->block = block;
> +        if (s->begin > block->offset ) {
> +            s->start = s->begin - block->offset;
> +        } else {
> +            s->start = 0;
> +        }
> +        return s->start;
> +    }
> +
> +    return -1;
> +}
> +
> +static DumpState *dump_init(bool paging, bool has_filter, int64_t begin,
> +                            int64_t length, Error **errp)
>  {
>      CPUState *env;
>      DumpState *s = dump_get_current();
> @@ -581,6 +685,15 @@ static DumpState *dump_init(bool paging, Error **errp)
>          s->error = NULL;
>      }
>  
> +    s->has_filter = has_filter;
> +    s->begin = begin;
> +    s->length = length;
> +    s->start = get_start_block(s);
> +    if (s->start == -1) {
> +        error_set(errp, QERR_INVALID_PARAMETER, "begin");

This will let the VM stopped.

> +        return NULL;
> +    }
> +
>      /*
>       * get dump info: endian, class and architecture.
>       * If the target architecture is not supported, cpu_get_dump_info() will
> @@ -607,6 +720,10 @@ static DumpState *dump_init(bool paging, Error **errp)
>          qemu_get_guest_simple_memory_mapping(&s->list);
>      }
>  
> +    if (s->has_filter) {
> +        memory_mapping_filter(&s->list, s->begin, s->length);
> +    }
> +
>      /*
>       * calculate phdr_num
>       *
> @@ -659,9 +776,10 @@ static void fd_cleanup(void *opaque)
>      }
>  }
>  
> -static DumpState *dump_init_fd(int fd, bool paging, Error **errp)
> +static DumpState *dump_init_fd(int fd, bool paging, bool has_filter,
> +                               int64_t begin, int64_t length, Error **errp)
>  {
> -    DumpState *s = dump_init(paging, errp);
> +    DumpState *s = dump_init(paging, has_filter, begin, length, errp);
>  
>      if (s == NULL) {
>          return NULL;
> @@ -674,12 +792,22 @@ static DumpState *dump_init_fd(int fd, bool paging, Error **errp)
>      return s;
>  }
>  
> -void qmp_dump(bool paging, const char *file, Error **errp)
> +void qmp_dump(bool paging, const char *file, bool has_begin,
> +              int64_t begin, bool has_length, int64_t length, Error **errp)
>  {
>      const char *p;
>      int fd = -1;
>      DumpState *s;
>  
> +    if (has_begin && !has_length) {
> +        error_set(errp, QERR_MISSING_PARAMETER, "length");
> +        return;
> +    }
> +    if (!has_begin && has_length) {
> +        error_set(errp, QERR_MISSING_PARAMETER, "begin");
> +        return;
> +    }
> +
>  #if !defined(WIN32)
>      if (strstart(file, "fd:", &p)) {
>          fd = qemu_get_fd(p);
> @@ -703,7 +831,7 @@ void qmp_dump(bool paging, const char *file, Error **errp)
>          return;
>      }
>  
> -    s = dump_init_fd(fd, paging, errp);
> +    s = dump_init_fd(fd, paging, has_begin, begin, length, errp);
>      if (!s) {
>          return;
>      }
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index abd412e..af0f112 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -883,21 +883,27 @@ ETEXI
>  #if defined(CONFIG_HAVE_CORE_DUMP)
>      {
>          .name       = "dump",
> -        .args_type  = "paging:-p,file:s",
> -        .params     = "[-p] file",
> -        .help       = "dump to file",
> +        .args_type  = "paging:-p,file:s,begin:i?,length:i?",
> +        .params     = "[-p] file [begin] [length]",
> +        .help       = "dump to file"
> +                      "\n\t\t\t begin(optional): the starting physical address"
> +                      "\n\t\t\t length(optional): the memory size, in bytes",
>          .user_print = monitor_user_noop,
>          .mhandler.cmd = hmp_dump,
>      },
>  
>  
>  STEXI
> -@item dump [-p] @var{file}
> +@item dump [-p] @var{file} @var{begin} @var{length}
>  @findex dump
>  Dump to @var{file}. The file can be processed with crash or gdb.
>      file: destination file(started with "file:") or destination file descriptor
>            (started with "fd:")
>    paging: do paging to get guest's memory mapping
> +   begin: the starting physical address. It's optional, and should be specified
> +          with length together.
> +  length: the memory size, in bytes. It's optional, and should be specified with
> +          begin together.
>  ETEXI
>  #endif
>  
> diff --git a/hmp.c b/hmp.c
> index d0aa94b..b399119 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -866,8 +866,19 @@ void hmp_dump(Monitor *mon, const QDict *qdict)
>      Error *errp = NULL;
>      int paging = qdict_get_try_bool(qdict, "paging", 0);
>      const char *file = qdict_get_str(qdict, "file");
> +    bool has_begin = qdict_haskey(qdict, "begin");
> +    bool has_length = qdict_haskey(qdict, "length");
> +    int64_t begin = 0;
> +    int64_t length = 0;
>  
> -    qmp_dump(!!paging, file, &errp);
> +    if (has_begin) {
> +        begin = qdict_get_int(qdict, "begin");
> +    }
> +    if (has_length) {
> +        length = qdict_get_int(qdict, "length");
> +    }
> +
> +    qmp_dump(!!paging, file, has_begin, begin, has_length, length, &errp);
>      hmp_handle_error(mon, &errp);
>  }
>  
> diff --git a/memory_mapping.c b/memory_mapping.c
> index 8dd0750..f2b8252 100644
> --- a/memory_mapping.c
> +++ b/memory_mapping.c
> @@ -209,3 +209,30 @@ void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list)
>          create_new_memory_mapping(list, block->offset, 0, block->length);
>      }
>  }
> +
> +void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
> +                           int64_t length)
> +{
> +    MemoryMapping *cur, *next;
> +
> +    QTAILQ_FOREACH_SAFE(cur, &list->head, next, next) {
> +        if (cur->phys_addr >= begin + length ||
> +            cur->phys_addr + cur->length <= begin) {
> +            QTAILQ_REMOVE(&list->head, cur, next);
> +            list->num--;
> +            continue;
> +        }
> +
> +        if (cur->phys_addr < begin) {
> +            cur->length -= begin - cur->phys_addr;
> +            if (cur->virt_addr) {
> +                cur->virt_addr += begin - cur->phys_addr;
> +            }
> +            cur->phys_addr = begin;
> +        }
> +
> +        if (cur->phys_addr + cur->length > begin + length) {
> +            cur->length -= cur->phys_addr + cur->length - begin - length;
> +        }
> +    }
> +}
> diff --git a/memory_mapping.h b/memory_mapping.h
> index 50b1f25..c5004ed 100644
> --- a/memory_mapping.h
> +++ b/memory_mapping.h
> @@ -55,4 +55,7 @@ int qemu_get_guest_memory_mapping(MemoryMappingList *list);
>  /* get guest's memory mapping without do paging(virtual address is 0). */
>  void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list);
>  
> +void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
> +                           int64_t length);
> +
>  #endif
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 9728f5f..cc42fa0 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -1671,12 +1671,16 @@
>  #
>  # @paging: if true, do paging to get guest's memory mapping
>  # @file: the filename or file descriptor of the vmcore.
> +# @begin: if specified, the starting physical address.
> +# @length: if specified, the memory size, in bytes.

'begin' and 'length' are optionals and have to be marked as such (look
in qapi-schema.json for examples).

Also, I would squash this patch into 11/14.

>  #
>  # Returns: nothing on success
>  #
>  # Since: 1.1
>  ##
> -{ 'command': 'dump', 'data': { 'paging': 'bool', 'file': 'str' } }
> +{ 'command': 'dump',
> +  'data': { 'paging': 'bool', 'file': 'str', '*begin': 'int',
> +            '*length': 'int' } }
>  
>  ##
>  # @dump_cancel
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index 036e111..738fff8 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -589,8 +589,8 @@ EQMP
>  #if defined(CONFIG_HAVE_CORE_DUMP)
>      {
>          .name       = "dump",
> -        .args_type  = "paging:-p,file:s",
> -        .params     = "[-p] file",
> +        .args_type  = "paging:-p,file:s,begin:i?,end:i?",
> +        .params     = "[-p] file [begin] [length]",
>          .help       = "dump to file",
>          .user_print = monitor_user_noop,
>          .mhandler.cmd_new = qmp_marshal_input_dump,
> @@ -607,6 +607,10 @@ Arguments:
>  - "paging": do paging to get guest's memory mapping (json-bool)
>  - "file": destination file(started with "file:") or destination file descriptor
>            (started with "fd:") (json-string)
> +- "begin": the starting physical address. It's optional, and should be specified
> +           with length together (json-int)
> +- "length": the memory size, in bytes. It's optional, and should be specified
> +            with begin together (json-int)
>  
>  Example:
>
diff mbox

Patch

diff --git a/dump.c b/dump.c
index 7f9ea09..cd65488 100644
--- a/dump.c
+++ b/dump.c
@@ -83,6 +83,12 @@  typedef struct DumpState {
     write_core_dump_function f;
     void (*cleanup)(void *opaque);
     void *opaque;
+
+    RAMBlock *block;
+    ram_addr_t start;
+    bool has_filter;
+    int64_t begin;
+    int64_t length;
 } DumpState;
 
 static DumpState *dump_get_current(void)
@@ -389,24 +395,30 @@  static int write_data(DumpState *s, void *buf, int length,
 }
 
 /* write the memroy to vmcore. 1 page per I/O. */
-static int write_memory(DumpState *s, RAMBlock *block,
-                        target_phys_addr_t *offset)
+static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start,
+                        target_phys_addr_t *offset, int64_t *size)
 {
     int i, ret;
+    int64_t writen_size = 0;
 
-    for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
-        ret = write_data(s, block->host + i * TARGET_PAGE_SIZE,
+    *size = block->length - start;
+    for (i = 0; i < *size / TARGET_PAGE_SIZE; i++) {
+        ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE,
                          TARGET_PAGE_SIZE, offset);
         if (ret < 0) {
-            return -1;
+            *size = writen_size;
+            return ret;
         }
+
+        writen_size += TARGET_PAGE_SIZE;
     }
 
-    if ((block->length % TARGET_PAGE_SIZE) != 0) {
-        ret = write_data(s, block->host + i * TARGET_PAGE_SIZE,
-                         block->length % TARGET_PAGE_SIZE, offset);
+    if ((*size % TARGET_PAGE_SIZE) != 0) {
+        ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE,
+                         *size % TARGET_PAGE_SIZE, offset);
         if (ret < 0) {
-            return -1;
+            *size = writen_size;
+            return ret;
         }
     }
 
@@ -415,17 +427,47 @@  static int write_memory(DumpState *s, RAMBlock *block,
 
 /* get the memory's offset in the vmcore */
 static target_phys_addr_t get_offset(target_phys_addr_t phys_addr,
-                                     target_phys_addr_t memory_offset)
+                                     DumpState *s)
 {
     RAMBlock *block;
-    target_phys_addr_t offset = memory_offset;
+    target_phys_addr_t offset = s->memory_offset;
+    int64_t size_in_block, start;
+
+    if (s->has_filter) {
+        if (phys_addr < s->begin || phys_addr >= s->begin + s->length) {
+            return -1;
+        }
+    }
 
     QLIST_FOREACH(block, &ram_list.blocks, next) {
-        if (phys_addr >= block->offset &&
-            phys_addr < block->offset + block->length) {
-            return phys_addr - block->offset + offset;
+        if (s->has_filter) {
+            if (block->offset >= s->begin + s->length ||
+                block->offset + block->length <= s->begin) {
+                /* This block is out of the range */
+                continue;
+            }
+
+            if (s->begin <= block->offset) {
+                start = block->offset;
+            } else {
+                start = s->begin;
+            }
+
+            size_in_block = block->length - (start - block->offset);
+            if (s->begin + s->length < block->offset + block->length) {
+                size_in_block -= block->offset + block->length -
+                                 (s->begin + s->length);
+            }
+        } else {
+            start = block->offset;
+            size_in_block = block->length;
         }
-        offset += block->length;
+
+        if (phys_addr >= start && phys_addr < start + size_in_block) {
+            return phys_addr - start + offset;
+        }
+
+        offset += size_in_block;
     }
 
     return -1;
@@ -512,7 +554,7 @@  static int dump_completed(DumpState *s)
     int phdr_index = 1, ret;
 
     QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
-        offset = get_offset(memory_mapping->phys_addr, s->memory_offset);
+        offset = get_offset(memory_mapping->phys_addr, s);
         if (s->dump_info.d_class == ELFCLASS64) {
             ret = write_elf64_load(s, memory_mapping, phdr_index++, offset);
         } else {
@@ -528,22 +570,55 @@  static int dump_completed(DumpState *s)
     return 0;
 }
 
+static int get_next_block(DumpState *s, RAMBlock *block)
+{
+    while (1) {
+        block = QLIST_NEXT(block, next);
+        if (!block) {
+            /* no more block */
+            return 1;
+        }
+
+        s->start = 0;
+        s->block = block;
+        if (s->has_filter) {
+            if (block->offset >= s->begin + s->length ||
+                block->offset + block->length <= s->begin) {
+                /* This block is out of the range */
+                continue;
+            }
+
+            if (s->begin > block->offset) {
+                s->start = s->begin - block->offset;
+            }
+        }
+
+        return 0;
+    }
+}
+
 /* write all memory to vmcore */
-static int dump_iterate(DumpState *s)
+static int dump_iterate(void *opaque)
 {
+    DumpState *s = opaque;
     RAMBlock *block;
     target_phys_addr_t offset = s->memory_offset;
+    int64_t size;
     int ret;
 
-    /* write all memory to vmcore */
-    QLIST_FOREACH(block, &ram_list.blocks, next) {
-        ret = write_memory(s, block, &offset);
-        if (ret < 0) {
-            return -1;
+    while(1) {
+        block = s->block;
+        ret = write_memory(s, block, s->start, &offset, &size);
+        if (ret == -1) {
+            return ret;
         }
-    }
 
-    return dump_completed(s);
+        ret = get_next_block(s, block);
+        if (ret == 1) {
+            dump_completed(s);
+            return 0;
+        }
+    }
 }
 
 static int create_vmcore(DumpState *s)
@@ -563,7 +638,36 @@  static int create_vmcore(DumpState *s)
     return 0;
 }
 
-static DumpState *dump_init(bool paging, Error **errp)
+static ram_addr_t get_start_block(DumpState *s)
+{
+    RAMBlock *block;
+
+    if (!s->has_filter) {
+        s->block = QLIST_FIRST(&ram_list.blocks);
+        return 0;
+    }
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (block->offset >= s->begin + s->length ||
+            block->offset + block->length <= s->begin) {
+            /* This block is out of the range */
+            continue;
+        }
+
+        s->block = block;
+        if (s->begin > block->offset ) {
+            s->start = s->begin - block->offset;
+        } else {
+            s->start = 0;
+        }
+        return s->start;
+    }
+
+    return -1;
+}
+
+static DumpState *dump_init(bool paging, bool has_filter, int64_t begin,
+                            int64_t length, Error **errp)
 {
     CPUState *env;
     DumpState *s = dump_get_current();
@@ -581,6 +685,15 @@  static DumpState *dump_init(bool paging, Error **errp)
         s->error = NULL;
     }
 
+    s->has_filter = has_filter;
+    s->begin = begin;
+    s->length = length;
+    s->start = get_start_block(s);
+    if (s->start == -1) {
+        error_set(errp, QERR_INVALID_PARAMETER, "begin");
+        return NULL;
+    }
+
     /*
      * get dump info: endian, class and architecture.
      * If the target architecture is not supported, cpu_get_dump_info() will
@@ -607,6 +720,10 @@  static DumpState *dump_init(bool paging, Error **errp)
         qemu_get_guest_simple_memory_mapping(&s->list);
     }
 
+    if (s->has_filter) {
+        memory_mapping_filter(&s->list, s->begin, s->length);
+    }
+
     /*
      * calculate phdr_num
      *
@@ -659,9 +776,10 @@  static void fd_cleanup(void *opaque)
     }
 }
 
-static DumpState *dump_init_fd(int fd, bool paging, Error **errp)
+static DumpState *dump_init_fd(int fd, bool paging, bool has_filter,
+                               int64_t begin, int64_t length, Error **errp)
 {
-    DumpState *s = dump_init(paging, errp);
+    DumpState *s = dump_init(paging, has_filter, begin, length, errp);
 
     if (s == NULL) {
         return NULL;
@@ -674,12 +792,22 @@  static DumpState *dump_init_fd(int fd, bool paging, Error **errp)
     return s;
 }
 
-void qmp_dump(bool paging, const char *file, Error **errp)
+void qmp_dump(bool paging, const char *file, bool has_begin,
+              int64_t begin, bool has_length, int64_t length, Error **errp)
 {
     const char *p;
     int fd = -1;
     DumpState *s;
 
+    if (has_begin && !has_length) {
+        error_set(errp, QERR_MISSING_PARAMETER, "length");
+        return;
+    }
+    if (!has_begin && has_length) {
+        error_set(errp, QERR_MISSING_PARAMETER, "begin");
+        return;
+    }
+
 #if !defined(WIN32)
     if (strstart(file, "fd:", &p)) {
         fd = qemu_get_fd(p);
@@ -703,7 +831,7 @@  void qmp_dump(bool paging, const char *file, Error **errp)
         return;
     }
 
-    s = dump_init_fd(fd, paging, errp);
+    s = dump_init_fd(fd, paging, has_begin, begin, length, errp);
     if (!s) {
         return;
     }
diff --git a/hmp-commands.hx b/hmp-commands.hx
index abd412e..af0f112 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -883,21 +883,27 @@  ETEXI
 #if defined(CONFIG_HAVE_CORE_DUMP)
     {
         .name       = "dump",
-        .args_type  = "paging:-p,file:s",
-        .params     = "[-p] file",
-        .help       = "dump to file",
+        .args_type  = "paging:-p,file:s,begin:i?,length:i?",
+        .params     = "[-p] file [begin] [length]",
+        .help       = "dump to file"
+                      "\n\t\t\t begin(optional): the starting physical address"
+                      "\n\t\t\t length(optional): the memory size, in bytes",
         .user_print = monitor_user_noop,
         .mhandler.cmd = hmp_dump,
     },
 
 
 STEXI
-@item dump [-p] @var{file}
+@item dump [-p] @var{file} @var{begin} @var{length}
 @findex dump
 Dump to @var{file}. The file can be processed with crash or gdb.
     file: destination file(started with "file:") or destination file descriptor
           (started with "fd:")
   paging: do paging to get guest's memory mapping
+   begin: the starting physical address. It's optional, and should be specified
+          with length together.
+  length: the memory size, in bytes. It's optional, and should be specified with
+          begin together.
 ETEXI
 #endif
 
diff --git a/hmp.c b/hmp.c
index d0aa94b..b399119 100644
--- a/hmp.c
+++ b/hmp.c
@@ -866,8 +866,19 @@  void hmp_dump(Monitor *mon, const QDict *qdict)
     Error *errp = NULL;
     int paging = qdict_get_try_bool(qdict, "paging", 0);
     const char *file = qdict_get_str(qdict, "file");
+    bool has_begin = qdict_haskey(qdict, "begin");
+    bool has_length = qdict_haskey(qdict, "length");
+    int64_t begin = 0;
+    int64_t length = 0;
 
-    qmp_dump(!!paging, file, &errp);
+    if (has_begin) {
+        begin = qdict_get_int(qdict, "begin");
+    }
+    if (has_length) {
+        length = qdict_get_int(qdict, "length");
+    }
+
+    qmp_dump(!!paging, file, has_begin, begin, has_length, length, &errp);
     hmp_handle_error(mon, &errp);
 }
 
diff --git a/memory_mapping.c b/memory_mapping.c
index 8dd0750..f2b8252 100644
--- a/memory_mapping.c
+++ b/memory_mapping.c
@@ -209,3 +209,30 @@  void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list)
         create_new_memory_mapping(list, block->offset, 0, block->length);
     }
 }
+
+void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
+                           int64_t length)
+{
+    MemoryMapping *cur, *next;
+
+    QTAILQ_FOREACH_SAFE(cur, &list->head, next, next) {
+        if (cur->phys_addr >= begin + length ||
+            cur->phys_addr + cur->length <= begin) {
+            QTAILQ_REMOVE(&list->head, cur, next);
+            list->num--;
+            continue;
+        }
+
+        if (cur->phys_addr < begin) {
+            cur->length -= begin - cur->phys_addr;
+            if (cur->virt_addr) {
+                cur->virt_addr += begin - cur->phys_addr;
+            }
+            cur->phys_addr = begin;
+        }
+
+        if (cur->phys_addr + cur->length > begin + length) {
+            cur->length -= cur->phys_addr + cur->length - begin - length;
+        }
+    }
+}
diff --git a/memory_mapping.h b/memory_mapping.h
index 50b1f25..c5004ed 100644
--- a/memory_mapping.h
+++ b/memory_mapping.h
@@ -55,4 +55,7 @@  int qemu_get_guest_memory_mapping(MemoryMappingList *list);
 /* get guest's memory mapping without do paging(virtual address is 0). */
 void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list);
 
+void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
+                           int64_t length);
+
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index 9728f5f..cc42fa0 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1671,12 +1671,16 @@ 
 #
 # @paging: if true, do paging to get guest's memory mapping
 # @file: the filename or file descriptor of the vmcore.
+# @begin: if specified, the starting physical address.
+# @length: if specified, the memory size, in bytes.
 #
 # Returns: nothing on success
 #
 # Since: 1.1
 ##
-{ 'command': 'dump', 'data': { 'paging': 'bool', 'file': 'str' } }
+{ 'command': 'dump',
+  'data': { 'paging': 'bool', 'file': 'str', '*begin': 'int',
+            '*length': 'int' } }
 
 ##
 # @dump_cancel
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 036e111..738fff8 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -589,8 +589,8 @@  EQMP
 #if defined(CONFIG_HAVE_CORE_DUMP)
     {
         .name       = "dump",
-        .args_type  = "paging:-p,file:s",
-        .params     = "[-p] file",
+        .args_type  = "paging:-p,file:s,begin:i?,end:i?",
+        .params     = "[-p] file [begin] [length]",
         .help       = "dump to file",
         .user_print = monitor_user_noop,
         .mhandler.cmd_new = qmp_marshal_input_dump,
@@ -607,6 +607,10 @@  Arguments:
 - "paging": do paging to get guest's memory mapping (json-bool)
 - "file": destination file(started with "file:") or destination file descriptor
           (started with "fd:") (json-string)
+- "begin": the starting physical address. It's optional, and should be specified
+           with length together (json-int)
+- "length": the memory size, in bytes. It's optional, and should be specified
+            with begin together (json-int)
 
 Example: