Patchwork [2/3] QEMU-C-F: Introducing qemu userspace tool qemu-core-filter.

login
register
mail settings
Submitter Mahesh Salgaonkar
Date June 22, 2010, 4:01 a.m.
Message ID <20100622040154.GC27051@in.ibm.com>
Download mbox | patch
Permalink /patch/56396/
State New
Headers show

Comments

Mahesh Salgaonkar - June 22, 2010, 4:01 a.m.
Qemu userspace tool to filter out guest OS memory from qemu core file.
Use '--enable-core-filter' option while running ./configure script to build
qemu-core-filter tool. This is a post-processing tool works offline on qemu
coredumps. This tool helps to reuce the size of qemu core file (generated by
qemu crash) by removing guest OS memory from original core file.

Currently it is only supported for Linux on x86 and x86_64.

Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---

 Makefile           |    6 
 configure          |   72 ++
 create_config      |    3 
 qemu-core-filter.c | 1976 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-core-filter.h |  216 ++++++
 5 files changed, 2272 insertions(+), 1 deletions(-)
 create mode 100644 qemu-core-filter.c
 create mode 100644 qemu-core-filter.h
Anthony Liguori - June 22, 2010, 1:02 p.m.
Hrm, the way you've sent this patch makes Thunderbird unhappy.  It 
appears the whole thing is treated as an attachment.  In the future, I'd 
suggest avoiding the Content-Disposition tag

On 06/21/2010 11:01 PM, Mahesh Salgaonkar wrote:
> Qemu userspace tool to filter out guest OS memory from qemu core file.
> Use '--enable-core-filter' option while running ./configure script to build
> qemu-core-filter tool. This is a post-processing tool works offline on qemu
> coredumps. This tool helps to reuce the size of qemu core file (generated by
> qemu crash) by removing guest OS memory from original core file.
>
> Currently it is only supported for Linux on x86 and x86_64.
>    

There are a few problems with a tool like this.  The first is that it 
depends on very specific internals of qemu (namely, the way we allocate 
ram).  If we applied this, we would get subtle breakages if we made even 
the slightest changes to qemu.

IMHO, the value is also questionable.  There is quite a bit of sensitive 
data left in the core file after removing guest memory.  Any DMA buffer 
may contain very sensitive data (for instance, if you crash during a 
read of /etc/shadow).  Even the CPU registers can contain sensitive data.

I think the only really viable approach to this problem is to take a 
white list approach instead of a black list approach.  That means 
extracting useful information that we're reasonably confident preserves 
privacy.   That would be information like a back trace, the crash 
reason, etc.   Tools like apport and ABT already do exactly this and 
they also present an interface to the user to validate the data before 
sending it.  They also provide a way to collect other information (like 
host dmesg).

Regards,

Anthony Liguori
Mahesh Salgaonkar - June 25, 2010, 12:38 p.m.
On 06/22/2010 06:32 PM, Anthony Liguori wrote:
> Hrm, the way you've sent this patch makes Thunderbird unhappy.  It
> appears the whole thing is treated as an attachment. In the future, I'd
> suggest avoiding the Content-Disposition tag
>
Sure. I will take care of this in future.

> On 06/21/2010 11:01 PM, Mahesh Salgaonkar wrote:
>> Qemu userspace tool to filter out guest OS memory from qemu core file.
>> Use '--enable-core-filter' option while running ./configure script to
>> build
>> qemu-core-filter tool. This is a post-processing tool works offline on
>> qemu
>> coredumps. This tool helps to reuce the size of qemu core file
>> (generated by
>> qemu crash) by removing guest OS memory from original core file.
>>
>> Currently it is only supported for Linux on x86 and x86_64.
>
> There are a few problems with a tool like this. The first is that it
> depends on very specific internals of qemu (namely, the way we allocate
> ram). If we applied this, we would get subtle breakages if we made even
> the slightest changes to qemu.
>
This is the precise reason we would like to get this tool integrated 
into QEMU sources. So, whenever something changes in qemu, then this 
tool can be modified accordingly.

> IMHO, the value is also questionable. There is quite a bit of sensitive
> data left in the core file after removing guest memory. Any DMA buffer
> may contain very sensitive data (for instance, if you crash during a
> read of /etc/shadow). Even the CPU registers can contain sensitive data.
>
> I think the only really viable approach to this problem is to take a
> white list approach instead of a black list approach. That means
> extracting useful information that we're reasonably confident preserves
> privacy. That would be information like a back trace, the crash reason,
> etc. Tools like apport and ABT already do exactly this and they also
> present an interface to the user to validate the data before sending it.
> They also provide a way to collect other information (like host dmesg).
>
I understand your point but this tool can be of interest of people who 
sends out large coredump files to service centers for initial analysis. 
This tool will help them to reduce the size of core file before sending 
it to service centers for analysis. What do you think?

> Regards,
>
> Anthony Liguori

Regards,
-Mahesh.

Patch

diff --git a/Makefile b/Makefile
index 221fbd8..1174628 100644
--- a/Makefile
+++ b/Makefile
@@ -135,7 +135,8 @@  iov.o: iov.c iov.h
 ######################################################################
 
 qemu-img.o: qemu-img-cmds.h
-qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o: $(GENERATED_HEADERS)
+qemu-core-filter.o: qemu-core-filter.h
+qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o qemu-core-filter.o: $(GENERATED_HEADERS)
 
 qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y)
 
@@ -143,6 +144,8 @@  qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-
 
 qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y)
 
+qemu-core-filter$(EXESUF): qemu-core-filter.o
+
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")
 
@@ -324,6 +327,7 @@  tarbin:
 	$(patsubst %,$(bindir)/%, $(USER_PROGS)) \
 	$(bindir)/qemu-img \
 	$(bindir)/qemu-nbd \
+	$(bindir)/qemu-core-filter \
 	$(datadir)/bios.bin \
 	$(datadir)/vgabios.bin \
 	$(datadir)/vgabios-cirrus.bin \
diff --git a/configure b/configure
index c0d8aa5..7aa8189 100755
--- a/configure
+++ b/configure
@@ -271,6 +271,7 @@  vnc_sasl=""
 xen=""
 linux_aio=""
 vhost_net=""
+core_filter_tool="no"
 
 gprof="no"
 debug_tcg="no"
@@ -687,6 +688,10 @@  for opt do
   ;;
   --enable-vhost-net) vhost_net="yes"
   ;;
+  --disable-core-filter) core_filter_tool="no"
+  ;;
+  --enable-core-filter) core_filter_tool="yes"
+  ;;
   --*dir)
   ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
@@ -865,6 +870,8 @@  echo "  --enable-docs            enable documentation build"
 echo "  --disable-docs           disable documentation build"
 echo "  --disable-vhost-net      disable vhost-net acceleration support"
 echo "  --enable-vhost-net       enable vhost-net acceleration support"
+echo "  --disable-core-filter    do not build qemu-core-filter tool (default)"
+echo "  --enable-core-filter     build qemu-core-filter tool"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -1021,6 +1028,18 @@  case "$cpu" in
   ;;
 esac
 
+#########################################
+# qemu-core-filter tool for x86 and x86_64
+if test "$core_filter_tool" != "no"; then
+  if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \
+          "$targetos" == "Linux" ; then \
+    core_filter_tool=yes
+  else
+    echo -n "Currently qemu-core-filter is only supported for Linux"
+    echo " on x86 and x86_64."
+    exit 1;
+  fi
+fi
 
 ##########################################
 # NPTL probe
@@ -1048,6 +1067,21 @@  EOF
 fi
 
 ##########################################
+# elfutils/version.h header file check
+
+if test "$core_filter_tool" != "no" ; then
+  elf_version_h=no
+  cat > $TMPC <<EOF
+#include <elfutils/version.h>
+int main(void) { return 0; }
+EOF
+
+  if compile_prog "" ""; then
+    elf_version_h=yes
+  fi
+fi
+
+##########################################
 # zlib check
 
 cat > $TMPC << EOF
@@ -1086,6 +1120,34 @@  EOF
 fi
 
 ##########################################
+# elfutils library probe
+
+if test "$core_filter_tool" != "no" ; then
+  elf_libs="-ldw -lelf"
+  cat > $TMPC <<EOF
+#include <elf.h>
+#include <dwarf.h>
+#include <elfutils/libdw.h>
+int main(void) {
+  dwarf_begin_elf(NULL, 0, NULL);
+  dwarf_attr(NULL, 0, NULL);
+  elf_version(EV_CURRENT);
+  return 0;
+}
+EOF
+  if compile_prog "" "$elf_libs" ; then
+    core_filter_tool=yes
+    libs_tools="$libs_tools $elf_libs"
+  else
+    if test "$core_filter_tool" = "yes" ; then
+      echo "ERROR: elfutils libraries (libdw and libelf) are missing."
+      exit 1;
+    fi
+    core_filter_tool=no
+  fi
+fi
+
+##########################################
 # pkgconfig probe
 
 pkgconfig="${cross_prefix}pkg-config"
@@ -2014,6 +2076,10 @@  if test "$softmmu" = yes ; then
   fi
 fi
 
+if test "$core_filter_tool" = "yes"; then \
+  tools="qemu-core-filter\$(EXESUF) $tools"
+fi
+
 # Mac OS X ships with a broken assembler
 roms=
 if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \
@@ -2086,6 +2152,7 @@  echo "preadv support    $preadv"
 echo "fdatasync         $fdatasync"
 echo "uuid support      $uuid"
 echo "vhost-net support $vhost_net"
+echo "build core-filter $core_filter_tool"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -2312,6 +2379,11 @@  echo "CONFIG_UNAME_RELEASE=\"$uname_release\"" >> $config_host_mak
 if test "$zero_malloc" = "yes" ; then
   echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak
 fi
+if test "$core_filter_tool" = "yes"; then
+  if test "$elf_version_h" = "yes" ; then
+    echo "HAVE_ELFUTILS_VERSION_H=y" >> $config_host_mak
+  fi
+fi
 
 # USB host support
 case "$usb" in
diff --git a/create_config b/create_config
index 0098e68..59227f1 100755
--- a/create_config
+++ b/create_config
@@ -37,6 +37,9 @@  case $line in
     done
     echo "    NULL"
     ;;
+ HAVE_ELFUTILS_VERSION_H=y)
+    echo "#define HAVE_ELFUTILS_VERSION_H 1"
+    ;;
  CONFIG_*=y) # configuration
     name=${line%=*}
     echo "#define $name 1"
diff --git a/qemu-core-filter.c b/qemu-core-filter.c
new file mode 100644
index 0000000..ab90c61
--- /dev/null
+++ b/qemu-core-filter.c
@@ -0,0 +1,1976 @@ 
+/*
+ * qemu-core-filter.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2010 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ *
+ * Adopted from: http://sourceforge.net/projects/makedumpfile
+ *    Some of the code source are adopted from makdumpfile project
+ *    which is GPL License sources.
+ */
+#include "qemu-core-filter.h"
+
+struct CoreDumpInfo *in_core = NULL;
+struct CoreDumpInfo *out_core = NULL;
+
+struct GuestOSMemMap    *guest_os_memmap = NULL;
+struct DwarfInfo dwarf_info;
+
+int debug_flag = 0;
+int force_overwrite = 0;
+const off_t failed = (off_t)-1;
+
+const char *debuginfo_directory = "/usr/lib/debug";
+
+#ifndef BUILD_ID_SUPPORT
+const char *debuginfo_default_paths[] = {
+    "/bin",
+    "/usr/bin",
+    "/usr/libexec",
+    NULL
+};
+#endif
+
+static int get_debug_info(void);
+
+static struct option longopts[] = {
+    {"symbols", required_argument, NULL, 's'},
+    {"force", required_argument, NULL, 'f'},
+    {"help", no_argument, NULL, 'h'},
+    { 0, 0, 0, 0}
+};
+
+static void print_usage(void)
+{
+    printf("\n");
+    printf("QEMU coredump filter version %s (qemu-core-filter-%s)\n", VERSION, VERSION);
+    printf("Usage:\n");
+    printf("\n");
+    printf("    qemu-core-filter [options] CORE DUMPFILE\n");
+    printf("\n");
+    printf("\n");
+    printf("Available options:\n");
+    printf("  -s|--symbols FILENAME\n");
+    printf("         This is a pathname to the qemu debuginfo file.\n");
+    printf("         This file must have the debug information.\n");
+    printf("  -f|--force\n");
+    printf("         force overwrite if o/p DUMPFILE already exists.\n");
+    printf("  -d\n");
+    printf("         Turn on the debug messages.\n");
+    printf("  -h|--help\n");
+    printf("         Prinf this message.\n");
+    printf("  CORE:\n");
+    printf("         This is a pathname to the qemu coredump image.\n");
+    printf("  DUMPFILE:\n");
+    printf("         This is a pathname to a file created by this command.\n");
+    printf("\n");
+}
+
+static int get_elf64_ehdr(Elf64_Ehdr *ehdr)
+{
+    if (lseek(in_core->fd_corefile, 0, SEEK_SET) == failed) {
+        ERRMSG("Can't seek the dump memory(%s). %s\n",
+            in_core->corefile_name, strerror(errno));
+        return FALSE;
+    }
+    if (read(in_core->fd_corefile, ehdr, sizeof(Elf64_Ehdr))
+        != sizeof(Elf64_Ehdr)) {
+        ERRMSG("Can't read the dump memory(%s). %s\n",
+            in_core->corefile_name, strerror(errno));
+        return FALSE;
+    }
+    if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
+        ERRMSG("Can't get valid e_ident.\n");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static int get_elf64_phdr(int fd, char *filename, int index, Elf64_Phdr *phdr)
+{
+    off_t offset;
+
+    offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) * index;
+
+    if (lseek(fd, offset, SEEK_SET) == failed) {
+        ERRMSG("Can't seek %s. %s\n", filename, strerror(errno));
+        return FALSE;
+    }
+    if (read(fd, phdr, sizeof(Elf64_Phdr)) != sizeof(Elf64_Phdr)) {
+        ERRMSG("Can't read %s. %s\n", filename, strerror(errno));
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static int get_elf32_ehdr(Elf32_Ehdr *ehdr)
+{
+    if (lseek(in_core->fd_corefile, 0, SEEK_SET) == failed) {
+        ERRMSG("Can't seek the dump memory(%s). %s\n",
+            in_core->corefile_name, strerror(errno));
+        return FALSE;
+    }
+    if (read(in_core->fd_corefile, ehdr, sizeof(Elf32_Ehdr))
+        != sizeof(Elf32_Ehdr)) {
+        ERRMSG("Can't read the dump memory(%s). %s\n",
+            in_core->corefile_name, strerror(errno));
+        return FALSE;
+    }
+    if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
+        ERRMSG("Can't get valid e_ident.\n");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static int get_elf32_phdr(int fd, char *filename, int index, Elf32_Phdr *phdr)
+{
+    off_t offset;
+
+    offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * index;
+
+    if (lseek(fd, offset, SEEK_SET) == failed) {
+        ERRMSG("Can't seek %s. %s\n", filename, strerror(errno));
+        return FALSE;
+    }
+    if (read(fd, phdr, sizeof(Elf32_Phdr)) != sizeof(Elf32_Phdr)) {
+        ERRMSG("Can't read %s. %s\n", filename, strerror(errno));
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static int check_elf_format(int fd, char *filename, int *phnum, int *num_load,
+                    int *elf_type)
+{
+    int i;
+    Elf64_Ehdr ehdr64;
+    Elf64_Phdr load64;
+    Elf32_Ehdr ehdr32;
+    Elf32_Phdr load32;
+
+    if (lseek(fd, 0, SEEK_SET) == failed) {
+        ERRMSG("Can't seek %s. %s\n", filename, strerror(errno));
+        return FALSE;
+    }
+    if (read(fd, &ehdr64, sizeof(Elf64_Ehdr)) != sizeof(Elf64_Ehdr)) {
+        ERRMSG("Can't read %s. %s\n", filename, strerror(errno));
+        return FALSE;
+    }
+    if (lseek(fd, 0, SEEK_SET) == failed) {
+        ERRMSG("Can't seek %s. %s\n", filename, strerror(errno));
+        return FALSE;
+    }
+    if (read(fd, &ehdr32, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)) {
+        ERRMSG("Can't read %s. %s\n", filename, strerror(errno));
+        return FALSE;
+    }
+    (*num_load) = 0;
+    if ((ehdr64.e_ident[EI_CLASS] == ELFCLASS64)
+        && (ehdr32.e_ident[EI_CLASS] != ELFCLASS32)) {
+        (*elf_type) = ehdr64.e_type;
+        (*phnum) = ehdr64.e_phnum;
+        for (i = 0; i < ehdr64.e_phnum; i++) {
+            if (!get_elf64_phdr(fd, filename, i, &load64)) {
+                ERRMSG("Can't find Phdr %d.\n", i);
+                return FALSE;
+            }
+            /* DEBUG_MSG("load64.p_type = %d\n", load64.p_type); */
+            if (load64.p_type == PT_LOAD)
+                (*num_load)++;
+        }
+        return ELF64;
+
+    } else if ((ehdr64.e_ident[EI_CLASS] != ELFCLASS64)
+        && (ehdr32.e_ident[EI_CLASS] == ELFCLASS32)) {
+        (*elf_type) = ehdr32.e_type;
+        (*phnum) = ehdr32.e_phnum;
+        for (i = 0; i < ehdr32.e_phnum; i++) {
+            if (!get_elf32_phdr(fd, filename, i, &load32)) {
+                ERRMSG("Can't find Phdr %d.\n", i);
+                return FALSE;
+            }
+            /* DEBUG_MSG("load32.p_type = %d\n", load32.p_type); */
+            if (load32.p_type == PT_LOAD)
+                (*num_load)++;
+        }
+        return ELF32;
+    }
+    ERRMSG("Can't get valid ehdr.\n");
+    return FALSE;
+}
+
+static int open_debugfile(void)
+{
+    in_core->fd_qemu_debug = open(in_core->name_qemu_debug, O_RDONLY);
+    if (in_core->fd_qemu_debug < 0) {
+        ERRMSG("Can't open debuginfo file for reading. %s\n",
+            strerror(errno));
+        return -errno;
+    }
+    return 0;
+}
+
+static int qemu_validate_options(void)
+{
+    /* Open input core file for reading. */
+    in_core->fd_corefile = open(in_core->corefile_name,
+                        O_RDONLY | O_LARGEFILE);
+    if (in_core->fd_corefile < 0) {
+        ERRMSG("Can't open input core file for reading. %s\n",
+            strerror(errno));
+        return -errno;
+    }
+
+    /* Open debuginfo file */
+    if (in_core->name_qemu_debug) {
+        int retval = open_debugfile();
+        if (retval) {
+            return retval;
+        }
+    }
+    return 0;
+}
+
+static void free_core_info(struct CoreDumpInfo * core_info)
+{
+    if (core_info->fd_corefile > 0) {
+        close(core_info->fd_corefile);
+    }
+
+    if (core_info->fd_qemu_debug > 0) {
+        close(core_info->fd_qemu_debug);
+    }
+
+    if (core_info->pt_load_segments) {
+        free(core_info->pt_load_segments);
+    }
+
+#ifdef BUILD_ID_SUPPORT
+    if (core_info->build_id) {
+        free(core_info->build_id);
+    }
+
+    if (core_info->dbg_build_id) {
+        free(core_info->dbg_build_id);
+    }
+
+#else
+    if (core_info->pgm_name) {
+        free(core_info->pgm_name);
+    }
+#endif
+}
+
+static void free_guest_os_memmap(void)
+{
+    struct GuestOSMemMap *p, *n;
+
+    p = guest_os_memmap;
+
+    while (p) {
+        n = p->next;
+        free(p);
+        p = n;
+    }
+    guest_os_memmap = NULL;
+}
+
+static int get_elf_phdr_memory(int index, Elf64_Phdr *phdr)
+{
+    Elf32_Phdr phdr32;
+
+    if (in_core->flag_elf64) { /* ELF64 */
+        if (!get_elf64_phdr(in_core->fd_corefile,
+                in_core->corefile_name, index, phdr)) {
+            ERRMSG("Can't find Phdr %d.\n", index);
+            return FALSE;
+        }
+    } else {
+        if (!get_elf32_phdr(in_core->fd_corefile,
+                in_core->corefile_name, index, &phdr32)) {
+            ERRMSG("Can't find Phdr %d.\n", index);
+            return FALSE;
+        }
+        memset(phdr, 0, sizeof(Elf64_Phdr));
+        phdr->p_type   = phdr32.p_type;
+        phdr->p_flags  = phdr32.p_flags;
+        phdr->p_offset = phdr32.p_offset;
+        phdr->p_vaddr  = phdr32.p_vaddr;
+        phdr->p_paddr  = phdr32.p_paddr;
+        phdr->p_filesz = phdr32.p_filesz;
+        phdr->p_memsz  = phdr32.p_memsz;
+        phdr->p_align  = phdr32.p_align;
+    }
+    return TRUE;
+}
+
+static int dump_Elf_load(Elf64_Phdr *prog, int num_load)
+{
+    struct PTLoadSegment *pls;
+
+    if (prog->p_type != PT_LOAD) {
+        ERRMSG("%s isn't the dump memory.\n", in_core->corefile_name);
+        return FALSE;
+    }
+
+    pls = &in_core->pt_load_segments[num_load];
+    pls->virt_start  = prog->p_vaddr;
+    pls->virt_end    = pls->virt_start + prog->p_filesz;
+    pls->file_offset = prog->p_offset;
+
+    DEBUG_MSG("LOAD (%d)\n", num_load);
+    DEBUG_MSG("  virt_start : %llx\n", pls->virt_start);
+    DEBUG_MSG("  virt_end   : %llx\n", pls->virt_end);
+
+    return TRUE;
+}
+
+#ifndef BUILD_ID_SUPPORT
+static char * get_core_note_pgmname(Elf *elfd, GElf_Phdr *phdr)
+{
+    Elf_Data *notes_data = NULL;
+    size_t offset = 0;
+    size_t name_offset = 0;
+    size_t desc_offset = 0;
+    size_t pgm_name_offset = 0;
+    GElf_Nhdr nhdr;
+
+    notes_data = elf_getdata_rawchunk(elfd, phdr->p_offset, phdr->p_filesz,
+                    ELF_T_NHDR);
+    if (!notes_data) {
+        ERRMSG("Can't get raw chunk from notes section.\n");
+        return NULL;
+    }
+
+    while ((offset = gelf_getnote(notes_data, offset, &nhdr,
+                    &name_offset, &desc_offset)) > 0) {
+        if (nhdr.n_namesz != sizeof "CORE" ||
+            memcmp(notes_data->d_buf + name_offset, "CORE",
+                sizeof "CORE")) {
+            continue;
+        }
+
+        if (nhdr.n_type != NT_PRPSINFO)
+            continue;
+
+        pgm_name_offset = desc_offset + nhdr.n_descsz - 80 - 16;
+        return strndup(notes_data->d_buf + pgm_name_offset, 16);
+    }
+    return NULL;
+}
+
+static char * get_debug_file(const char *path)
+{
+    char *dbg_link, *ptr;
+
+    dbg_link = malloc(strlen(debuginfo_directory) + strlen(path) +
+                      strlen(in_core->pgm_name) + 1 +
+                      sizeof ".debug" + 1);
+    if (!dbg_link) {
+        ERRMSG("Can't allocate memory for debuginfo file name.\n");
+        return NULL;
+    }
+
+    ptr = dbg_link;
+    ptr += sprintf(ptr, "%s%s/%s.debug", debuginfo_directory, path,
+                                         in_core->pgm_name);
+
+    DEBUG_MSG("Looking for debuginfo file at: %s\n", dbg_link);
+
+    ptr = realpath(dbg_link, NULL);
+    free(dbg_link);
+
+    return ptr;
+}
+
+static char * get_debugfile_by_core_name(void)
+{
+    char *dbg_file;
+    int i = 0;
+
+    if (!in_core->pgm_name) {
+        return NULL;
+    }
+
+    /* find DEBUG DIR/<default-path>/pgm_name>.debug file */
+    for (i = 0; debuginfo_default_paths[i] != NULL; i++) {
+        dbg_file = get_debug_file(debuginfo_default_paths[i]);
+
+        if (dbg_file) {
+            return dbg_file;
+        }
+    }
+
+    return NULL;
+}
+#else
+
+static GElf_Addr *
+get_auxv_phdr(Elf *elfd, GElf_Phdr *phdr, GElf_Addr *auxv_phdr)
+{
+    Elf_Data *notes_data, *auxv_data = NULL;
+    unsigned long auxv_data_sz = 0;
+    size_t offset = 0;
+    size_t name_offset = 0;
+    size_t desc_offset = 0;
+    size_t num_auxv = 0;
+    GElf_Nhdr nhdr;
+    int i;
+
+    notes_data = elf_getdata_rawchunk(elfd, phdr->p_offset, phdr->p_filesz,
+                    ELF_T_NHDR);
+    if (!notes_data) {
+        ERRMSG("Can't get raw chunk from notes section.\n");
+        return NULL;
+    }
+
+    while ((offset = gelf_getnote(notes_data, offset, &nhdr,
+                    &name_offset, &desc_offset)) > 0) {
+        if (nhdr.n_namesz != sizeof "CORE" ||
+            memcmp(notes_data->d_buf + name_offset, "CORE",
+                sizeof "CORE")) {
+            continue;
+        }
+
+        if (nhdr.n_type != NT_AUXV)
+            continue;
+
+        auxv_data_sz = nhdr.n_descsz;
+        auxv_data = elf_getdata_rawchunk(elfd,
+                    phdr->p_offset + desc_offset,
+                    nhdr.n_descsz, ELF_T_AUXV);
+        if (!auxv_data) {
+            ERRMSG("Can't get AUXV\n");
+            return NULL;
+        }
+        DEBUG_MSG("Found AUXV at %p of size %lu\n", auxv_data,
+                                auxv_data_sz);
+        break;
+    }
+
+    if (!auxv_data || !auxv_data_sz) {
+        return NULL;
+    }
+
+    num_auxv = auxv_data_sz / gelf_fsize(elfd, ELF_T_AUXV, 1, EV_CURRENT);
+
+    for (i = 0; i < num_auxv; i++) {
+        GElf_auxv_t *auxv, auxv_mem;
+
+        if ((auxv = gelf_getauxv(auxv_data, i, &auxv_mem)) == NULL) {
+            return NULL;
+        }
+
+        if (auxv->a_type == AT_PHDR) {
+            *auxv_phdr = auxv->a_un.a_val;
+            DEBUG_MSG("AUXV Phdr = %llx\n", *auxv_phdr);
+            return auxv_phdr;
+        }
+    }
+    return NULL;
+}
+
+static struct PTLoadSegment * find_memseg(GElf_Addr auxv_addr, size_t size)
+{
+    struct PTLoadSegment *pls = NULL;
+    int i;
+
+    for (i = 0; i < in_core->num_load_memory; i++) {
+        pls = &in_core->pt_load_segments[i];
+
+        if (pls->virt_start <= auxv_addr &&
+            pls->virt_end > (auxv_addr + size)) {
+            DEBUG_MSG("auxv phdr lies in load segment(O=0x%llx, "
+                "[0x%llx - 0x%llx])\n",
+                pls->file_offset, pls->virt_start,
+                pls->virt_end);
+            return pls;
+        }
+    }
+    return NULL;
+}
+
+static Elf * get_app_elfd(Elf *elfd, GElf_Addr auxv_phdr)
+{
+    struct PTLoadSegment *pls;
+    unsigned long long filesz;
+    Elf_Data *data;
+    unsigned char *e_indent;
+    void *app_ehdr_mem;
+
+    if ((pls = find_memseg(auxv_phdr, ELF_T_EHDR)) == NULL) {
+        ERRMSG("Can't locate load segment for AUXV\n");
+        return NULL;
+    }
+
+    filesz = pls->virt_end - pls->virt_start;
+
+    data = elf_getdata_rawchunk(elfd, pls->file_offset, filesz,
+                                ELF_T_EHDR);
+    if (!data) {
+        ERRMSG("Can't read the load segment.\n");
+        return NULL;
+    }
+
+    e_indent = (unsigned char *)data->d_buf;
+    if (memcmp(e_indent, ELFMAG, SELFMAG) ||
+        (e_indent[EI_CLASS] <= ELFCLASSNONE) ||
+        (e_indent[EI_CLASS] >= ELFCLASSNUM) ||
+        (e_indent[EI_DATA] <= ELFDATANONE) ||
+        (e_indent[EI_DATA] >= ELFDATANUM) ||
+        (e_indent[EI_VERSION] <= EV_NONE) ||
+        (e_indent[EI_VERSION] >= EV_NUM)) {
+        ERRMSG("Invalid ELF header in load segment.\n");
+        return NULL;
+    }
+
+    app_ehdr_mem = calloc(1, filesz);
+    if (!app_ehdr_mem) {
+        ERRMSG("Can't allocate memory for application ELF header.\n");
+        return NULL;
+    }
+
+    memcpy(app_ehdr_mem, data->d_buf, filesz);
+
+    if (gelf_getclass(elfd) == ELFCLASS32) {
+        Elf32_Ehdr *ehdr = app_ehdr_mem;
+        ehdr->e_shoff = 0;
+        ehdr->e_shnum = 0;
+    } else {
+        Elf64_Ehdr *ehdr = app_ehdr_mem;
+        ehdr->e_shoff = 0;
+        ehdr->e_shnum = 0;
+    }
+
+    return elf_memory(app_ehdr_mem, filesz);
+
+}
+
+static unsigned char * note_getbuildid(Elf_Data *data, size_t *len)
+{
+    GElf_Nhdr *nhdr;
+    size_t offset = 0, name_off, desc_off;
+    unsigned char *buildid = NULL;
+    int found = 0;
+    unsigned char *id;
+
+    if (data->d_type != ELF_T_NHDR) {
+        return NULL;
+    }
+
+    while (offset < data->d_size) {
+        nhdr = data->d_buf + offset;
+        name_off = offset + sizeof(*nhdr);
+        desc_off = name_off + NOTE_ALIGN(nhdr->n_namesz);
+
+        if ((nhdr->n_namesz == sizeof "GNU")
+            && (nhdr->n_type == NT_GNU_BUILD_ID)
+            && (!memcmp(data->d_buf + name_off, "GNU", sizeof "GNU"))) {
+            DEBUG_MSG("Found build id at %#x %#x %#x\n",
+                    offset, name_off, desc_off);
+            found = 1;
+            *len = nhdr->n_descsz;
+            id = data->d_buf + desc_off;
+            break;
+        }
+        offset = desc_off + NOTE_ALIGN(nhdr->n_descsz);
+    }
+
+    if (found) {
+        buildid = malloc(*len);
+        if (!buildid) {
+            ERRMSG("Can't allocate memory for build-id\n");
+            return NULL;
+        }
+        memcpy(buildid, id, *len);
+        return buildid;
+    }
+    return NULL;
+}
+
+static unsigned char * get_buildid(Elf *elfd, size_t *len)
+{
+    GElf_Ehdr ehdr;
+    Elf_Data *data;
+    unsigned char *buildid = NULL;
+    int i;
+
+    if (gelf_getehdr(elfd, &ehdr) == NULL) {
+        ERRMSG("Can't get ELF header\n");
+        return NULL;
+    }
+
+    for (i = 0; i < ehdr.e_phnum; i++) {
+        GElf_Phdr nphdr;
+
+        if (gelf_getphdr(elfd, i, &nphdr) == NULL) {
+            return NULL;
+        }
+
+        if (nphdr.p_type != PT_NOTE) {
+            continue;
+        }
+
+        data = elf_getdata_rawchunk(elfd, nphdr.p_offset,
+                        nphdr.p_filesz, ELF_T_NHDR);
+        if (!data) {
+            ERRMSG("Can't read NOTE segment.\n");
+            return NULL;
+        }
+
+        buildid = note_getbuildid(data, len);
+        if (buildid) {
+            return buildid;
+        }
+    }
+
+    return NULL;
+}
+
+static unsigned char * get_debug_buildid(size_t *len)
+{
+    Elf *elfd;
+
+    if (lseek(dwarf_info.fd_debuginfo, 0, SEEK_SET) == failed) {
+        ERRMSG("Can't seek the kernel file(%s). %s\n",
+            dwarf_info.name_debuginfo, strerror(errno));
+        return FALSE;
+    }
+    if (!(elfd = elf_begin(dwarf_info.fd_debuginfo, ELF_C_READ_MMAP, NULL))) {
+        ERRMSG("Can't get first elf header of %s.\n",
+            dwarf_info.name_debuginfo);
+        return FALSE;
+    }
+
+    dwarf_info.build_id = get_buildid(elfd, &dwarf_info.build_id_size);
+    elf_end(elfd);
+
+    if (!dwarf_info.build_id) {
+        dwarf_info.cmd = DWARF_INFO_GET_BUILD_ID;
+
+        if (!get_debug_info()) {
+            return NULL;
+        }
+    }
+
+    *len = dwarf_info.build_id_size;
+    return dwarf_info.build_id;
+}
+
+static char * get_debugfile_by_build_id(void)
+{
+    char *dbg_link, *ptr;
+    unsigned char *id;
+    int i;
+
+    if (!in_core->build_id) {
+        return NULL;
+    }
+
+    id = in_core->build_id;
+
+    /* DEBUG DIR/.build-id/ab/cdef... */
+    dbg_link = malloc(strlen(debuginfo_directory) + sizeof "/.build-id/" +
+                      (2 * in_core->build_id_size) + 1 +
+                      sizeof ".debug" + 1);
+    if (!dbg_link) {
+        ERRMSG("Can't allocate memory for debuginfo file name.\n");
+        return NULL;
+    }
+
+    ptr = dbg_link;
+    ptr += sprintf(ptr, "%s/.build-id/%02x/", debuginfo_directory, id[0]);
+
+    for (i = 1; i < in_core->build_id_size; i++) {
+        ptr += sprintf(ptr, "%02x", id[i]);
+    }
+
+    sprintf(ptr, ".debug");
+
+    DEBUG_MSG("Debuginfo link file: %s\n", dbg_link);
+
+    ptr = realpath(dbg_link, NULL);
+    free(dbg_link);
+
+    return ptr;
+}
+#endif
+
+#ifdef BUILD_ID_SUPPORT
+static unsigned char * get_core_buildid(size_t *len)
+#else
+static char * get_core_pgmname(void)
+#endif
+{
+    Elf *elfd = NULL;
+    GElf_Ehdr ehdr_mem, *ehdr = NULL;
+    int i;
+#ifdef BUILD_ID_SUPPORT
+    Elf *app_elfd = NULL;
+    GElf_Addr auxv_phdr = 0;
+    unsigned char *build_id = NULL;
+#else
+    char *pgm_name = NULL;
+#endif
+
+    if (lseek(in_core->fd_corefile, 0, SEEK_SET) == failed) {
+        ERRMSG("Can't seek the dump memory(%s). %s\n",
+            in_core->corefile_name, strerror(errno));
+        return NULL;
+    }
+
+    elfd = elf_begin(in_core->fd_corefile, ELF_C_READ_MMAP, NULL);
+    if (elfd == NULL) {
+        ERRMSG("Can't get first elf header of %s.\n",
+            in_core->corefile_name);
+        return NULL;
+    }
+
+    if ((ehdr = gelf_getehdr(elfd, &ehdr_mem)) == NULL) {
+        ERRMSG("Can't get the ELF header\n");
+        goto out;
+    }
+
+    for (i = 0; i < ehdr->e_phnum; i++) {
+        GElf_Phdr *phdr, phdr_mem;
+
+        if ((phdr = gelf_getphdr(elfd, i, &phdr_mem)) == NULL) {
+            goto out;
+        }
+
+        if (phdr->p_type != PT_NOTE) {
+            continue;
+        }
+
+#ifdef BUILD_ID_SUPPORT
+        if (get_auxv_phdr(elfd, phdr, &auxv_phdr)) {
+            break;
+        }
+#else
+        if ((pgm_name = get_core_note_pgmname(elfd, phdr))) {
+            break;
+        }
+#endif
+    }
+
+#ifdef BUILD_ID_SUPPORT
+    if (!auxv_phdr) {
+        DEBUG_MSG("Can't locate AUXV Phdr.\n");
+        goto out;
+    }
+
+    /*
+     * Get application ELF header from load segment.
+     */
+    if ((app_elfd = get_app_elfd(elfd, auxv_phdr)) == NULL) {
+        DEBUG_MSG("Couldn't find the Application ELF header.\n");
+        goto out;
+    }
+
+    build_id = get_buildid(app_elfd, len);
+#endif
+
+out:
+    if (elfd) {
+        elf_end(elfd);
+    }
+
+#ifdef BUILD_ID_SUPPORT
+    return build_id;
+#else
+    return pgm_name;
+#endif
+}
+
+
+static int get_elf_info(void)
+{
+    int i, j, phnum, num_load, elf_format, elf_type;
+    Elf64_Phdr phdr;
+
+    if (elf_version(EV_CURRENT) == EV_NONE) {
+        /*
+         * library out of date
+         */
+        ERRMSG("Elf library out of date!\n");
+        return -EINVAL;
+    }
+
+    /*
+     * Check ELF64 or ELF32.
+     */
+    elf_format = check_elf_format(in_core->fd_corefile,
+                in_core->corefile_name,
+                &phnum, &num_load, &elf_type);
+
+    if (elf_format == ELF64) {
+        in_core->flag_elf64 = TRUE;
+    } else if (elf_format == ELF32) {
+        in_core->flag_elf64 = FALSE;
+    } else {
+        return -EINVAL;
+    }
+
+    if (elf_type == ET_CORE) {
+        in_core->elf_type = ET_CORE;
+    } else {
+        return -EINVAL;
+    }
+
+    in_core->num_load_memory = num_load;
+
+    if (!in_core->num_load_memory) {
+        ERRMSG("Can't get the number of PT_LOAD.\n");
+        return -EINVAL;
+    }
+    if ((in_core->pt_load_segments = (struct PTLoadSegment *)
+        calloc(1, sizeof(struct PTLoadSegment) *
+        in_core->num_load_memory)) == NULL) {
+        ERRMSG("Can't allocate memory for the PT_LOAD. %s\n",
+            strerror(errno));
+        return -ENOMEM;
+    }
+
+    for (i = 0, j = 0; i < phnum; i++) {
+        if (!get_elf_phdr_memory(i, &phdr)) {
+            return FALSE;
+        }
+
+        if (phdr.p_type != PT_LOAD) {
+            continue;
+        }
+
+        if (!in_core->page_size) {
+            in_core->page_size = (long) phdr.p_align;
+        }
+
+        if (j == 0) {
+            in_core->offset_load = phdr.p_offset;
+            if (!in_core->offset_load) {
+                ERRMSG("Can't get the offset of page data.\n");
+                return -EINVAL;
+            }
+        }
+        if (j >= in_core->num_load_memory) {
+            return -EINVAL;
+        }
+
+        if (!dump_Elf_load(&phdr, j)) {
+            return -EINVAL;
+        }
+        j++;
+    }
+
+#ifdef BUILD_ID_SUPPORT
+    in_core->build_id = get_core_buildid(&in_core->build_id_size);
+    if (in_core->build_id == NULL) {
+        ERRMSG("Failed to extract build-id info from core file: %s\n",
+            in_core->corefile_name);
+        return -EINVAL;
+    }
+
+    DEBUG_PRINT_BUILDID("core file build-id:", in_core->build_id,
+                    in_core->build_id_size);
+#else
+    in_core->pgm_name = get_core_pgmname();
+    if (in_core->pgm_name == NULL) {
+        ERRMSG("Failed to extract program name from core file: %s\n",
+            in_core->corefile_name);
+        return -EINVAL;
+    }
+    DEBUG_MSG("Program name: %s\n", in_core->pgm_name);
+#endif
+
+    return 0;
+}
+
+/* Get symbol address for a given symbol name from debuginfo file. */
+static unsigned long long get_symbol_addr(const char *symname)
+{
+    int i;
+    unsigned long long symbol = NOT_FOUND_SYMBOL;
+    Elf *elfd = NULL;
+    GElf_Shdr shdr;
+    GElf_Sym sym;
+    Elf_Data *data = NULL;
+    Elf_Scn *scn = NULL;
+    char *sym_name = NULL;
+
+    if (lseek(dwarf_info.fd_debuginfo, 0, SEEK_SET) == failed) {
+        ERRMSG("Can't seek the debuginfo file(%s). %s\n",
+            dwarf_info.name_debuginfo, strerror(errno));
+        return NOT_FOUND_SYMBOL;
+    }
+    if (!(elfd = elf_begin(dwarf_info.fd_debuginfo, ELF_C_READ, NULL))) {
+        ERRMSG("Can't get first elf header of %s.\n",
+            dwarf_info.name_debuginfo);
+        return NOT_FOUND_SYMBOL;
+    }
+    while ((scn = elf_nextscn(elfd, scn)) != NULL) {
+        if (gelf_getshdr(scn, &shdr) == NULL) {
+            ERRMSG("Can't get section header.\n");
+            goto out;
+        }
+        if (shdr.sh_type == SHT_SYMTAB) {
+            break;
+        }
+    }
+    if (!scn) {
+        ERRMSG("Can't find symbol table from debuginfo file %s.\n",
+                dwarf_info.name_debuginfo);
+        goto out;
+    }
+
+    data = elf_getdata(scn, data);
+
+    if ((!data) || (data->d_size == 0)) {
+        ERRMSG("No data in symbol table.\n");
+        goto out;
+    }
+
+    for (i = 0; i < (shdr.sh_size/shdr.sh_entsize); i++) {
+        if (gelf_getsym(data, i, &sym) == NULL) {
+            ERRMSG("Can't get symbol at index %d.\n", i);
+            goto out;
+        }
+        sym_name = elf_strptr(elfd, shdr.sh_link, sym.st_name);
+
+        if (sym_name == NULL) {
+            continue;
+        }
+
+        if (!strcmp(sym_name, symname)) {
+            symbol = sym.st_value;
+            break;
+        }
+    }
+out:
+    if (elfd != NULL)
+        elf_end(elfd);
+
+    return symbol;
+}
+
+static int get_data_member_location(Dwarf_Die *die, long *offset)
+{
+    size_t expcnt;
+    Dwarf_Attribute attr;
+    Dwarf_Op *expr;
+
+    if (dwarf_attr(die, DW_AT_data_member_location, &attr) == NULL) {
+        return FALSE;
+    }
+
+    if (dwarf_getlocation(&attr, &expr, &expcnt) < 0) {
+        return FALSE;
+    }
+
+    (*offset) = expr[0].number;
+
+    return TRUE;
+}
+
+static void search_member(Dwarf *dwarfd, Dwarf_Die *die)
+{
+    int tag;
+    long offset;
+    const char *name;
+    Dwarf_Die child, *walker;
+
+    if (dwarf_child(die, &child) != 0) {
+        return;
+    }
+
+    walker = &child;
+
+    do {
+        tag  = dwarf_tag(walker);
+        name = dwarf_diename(walker);
+
+        if (tag != DW_TAG_member) {
+            continue;
+        }
+
+        if ((!name) || strcmp(name, dwarf_info.member_name)) {
+            continue;
+        }
+        /*
+         * Get the member offset.
+         */
+        if (!get_data_member_location(walker, &offset)) {
+            continue;
+        }
+        dwarf_info.member_offset = offset;
+        return;
+    } while (!dwarf_siblingof(walker, walker));
+
+    /*
+     * Return even if not found.
+     */
+    return;
+}
+
+static void search_structure(Dwarf *dwarfd, Dwarf_Die *die, int *found)
+{
+    int tag;
+    const char *name;
+
+    /*
+     * If we get to here then we don't have any more
+     * children, check to see if this is a relevant tag
+     */
+    do {
+        tag  = dwarf_tag(die);
+        name = dwarf_diename(die);
+        if ((tag != DW_TAG_structure_type) || (!name)
+            || strcmp(name, dwarf_info.struct_name)) {
+            continue;
+        }
+        /*
+         * Skip if DW_AT_byte_size is not included.
+         */
+        dwarf_info.struct_size = dwarf_bytesize(die);
+
+        if (dwarf_info.struct_size > 0) {
+            break;
+        }
+
+    } while (!dwarf_siblingof(die, die));
+
+    if (dwarf_info.struct_size <= 0) {
+        /*
+         * Not found the demanded structure.
+         */
+        return;
+    }
+
+    /*
+     * Found the demanded structure.
+     */
+    *found = TRUE;
+    switch (dwarf_info.cmd) {
+    case DWARF_INFO_GET_STRUCT_SIZE:
+        break;
+    case DWARF_INFO_GET_MEMBER_OFFSET:
+        search_member(dwarfd, die);
+        break;
+    }
+}
+
+static void search_die_tree(Dwarf *dwarfd, Dwarf_Die *die, int *found)
+{
+    Dwarf_Die child;
+
+    /*
+     * start by looking at the children
+     */
+    if (dwarf_child(die, &child) == 0) {
+        search_die_tree(dwarfd, &child, found);
+    }
+
+    if (*found) {
+        return;
+    }
+
+    search_structure(dwarfd, die, found);
+}
+
+static int get_debug_info(void)
+{
+    int found = FALSE;
+    char *name = NULL;
+    size_t shstrndx, header_size;
+    uint8_t address_size, offset_size;
+    Dwarf *dwarfd = NULL;
+    Elf *elfd = NULL;
+    Dwarf_Off off = 0, next_off = 0, abbrev_offset = 0;
+    Elf_Scn *scn = NULL;
+    GElf_Shdr scnhdr_mem, *scnhdr = NULL;
+    Dwarf_Die cu_die;
+    const char *section_name = ".debug_info";
+
+    int ret = FALSE;
+
+    if (lseek(dwarf_info.fd_debuginfo, 0, SEEK_SET) == failed) {
+        ERRMSG("Can't seek the kernel file(%s). %s\n",
+            dwarf_info.name_debuginfo, strerror(errno));
+        return FALSE;
+    }
+    if (!(elfd = elf_begin(dwarf_info.fd_debuginfo, ELF_C_READ_MMAP, NULL))) {
+        ERRMSG("Can't get first elf header of %s.\n",
+            dwarf_info.name_debuginfo);
+        return FALSE;
+    }
+    if (!(dwarfd = dwarf_begin_elf(elfd, DWARF_C_READ, NULL))) {
+        ERRMSG("Can't create a handle for a new debug session.\n");
+        goto out;
+    }
+    if (elf_getshdrstrndx(elfd, &shstrndx) < 0) {
+        ERRMSG("Can't get the section index of the string table.\n");
+        goto out;
+    }
+
+#ifdef BUILD_ID_SUPPORT
+    if (dwarf_info.cmd == DWARF_INFO_GET_BUILD_ID) {
+        section_name = ".note.gnu.build-id";
+    }
+#endif
+    /*
+     * Search for ".debug_info" section.
+     */
+    while ((scn = elf_nextscn(elfd, scn)) != NULL) {
+        scnhdr = gelf_getshdr(scn, &scnhdr_mem);
+        name = elf_strptr(elfd, shstrndx, scnhdr->sh_name);
+        if (!strcmp(name, section_name)) {
+            break;
+        }
+    }
+    if (strcmp(name, section_name)) {
+        ERRMSG("Can't get %s section.\n", section_name);
+        goto out;
+    }
+
+#ifdef BUILD_ID_SUPPORT
+    if (dwarf_info.cmd == DWARF_INFO_GET_BUILD_ID) {
+        Elf_Data *data = elf_getdata(scn, NULL);
+        if (!data) {
+            ERRMSG("Can't read the section data for build-id.\n");
+            goto out;
+        }
+        dwarf_info.build_id =
+            note_getbuildid(data, &dwarf_info.build_id_size);
+        if (dwarf_info.build_id) {
+            ret = TRUE;
+        }
+        goto out;
+    }
+#endif
+
+    /*
+     * Search by each CompileUnit.
+     */
+    while (dwarf_nextcu(dwarfd, off, &next_off, &header_size,
+        &abbrev_offset, &address_size, &offset_size) == 0) {
+        off += header_size;
+        if (dwarf_offdie(dwarfd, off, &cu_die) == NULL) {
+            ERRMSG("Can't get CU die.\n");
+            goto out;
+        }
+        search_die_tree(dwarfd, &cu_die, &found);
+        if (found) {
+            break;
+        }
+        off = next_off;
+    }
+    ret = TRUE;
+out:
+    if (dwarfd != NULL) {
+        dwarf_end(dwarfd);
+    }
+    if (elfd != NULL) {
+        elf_end(elfd);
+    }
+
+    return ret;
+}
+
+/*
+ * Get the size of structure.
+ */
+static long get_structure_size(const char *structname)
+{
+    dwarf_info.cmd = DWARF_INFO_GET_STRUCT_SIZE;
+
+    dwarf_info.struct_name = structname;
+    dwarf_info.struct_size = NOT_FOUND_STRUCTURE;
+
+    if (!get_debug_info()) {
+        return FAILED_DWARFINFO;
+    }
+
+    return dwarf_info.struct_size;
+}
+
+/*
+ * Get the offset of member.
+ */
+static long
+get_member_offset(const char *structname, const char *membername, int cmd)
+{
+    dwarf_info.cmd = cmd;
+    dwarf_info.struct_name = structname;
+    dwarf_info.struct_size = NOT_FOUND_STRUCTURE;
+    dwarf_info.member_name = membername;
+    dwarf_info.member_offset = NOT_FOUND_STRUCTURE;
+
+    if (!get_debug_info()) {
+        return FAILED_DWARFINFO;
+    }
+
+    return dwarf_info.member_offset;
+}
+
+static int is_in_same_page(unsigned long vaddr1, unsigned long vaddr2)
+{
+    if (round(vaddr1, in_core->page_size)
+                    == round(vaddr2, in_core->page_size)) {
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*
+ * Convert virtual Address to File Offset.
+ *  If this function returns 0x0, File Offset isn't found.
+ *  The File Offset 0x0 is in the ELF header.
+ *  It is not in the memory image.
+ */
+static off_t vaddr_to_offset(unsigned long long vaddr)
+{
+    int i;
+    off_t offset;
+    struct PTLoadSegment *pls;
+
+    for (i = offset = 0; i < in_core->num_load_memory; i++) {
+        pls = &in_core->pt_load_segments[i];
+        if ((vaddr >= pls->virt_start)
+            && (vaddr < pls->virt_end)) {
+            offset = (off_t)(vaddr - pls->virt_start) + pls->file_offset;
+                break;
+        }
+    }
+    return offset;
+}
+
+static int readmem(unsigned long long addr, void *bufptr, size_t size)
+{
+    size_t read_size, next_size;
+    off_t offset = 0;
+    unsigned long long next_addr;
+    char *next_ptr;
+
+    read_size = size;
+
+    /*
+     * Read each page, because pages are not necessarily continuous.
+     * Ex) pages in vmalloc area
+     */
+    if (!is_in_same_page(addr, addr + size - 1)) {
+        read_size = in_core->page_size - (addr % in_core->page_size);
+        next_addr = roundup(addr + 1, in_core->page_size);
+        next_size = size - read_size;
+        next_ptr  = (char *)bufptr + read_size;
+
+        if (!readmem(next_addr, next_ptr, next_size)) {
+            goto error;
+        }
+    }
+
+    if (!(offset = vaddr_to_offset(addr))) {
+        ERRMSG("Can't convert a virtual address(%llx) to offset.\n",
+            addr);
+        goto error;
+    }
+
+    if (lseek(in_core->fd_corefile, offset, SEEK_SET) == failed) {
+        ERRMSG("Can't seek the dump memory(%s). %s\n",
+            in_core->corefile_name, strerror(errno));
+        goto error;
+    }
+
+    if (read(in_core->fd_corefile, bufptr, read_size) != read_size) {
+        ERRMSG("Can't read the dump memory(%s). %s\n",
+            in_core->corefile_name, strerror(errno));
+        goto error;
+    }
+
+    return size;
+error:
+    ERRMSG("addr:%llx, size:%zd\n", addr, size);
+    return FALSE;
+}
+
+static int collect_debuginfo(char *dbg_filename, int dbg_fd)
+{
+#ifdef BUILD_ID_SUPPORT
+    size_t len = 0;
+#endif
+
+    dwarf_info.fd_debuginfo = dbg_fd;
+    dwarf_info.name_debuginfo = dbg_filename;
+
+#ifdef BUILD_ID_SUPPORT
+    /*
+     * First verify whether debuginfo build-id matches with that of
+     * coredump file.
+     */
+    in_core->dbg_build_id = get_debug_buildid(&len);
+    if (!in_core->dbg_build_id) {
+        ERRMSG("Can't read build-id from debuginfo file: %s\n",
+                    dwarf_info.name_debuginfo);
+        return -EINVAL;
+    }
+    in_core->dbg_build_id_size = len;
+    DEBUG_PRINT_BUILDID("debuginfo file build-id:",
+                in_core->dbg_build_id,
+                in_core->dbg_build_id_size);
+
+    if ((in_core->build_id_size != in_core->dbg_build_id_size)
+        || (memcmp(in_core->build_id, in_core->dbg_build_id,
+                    in_core->build_id_size))) {
+        ERRMSG("build-id mismatch found."
+                " incorrect debuginfo file: %s\n",
+                dwarf_info.name_debuginfo);
+        return -EINVAL;
+    }
+#endif
+
+    /*
+     * Start loading symbol from debuginfo file.
+     */
+    DEBUG_MSG("Reading symbols from %s.\n", dwarf_info.name_debuginfo);
+    in_core->ram_blocks.sym_name = (char *)RAM_BLOCKS_SYMNAME;
+
+    /* Initialize ram_blocks symbol address */
+    SYMBOL(ram_blocks) = get_symbol_addr(RAM_BLOCKS_SYMNAME);
+    if (SYMBOL(ram_blocks) == NOT_FOUND_SYMBOL) {
+        ERRMSG("Symbol not found: %s\n", RAM_BLOCKS_SYMNAME);
+        return -EINVAL;
+    }
+    DEBUG_MSG("ram_blocks:addr = 0x%llx\n", SYMBOL(ram_blocks));
+
+    /* Initialize ram_blocks symbol size */
+    SIZE(ram_blocks) = get_structure_size(RAM_BLOCKS_STRUCTNAME);
+    if (SIZE(ram_blocks) == FAILED_DWARFINFO) {
+        return -EINVAL;
+    }
+
+    DEBUG_MSG("ram_blocks:size = 0x%lx\n", SIZE(ram_blocks));
+
+    /* Initialize offset value for ram_blocks.host member */
+    OFFSET(host) = get_member_offset(RAM_BLOCKS_STRUCTNAME, "host",
+                    DWARF_INFO_GET_MEMBER_OFFSET);
+    if (OFFSET(host) == FAILED_DWARFINFO) {
+        return -EINVAL;
+    }
+
+    DEBUG_MSG("ram_blocks:m.host = 0x%lx\n", OFFSET(host));
+
+    /* Initialize offset value for ram_blocks.length member */
+    OFFSET(length) = get_member_offset(RAM_BLOCKS_STRUCTNAME, "length",
+                    DWARF_INFO_GET_MEMBER_OFFSET);
+    if (OFFSET(length) == FAILED_DWARFINFO) {
+        return -EINVAL;
+    }
+
+    DEBUG_MSG("ram_blocks:m.length = 0x%lx\n", OFFSET(length));
+
+    /* Initialize offset value for ram_blocks.next member */
+    OFFSET(next) = get_member_offset(RAM_BLOCKS_STRUCTNAME, "next",
+                    DWARF_INFO_GET_MEMBER_OFFSET);
+    if (OFFSET(next) == FAILED_DWARFINFO) {
+        return -EINVAL;
+    }
+
+    DEBUG_MSG("ram_blocks:m.next = 0x%lx\n", OFFSET(next));
+    return 0;
+}
+
+static int get_qemu_debuginfo(void)
+{
+    /*
+     * If user has not specified debuginfo file then search it using
+     * build-id.
+     */
+    if (!in_core->name_qemu_debug) {
+#ifdef BUILD_ID_SUPPORT
+        in_core->name_qemu_debug = get_debugfile_by_build_id();
+#else
+        in_core->name_qemu_debug = get_debugfile_by_core_name();
+#endif
+        if (!in_core->name_qemu_debug) {
+            ERRMSG("Missing separate debuginfo file. "
+                "Use '-s' option to specify debuginfo file manually.\n");
+            return -EINVAL;
+        }
+
+        DEBUG_MSG("debuginfo file found: %s\n", in_core->name_qemu_debug);
+        if (open_debugfile())
+            return -EINVAL;
+    }
+
+    return collect_debuginfo(in_core->name_qemu_debug, in_core->fd_qemu_debug);
+}
+
+static int update_guest_os_memmap(unsigned char *ram_block_mem)
+{
+    struct GuestOSMemMap *node;
+
+    node = malloc(sizeof(*node));
+    if (!node) {
+        DEBUG_MSG("Can't allocate memory for Guest OS memory map.\n");
+        return -ENOMEM;
+    }
+
+    node->mem_start = ULONG(ram_block_mem + OFFSET(host));
+    node->mem_end = node->mem_start + ULONG(ram_block_mem + OFFSET(length));
+    node->next = NULL;
+
+    DEBUG_MSG("Guest OS memory: start(0x%llx) end(0x%llx)\n", node->mem_start,
+                            node->mem_end);
+
+    if (guest_os_memmap == NULL) {
+        guest_os_memmap = node;
+    } else {
+        node->next = guest_os_memmap;
+        guest_os_memmap = node;
+    }
+    return 0;
+}
+
+static int build_guest_os_memmap(void)
+{
+    unsigned long ram_blocks;
+    unsigned char *ram_block_mem;
+    int err = 0;
+
+    DEBUG_MSG("Building Guest OS memory mappings.\n");
+    if (!readmem(in_core->ram_blocks.sym_addr, &ram_blocks,
+                sizeof(ram_blocks))) {
+        ERRMSG("Can't get the value of ram_blocks.\n");
+        return -EINVAL;
+    }
+
+    ram_block_mem = malloc(in_core->ram_blocks.sym_size);
+    if (!ram_block_mem) {
+        ERRMSG("Can't allocate memory for a struct RAMBlock. %s\n",
+                strerror(errno));
+        return -ENOMEM;
+    }
+
+    while (ram_blocks) {
+        DEBUG_MSG("ram_blocks => 0x%08lx\n", ram_blocks);
+
+        if (!readmem(ram_blocks, ram_block_mem,
+                    in_core->ram_blocks.sym_size)) {
+            ERRMSG("Can't get struct RAMBlock.\n");
+            err = -EINVAL;
+            goto out;
+        }
+
+        err = update_guest_os_memmap(ram_block_mem);
+        if (err) {
+            goto out;
+        }
+
+        ram_blocks = ULONG(ram_block_mem + OFFSET(next));
+    }
+out:
+    free(ram_block_mem);
+    return err;
+}
+
+static int get_phnum_memory(void)
+{
+    int phnum;
+    Elf64_Ehdr ehdr64;
+    Elf32_Ehdr ehdr32;
+
+    if (in_core->flag_elf64) { /* ELF64 */
+        if (!get_elf64_ehdr(&ehdr64)) {
+            ERRMSG("Can't get ehdr64.\n");
+            return FALSE;
+        }
+        phnum = ehdr64.e_phnum;
+    } else {                /* ELF32 */
+        if (!get_elf32_ehdr(&ehdr32)) {
+            ERRMSG("Can't get ehdr32.\n");
+            return FALSE;
+        }
+        phnum = ehdr32.e_phnum;
+    }
+
+    return phnum;
+}
+
+static int
+write_and_check_space(int fd, void *buf, size_t buf_size, char *file_name)
+{
+    int status, written_size = 0;
+
+    while (written_size < buf_size) {
+        status = write(fd, buf + written_size,
+                   buf_size - written_size);
+        if (0 < status) {
+            written_size += status;
+            continue;
+        }
+        if (errno == ENOSPC) {
+            out_core->flag_nospace = TRUE;
+        }
+        ERRMSG("\nCan't write the dump file(%s). %s\n",
+                file_name, strerror(errno));
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static int write_buffer(int fd, off_t offset, void *buf, size_t buf_size,
+                                                    char *file_name)
+{
+    DEBUG_MSG("offset: 0x%08lx, off end: 0x%08lx, size = %zd\n",
+                    (unsigned long int)offset,
+                    (unsigned long int)(offset + buf_size),
+                    buf_size);
+
+    if (lseek(fd, offset, SEEK_SET) == failed) {
+        ERRMSG("Can't seek the dump file(%s). %s\n",
+            file_name, strerror(errno));
+        return FALSE;
+    }
+    if (!write_and_check_space(fd, buf, buf_size, file_name)) {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static int write_cache(struct CacheData *cd, void *buf, size_t size)
+{
+    if (!write_buffer(cd->fd, cd->offset, buf, size,
+                cd->file_name)) {
+        return FALSE;
+    }
+
+    cd->offset += size;
+    return TRUE;
+}
+
+static int write_elf_phdr(struct CacheData *cd_hdr, Elf64_Phdr *load)
+{
+    Elf32_Phdr load32;
+
+    if (in_core->flag_elf64) { /* ELF64 */
+        if (!write_cache(cd_hdr, load, sizeof(Elf64_Phdr))) {
+            return FALSE;
+        }
+    } else {
+        memset(&load32, 0, sizeof(Elf32_Phdr));
+        load32.p_type   = load->p_type;
+        load32.p_flags  = load->p_flags;
+        load32.p_offset = load->p_offset;
+        load32.p_vaddr  = load->p_vaddr;
+        load32.p_paddr  = load->p_paddr;
+        load32.p_filesz = load->p_filesz;
+        load32.p_memsz  = load->p_memsz;
+        load32.p_align  = load->p_align;
+
+        if (!write_cache(cd_hdr, &load32, sizeof(Elf32_Phdr))) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static void guest_mem_adjust(Elf64_Phdr *load)
+{
+    struct GuestOSMemMap *p;
+    Elf64_Addr vm_start, vm_end;
+
+    if (!load->p_filesz) {
+        return;
+    }
+
+    vm_start = load->p_vaddr;
+    vm_end = load->p_vaddr + load->p_filesz;
+
+    p = guest_os_memmap;
+    while (p) {
+        if ((p->mem_start >= vm_start) && (p->mem_start < vm_end)) {
+            load->p_filesz = p->mem_start - vm_start;
+            return;
+        } else if ((p->mem_end > vm_start) && (p->mem_end <= vm_end)) {
+            load->p_filesz = 0;
+            return;
+        } else if ((p->mem_start < vm_start) && (p->mem_end > vm_end)) {
+            load->p_filesz = 0;
+            return;
+        }
+        p = p->next;
+    }
+    return;
+}
+
+static int write_elf_header(struct CacheData *cd_header)
+{
+    int i, phnum;
+    off_t offset_note_memory, offset_note_dumpfile;
+    size_t size_note;
+    Elf64_Ehdr ehdr64;
+    Elf32_Ehdr ehdr32;
+    Elf64_Phdr note;
+
+    char *buf = NULL;
+
+    int ret = FALSE;
+
+    DEBUG_MSG("Writing ELF Header\n");
+
+    if (in_core->flag_elf64) { /* ELF64 */
+        if (!get_elf64_ehdr(&ehdr64)) {
+            ERRMSG("Can't get ehdr64.\n");
+            goto out;
+        }
+    } else {                /* ELF32 */
+        if (!get_elf32_ehdr(&ehdr32)) {
+            ERRMSG("Can't get ehdr32.\n");
+            goto out;
+        }
+    }
+
+    /*
+     * Write an ELF header.
+     */
+    if (in_core->flag_elf64) { /* ELF64 */
+        if (!write_buffer(out_core->fd_corefile, 0, &ehdr64, sizeof(ehdr64),
+            out_core->corefile_name)) {
+            goto out;
+        }
+
+    } else {                /* ELF32 */
+        if (!write_buffer(out_core->fd_corefile, 0, &ehdr32, sizeof(ehdr32),
+            out_core->corefile_name)) {
+            goto out;
+        }
+    }
+
+    /*
+     * Write a PT_NOTE header.
+     */
+    DEBUG_MSG("Writing PT_NOTE Header\n");
+
+    if (!(phnum = get_phnum_memory())) {
+        goto out;
+    }
+
+    for (i = 0; i < phnum; i++) {
+        if (!get_elf_phdr_memory(i, &note)) {
+            return FALSE;
+        }
+        if (note.p_type == PT_NOTE) {
+            break;
+        }
+    }
+    if (note.p_type != PT_NOTE) {
+        ERRMSG("Can't get a PT_NOTE header.\n");
+        goto out;
+    }
+
+    if (in_core->flag_elf64) { /* ELF64 */
+        cd_header->offset    = sizeof(ehdr64);
+        offset_note_dumpfile = sizeof(ehdr64)
+            + sizeof(Elf64_Phdr) * ehdr64.e_phnum;
+    } else {
+        cd_header->offset    = sizeof(ehdr32);
+        offset_note_dumpfile = sizeof(ehdr32)
+            + sizeof(Elf32_Phdr) * ehdr32.e_phnum;
+    }
+    offset_note_memory = note.p_offset;
+    note.p_offset      = offset_note_dumpfile;
+    size_note          = note.p_filesz;
+    DEBUG_MSG("offset_note_memory(0x%08lx), offset_note_dumpfile(0x%08lx),"
+            "size_note = %zd\n", (unsigned long int) offset_note_memory,
+            (unsigned long int) offset_note_dumpfile,
+            size_note);
+
+    if (!write_elf_phdr(cd_header, &note)) {
+        goto out;
+    }
+
+    /*
+     * Write a PT_NOTE segment.
+     * PT_LOAD header will be written later.
+     */
+    if ((buf = malloc(size_note)) == NULL) {
+        ERRMSG("Can't allocate memory for PT_NOTE segment. %s\n",
+            strerror(errno));
+        goto out;
+    }
+    if (lseek(in_core->fd_corefile, offset_note_memory, SEEK_SET) == failed) {
+        ERRMSG("Can't seek the dump memory(%s). %s\n",
+            in_core->corefile_name, strerror(errno));
+        goto out;
+    }
+    if (read(in_core->fd_corefile, buf, size_note) != size_note) {
+        ERRMSG("Can't read the dump memory(%s). %s\n",
+            in_core->corefile_name, strerror(errno));
+        goto out;
+    }
+    if (!write_buffer(out_core->fd_corefile, offset_note_dumpfile, buf,
+        size_note, out_core->corefile_name)) {
+        goto out;
+    }
+
+    /*
+     * Set an offset of PT_LOAD segment.
+     */
+    out_core->offset_load = offset_note_dumpfile + size_note;
+
+    ret = TRUE;
+out:
+    if (buf != NULL) {
+        free(buf);
+    }
+
+    return ret;
+}
+
+static int
+write_elf_load_segment(struct CacheData *cd_page, unsigned long long paddr,
+               off_t off_memory, long long size)
+{
+    long long bufsz_write;
+    long page_size = in_core->page_size;
+    char buf[in_core->page_size];
+
+    if (lseek(in_core->fd_corefile, off_memory, SEEK_SET) < 0) {
+        ERRMSG("Can't seek the dump memory(%s). %s\n",
+            in_core->corefile_name, strerror(errno));
+        return FALSE;
+    }
+
+    while (size > 0) {
+        if (size >= page_size) {
+            bufsz_write = page_size;
+        } else {
+            bufsz_write = size;
+        }
+
+        if (read(in_core->fd_corefile, buf, bufsz_write) != bufsz_write) {
+            ERRMSG("Can't read the dump memory(%s). %s\n",
+                in_core->corefile_name, strerror(errno));
+            return FALSE;
+        }
+        if (!write_cache(cd_page, buf, bufsz_write)) {
+            return FALSE;
+        }
+        size -= page_size;
+    }
+
+    return TRUE;
+}
+
+static int
+write_elf_pages(struct CacheData *cd_header, struct CacheData *cd_page)
+{
+    int i, phnum;
+    unsigned long long paddr;
+    off_t off_memory;
+    Elf64_Phdr load;
+
+    cd_page->offset = out_core->offset_load;
+
+    if (!(phnum = get_phnum_memory())) {
+        return FALSE;
+    }
+
+    for (i = 0; i < phnum; i++) {
+        if (!get_elf_phdr_memory(i, &load)) {
+            return FALSE;
+        }
+
+        if (load.p_type != PT_LOAD) {
+            continue;
+        }
+
+        off_memory = load.p_offset;
+        cd_page->offset = roundup(cd_page->offset, in_core->page_size);
+        load.p_offset = cd_page->offset;
+
+        paddr     = load.p_paddr;
+
+        /*
+         * adjust PT_LOAD to filter guest os memory from
+         * cordump.
+         */
+        guest_mem_adjust(&load);
+
+        /*
+         * Write a PT_LOAD header.
+         */
+        if (!write_elf_phdr(cd_header, &load)) {
+            return FALSE;
+        }
+
+        /*
+         * Write a PT_LOAD segment.
+         */
+        if (!write_elf_load_segment(cd_page, paddr, off_memory,
+                                    load.p_filesz)) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static int prepare_cache_data(struct CacheData *cd)
+{
+    cd->fd        = out_core->fd_corefile;
+    cd->file_name    = out_core->corefile_name;
+
+    return 0;
+}
+
+static int open_outcorefile(void)
+{
+    int out_flag = O_CREAT | O_WRONLY | O_LARGEFILE;
+
+    if (force_overwrite) {
+        out_flag |= O_TRUNC;
+    } else {
+        out_flag |= O_EXCL;
+    }
+
+    /* Open target core file for writing. */
+    out_core->fd_corefile = open(out_core->corefile_name, out_flag,
+                S_IRUSR|S_IWUSR);
+    if (out_core->fd_corefile < 0) {
+        if (errno == EEXIST) {
+            ERRMSG("core file already exists. "
+                    "Use '-f' option to overwrite. %s\n",
+                    out_core->corefile_name);
+        } else {
+            ERRMSG("Can't open target core file for writing. %s\n",
+                    strerror(errno));
+        }
+        return -errno;
+    }
+    return 0;
+}
+
+static int writeout_coredump(void)
+{
+    int ret = 0;
+    struct CacheData cd_header, cd_page;
+
+    if ((ret = open_outcorefile())) {
+        return ret;
+    }
+
+    out_core->flag_nospace = FALSE;
+
+    prepare_cache_data(&cd_header);
+    prepare_cache_data(&cd_page);
+
+    if (!write_elf_header(&cd_header)) {
+        goto out;
+    }
+
+    write_elf_pages(&cd_header, &cd_page);
+
+out:
+    if (out_core->flag_nospace) {
+        return -ENOSPC;
+    } else {
+        return ret;
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    int opt, err = 0;
+
+    in_core = (struct CoreDumpInfo *) calloc(1, sizeof(struct CoreDumpInfo));
+    if (in_core == NULL) {
+        ERRMSG("Can't allocate memory for core info cache. %s\n",
+            strerror(errno));
+        return -ENOMEM;
+    }
+
+    out_core = (struct CoreDumpInfo *) calloc(1, sizeof(struct CoreDumpInfo));
+    if (out_core == NULL) {
+        ERRMSG("Can't allocate memory for core info cache. %s\n",
+            strerror(errno));
+        return -ENOMEM;
+    }
+
+    while ((opt = getopt_long(argc, argv, "s:hdf", longopts, NULL)) != -1) {
+        switch (opt) {
+        case 's':
+            in_core->name_qemu_debug = optarg;
+            break;
+        case 'h':
+            print_usage();
+            goto out;
+        case 'd':
+            debug_flag = 1;
+            break;
+        case 'f':
+            force_overwrite = 1;
+            break;
+        default:
+            ERRMSG("Command line parameter is invalid.\n");
+            ERRMSG("Try 'qemu-core-filter --help' for more information.\n");
+            goto out;
+        }
+    }
+
+    if (argc != optind + 2) {
+        print_usage();
+        err = -EINVAL;
+        goto out;
+    }
+
+    in_core->corefile_name = argv[optind];
+    DEBUG_MSG("In core file name: %s\n", in_core->corefile_name);
+
+    out_core->corefile_name = argv[optind + 1];
+    DEBUG_MSG("Out core file name: %s\n", out_core->corefile_name);
+
+    err = qemu_validate_options();
+    if (err) {
+        goto out;
+    }
+
+    err = get_elf_info();
+    if (err) {
+        goto out;
+    }
+
+    err = get_qemu_debuginfo();
+    if (err) {
+        goto out;
+    }
+
+    err = build_guest_os_memmap();
+    if (err) {
+        goto out;
+    }
+
+    err = writeout_coredump();
+
+out:
+    if (in_core) {
+        free_core_info(in_core);
+        free(in_core);
+    }
+    if (out_core) {
+        free_core_info(out_core);
+        free(out_core);
+    }
+    free_guest_os_memmap();
+
+    return err;
+}
diff --git a/qemu-core-filter.h b/qemu-core-filter.h
new file mode 100644
index 0000000..5dbdcd1
--- /dev/null
+++ b/qemu-core-filter.h
@@ -0,0 +1,216 @@ 
+/*
+ * qemu-core-filter.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2010 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ *
+ * Adopted from: http://sourceforge.net/projects/makedumpfile
+ *    Some of the code source are adopted from makdumpfile project
+ *    which is GPL License sources.
+ */
+#include "config-host.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <elf.h>
+#include <gelf.h>
+#include <elfutils/libdw.h>
+#include <libelf.h>
+#include <dwarf.h>
+#include <getopt.h>
+
+#ifdef HAVE_ELFUTILS_VERSION_H
+#include <elfutils/version.h>
+
+#if !_ELFUTILS_PREREQ(0, 142)
+#define elf_getshdrstrndx elf_getshstrndx
+#endif
+
+#if _ELFUTILS_PREREQ(0, 138)
+/* build-id support is introduced only from elfutils >= 0.138 */
+#define BUILD_ID_SUPPORT    1
+#endif
+
+#else /* !HAVE_ELFUTILS_VERSION_H */
+
+#define elf_getshdrstrndx elf_getshstrndx
+
+#endif
+
+#ifndef VERSION
+#define VERSION  "0.3.1"
+#endif
+
+#define round(x, y)     (((x) / (y)) * (y))
+
+#define TRUE            1
+#define FALSE           0
+
+#define ELF32           1
+#define ELF64           2
+
+/*
+ * for symbol
+ */
+#define NOT_FOUND_SYMBOL        (0)
+#define RAM_BLOCKS_SYMNAME      "ram_blocks"
+#define RAM_BLOCKS_STRUCTNAME   "RAMBlock"
+
+#define SYMBOL(X)       (in_core->X.sym_addr)
+#define SIZE(x)         (in_core->x.sym_size)
+#define OFFSET(x)       (in_core->ram_blocks.offset.x)
+#define ULONG(ADDR)     (*((unsigned long *)(ADDR)))
+
+#define BITPERBYTE      8
+#define BYTE(x)         (x / BITPERBYTE)
+#define BIT(x)          (x % BITPERBYTE)
+#define NOTE_ALIGN(s)   (((s) + 3) & -4U)
+
+/*
+ * for dwarf
+ */
+
+#define NOT_FOUND_STRUCTURE (-1)
+#define FAILED_DWARFINFO    (-2)
+
+enum {
+    DWARF_INFO_GET_STRUCT_SIZE,
+    DWARF_INFO_GET_MEMBER_OFFSET,
+#ifdef BUILD_ID_SUPPORT
+    DWARF_INFO_GET_BUILD_ID
+#endif
+};
+
+struct DwarfInfo {
+    unsigned int    cmd;              /* IN  */
+    int     fd_debuginfo;             /* IN  */
+    const char    *name_debuginfo;    /* IN  */
+    const char    *struct_name;       /* IN  */
+    const char    *member_name;       /* IN  */
+    long    struct_size;              /* OUT */
+    long    member_offset;            /* OUT */
+#ifdef BUILD_ID_SUPPORT
+    unsigned char    *build_id;       /* OUT */
+    size_t  build_id_size;            /* OUT */
+#endif
+};
+
+struct PTLoadSegment {
+    off_t                 file_offset;
+    unsigned long long    virt_start;
+    unsigned long long    virt_end;
+};
+
+struct SymbolInfo {
+    char        *sym_name;
+    unsigned long long    sym_addr;
+    long        sym_size;
+    struct offset {
+        long    host;
+        long    length;
+        long    next;
+    } offset;
+};
+
+struct GuestOSMemMap {
+    unsigned long long    mem_start;
+    unsigned long long    mem_end;
+    struct GuestOSMemMap  *next;
+};
+
+struct CoreDumpInfo {
+
+    /*
+     * coredump image info
+     */
+    char       *corefile_name;    /* Core dump file name.    */
+    int        fd_corefile;
+
+    /*
+     * General info
+     */
+    int        flag_elf64;        /* flag for ELF64 format   */
+    int        elf_type;
+    int        flag_nospace;      /* No space left on device */
+    int        offset_load;
+
+    /*
+     * ELF info
+     */
+
+    int         num_load_memory;
+    long        page_size;
+#ifdef BUILD_ID_SUPPORT
+    unsigned char    *build_id;   /* Unique build id         */
+    size_t      build_id_size;    /* Size of build id        */
+#else
+    char        *pgm_name;        /* program name.           */
+#endif
+
+    /*
+     * Debug info
+     */
+
+    char       *name_qemu_debug;  /* QEMU Debuginfo file name */
+    int        fd_qemu_debug;
+#ifdef BUILD_ID_SUPPORT
+    unsigned char    *dbg_build_id;     /* debuginfo build id */
+    size_t     dbg_build_id_size;
+#endif
+
+    struct PTLoadSegment    *pt_load_segments;
+    struct SymbolInfo    ram_blocks;
+};
+
+struct CacheData {
+    int   fd;
+    char  *file_name;
+    off_t offset;
+};
+
+#define ERRMSG(x...) \
+do { \
+    fprintf(stderr, x); \
+} while (0)
+
+#define DEBUG_MSG(x...) \
+do { \
+    if (debug_flag) { \
+        fprintf(stderr, __FUNCTION__); \
+        fprintf(stderr, ": "); \
+        fprintf(stderr, x); \
+    } \
+} while (0)
+
+#ifdef BUILD_ID_SUPPORT
+#define DEBUG_PRINT_BUILDID(msg, id, sz) \
+do { \
+    int i; \
+    if (debug_flag) { \
+        fprintf(stderr, __FUNCTION__); \
+        fprintf(stderr, ": "); \
+        fprintf(stderr, msg); \
+        fprintf(stderr, " "); \
+        for (i = 0; i < (sz); i++) \
+            fprintf(stderr, "%02x", id[i]); \
+        fprintf(stderr, "\n"); \
+    } \
+} while (0)
+#endif /* BUILD_ID_SUPPORT */
+