[RFC] makedumpfile-1.1.4-rc: ia64 DISCONTIGMEM support

Ken'ichi Ohmichi oomichi at mxs.nes.nec.co.jp
Fri Jun 1 05:11:14 EDT 2007


Hi,

The attached patch is for the development, and it isn't stable yet.
This patch can be applied to makedumpfile version 1.1.3.
If you find some problems in this patch, please let me know.
If there aren't any problems, I will release a new makedumpfile
by next weekend.

Changelog:
1. Add __FUNCTION__ to ERRMSG.
  The function name is added to ERRMSG.
2. Add ia64_vtop().
  The translation function from a virtual address to a
  physical address is added for ia64.
  The patch was provided by Bernhard Walle.
3. Add ia64 DISCONTIGMEM support.
  A new makedumpfile supports ia64 DISCONTIGMEM.
4. Cleanup README.
  The destination of BUG REPORT is changed to kexec-ml.
  The item REQUIREMENTS is added.
5. Fix DISCONTIGMEM bitmap.
  This patch fixes the problem that it cannot output the part
  of bitmap on DISCONTIGMEM kernel.
6. Fix ELF output with overlapping sections.
  The patch was provided by Bernhard Walle.


Thanks
Ken'ichi Ohmichi


------------------------------------------------------------------------

Signed-off-by: Bernhard Walle <bwalle at suse.de>
Signed-off-by: Ken'ichi Ohmichi <oomichi at mxs.nes.nec.co.jp>
---

diff -puN backup/v1.1.3/Makefile makedumpfile/Makefile
--- backup/v1.1.3/Makefile	2007-04-13 15:44:55.000000000 +0900
+++ makedumpfile/Makefile	2007-06-01 13:05:24.000000000 +0900
@@ -1,7 +1,7 @@
 # makedumpfile
 
-VERSION=1.1.3
-DATE=13 April 2007
+VERSION=1.1.4-rc
+DATE=01 June 2007
 
 CC	= gcc
 CFLAGS = -g -O2 -Wall -D_FILE_OFFSET_BITS=64 \
diff -puN backup/v1.1.3/README makedumpfile/README
--- backup/v1.1.3/README	2007-04-13 15:44:55.000000000 +0900
+++ makedumpfile/README	2007-06-01 13:05:19.000000000 +0900
@@ -3,6 +3,10 @@
  makdumpfile's README
 ======================
 
+* REQUIREMENTS
+  Please download the following library file and install it:
+  - elfutils-0.125.tar.gz
+
 * BUILD & INSTALL
   1.Get the latest makedumpfile from the following site:
     https://sourceforge.net/projects/makedumpfile/
@@ -14,7 +18,7 @@
     # make; make install
 
 * SUPPORTED KERNELS
-  makedumpfile (version 1.1.3) supports the following kernels.
+  makedumpfile (version 1.1.4-rc) supports the following kernels.
 
          |      FLATMEM      |   DISCONTIGMEM    |     SPARSEMEM
          |-------------------+-------------------+-------------------
@@ -22,9 +26,9 @@
   Version| x86| _64|ia64|  64| x86| _64|ia64|  64| x86| _64|ia64|  64
   -------+----+----+----+----+----+----+----+----+----+----+----+----
   2.6.15 | OK | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | --
-  2.6.16 | OK | OK | -- |    | -- | OK | -- | -- | -- |    | -- |
+  2.6.16 | OK | OK | -- |    | -- | OK | OK | -- | -- |    | -- |
   2.6.17 | OK | OK | -- |    | -- | OK | -- | -- | -- | OK | -- |
-  2.6.18 | OK | OK | -- | OK | -- | OK |TODO| -- | -- | OK | OK | OK
+  2.6.18 | OK | OK | -- | OK | -- | OK | OK | -- | -- | OK | OK | OK
   2.6.19 | OK | OK | -- | OK | OK | OK |TODO| -- | OK | OK | OK | OK
   2.6.20 | OK | OK | -- | KP | OK | OK |TODO| -- | OK | OK | OK | KP
   21-rc5 | OK | OK | -- | OK | OK | OK |TODO| -- | OK | OK | OK | OK
@@ -41,11 +45,12 @@
 
 * REFERENCES
   https://sourceforge.net/projects/makedumpfile/
-  http://lists.osdl.org/pipermail/fastboot/
+  http://lists.infradead.org/pipermail/kexec/
+  https://lists.linux-foundation.org/pipermail/fastboot/
 
 * BUG REPORT
   If finding some bugs, please send the information to the following:
   Ken'ichi Ohmichi <oomichi at mxs.nes.nec.co.jp>
   Masaki Tachibana <tachibana at mxm.nes.nec.co.jp>
-  Fastboot-ml <fastboot at lists.osdl.org>
+  kexec-ml <kexec at lists.infradead.org>
 
diff -puN backup/v1.1.3/ia64.c makedumpfile/ia64.c
--- backup/v1.1.3/ia64.c	2007-04-13 15:44:45.000000000 +0900
+++ makedumpfile/ia64.c	2007-05-31 12:03:18.000000000 +0900
@@ -17,6 +17,18 @@
 
 #include "makedumpfile.h"
 
+
+/*
+ *  vmalloc() starting address is either the traditional 0xa000000000000000 or
+ *  bumped up in 2.6 to 0xa000000200000000.
+ */
+int
+is_vmalloc_addr_ia64(struct DumpInfo *info, unsigned long vaddr)
+{
+	return ((vaddr >= info->vmalloc_start) &&
+			(vaddr < (ulong)KERNEL_UNCACHED_BASE));
+}
+
 int
 get_phys_base_ia64(struct DumpInfo *info)
 {
@@ -45,8 +57,231 @@ get_machdep_info_ia64(struct DumpInfo *i
 	info->section_size_bits = _SECTION_SIZE_BITS;
 	info->max_physmem_bits  = _MAX_PHYSMEM_BITS;
 
+	/*
+	 * Get kernel_start and vmalloc_start.
+	 */
+	if (SYMBOL(_stext) == NOT_FOUND_SYMBOL)
+		return FALSE;
+
+	info->kernel_start = SYMBOL(_stext);
+
+	if (VADDR_REGION(info->kernel_start) == KERNEL_VMALLOC_REGION)
+		info->vmalloc_start = info->kernel_start + 4*1024UL*1024UL*1024UL;
+	else
+		info->vmalloc_start = KERNEL_VMALLOC_BASE;
+
+	/*
+	 * Check the pgtable (3 Levels or 4 Levels).
+	 */
+	if (!strncmp(SRCFILE(pud_t), STR_PUD_T_4L, strlen(STR_PUD_T_4L)))
+		info->mem_flags |= MEMORY_PAGETABLE_4L;
+
+	else if (!strncmp(SRCFILE(pud_t), STR_PUD_T_3L, strlen(STR_PUD_T_3L)))
+		info->mem_flags |= MEMORY_PAGETABLE_3L;
+
+	else
+		MSG("Can't distinguish the pgtable.\n");
+
 	return TRUE;
 }
 
+unsigned long
+ia64_vtop3(struct DumpInfo *info, unsigned long long vaddr)
+{
+	unsigned long paddr, temp, page_dir, pgd_pte, page_middle, pmd_pte;
+	unsigned long page_table, pte;
+
+	/*
+	 * Translate a virtual address to a physical address
+	 * by using 3 levels paging.
+	 */
+	if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) {
+		ERRMSG("Can't get the symbol of swapper_pg_dir.\n");
+		return 0x0;
+	}
+
+	/*
+	 * Get PGD
+	 */
+	temp = vaddr & MASK_PGD_3L;
+	temp = temp >> (PGDIR_SHIFT_3L - 3);
+	page_dir = SYMBOL(swapper_pg_dir) + temp;
+	if (!readmem(info, page_dir, &pgd_pte, sizeof pgd_pte)) {
+		ERRMSG("Can't get pgd_pte (page_dir:%lx).\n", page_dir);
+		return 0x0;
+	}
+
+	/*
+	 * Get PMD
+	 */
+	temp = vaddr & MASK_PMD;
+	temp = temp >> (PMD_SHIFT - 3);
+	page_middle = pgd_pte + temp;
+	/*
+	 * Convert physical address to virtual address
+	 */
+	page_middle = paddr_to_vaddr(info, page_middle);
+	if (!readmem(info, page_middle, &pmd_pte, sizeof pmd_pte)) {
+		ERRMSG("Can't get pmd_pte (page_middle:%lx).\n", page_middle);
+		return 0x0;
+	}
+
+	/*
+	 * Get PTE
+	 */
+	temp = vaddr & MASK_PTE;
+	temp = temp >> (PAGE_SHIFT - 3);
+	page_table = pmd_pte + temp;
+	/*
+	 * Convert physical address to virtual address
+	 */
+	page_table = paddr_to_vaddr(info, page_table);
+	if (!readmem(info, page_table, &pte, sizeof pte)) {
+		ERRMSG("Can't get pte (page_table:%lx).\n", page_table);
+		return 0x0;
+	}
+
+	/*
+	 * Get physical address
+	 */
+	temp = vaddr & MASK_POFFSET;
+	paddr = (pte & _PAGE_PPN_MASK) + temp;
+
+	return paddr;
+}
+
+unsigned long
+ia64_vtop4(struct DumpInfo *info, unsigned long long vaddr)
+{
+	unsigned long paddr, temp, page_dir, pgd_pte, page_upper, pud_pte;
+	unsigned long page_middle, pmd_pte, page_table, pte;
+
+	/*
+	 * Translate a virtual address to a physical address
+	 * by using 4 levels paging.
+	 */
+	if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) {
+		ERRMSG("Can't get the symbol of swapper_pg_dir.\n");
+		return 0x0;
+	}
+
+	/*
+	 * Get PGD
+	 */
+	temp = vaddr & MASK_PGD_4L;
+	temp = temp >> (PGDIR_SHIFT_4L - 3);
+	page_dir = SYMBOL(swapper_pg_dir) + temp;
+	if (!readmem(info, page_dir, &pgd_pte, sizeof pgd_pte)) {
+		ERRMSG("Can't get pgd_pte (page_dir:%lx).\n", page_dir);
+		return 0x0;
+	}
+
+	/*
+	 * Get PUD
+	 */
+	temp = vaddr & MASK_PUD;
+	temp = temp >> (PUD_SHIFT - 3);
+	page_upper = pgd_pte + temp;
+	/*
+	 * Convert physical address to virtual address
+	 */
+	page_upper = paddr_to_vaddr(info, page_upper);
+	if (!readmem(info, page_upper, &pud_pte, sizeof pud_pte)) {
+		ERRMSG("Can't get pud_pte (page_upper:%lx).\n", page_upper);
+		return 0x0;
+	}
+
+	/*
+	 * Get PMD
+	 */
+	temp = vaddr & MASK_PMD;
+	temp = temp >> (PMD_SHIFT - 3);
+	page_middle = pud_pte + temp;
+	/*
+	 * Convert physical address to virtual address
+	 */
+	page_middle = paddr_to_vaddr(info, page_middle);
+	if (!readmem(info, page_middle, &pmd_pte, sizeof pmd_pte)) {
+		ERRMSG("Can't get pmd_pte (page_middle:%lx).\n", page_middle);
+		return 0x0;
+	}
+
+	/*
+	 * Get PTE
+	 */
+	temp = vaddr & MASK_PTE;
+	temp = temp >> (PAGE_SHIFT - 3);
+	page_table = pmd_pte + temp;
+	/*
+	 * Convert physical address to virtual address
+	 */
+	page_table = paddr_to_vaddr(info, page_table);
+	if (!readmem(info, page_table, &pte, sizeof pte)) {
+		ERRMSG("Can't get pte (page_table:%lx).\n", page_table);
+		return 0x0;
+	}
+
+	/*
+	 * Get physical address
+	 */
+	temp = vaddr & MASK_POFFSET;
+	paddr = (pte & _PAGE_PPN_MASK) + temp;
+
+	return paddr;
+}
+
+unsigned long
+ia64_vtop(struct DumpInfo *info, unsigned long long vaddr)
+{
+	unsigned long paddr;
+
+	if (VADDR_REGION(vaddr) != KERNEL_VMALLOC_REGION) {
+		ERRMSG("vaddr(%llx) is not KERNEL_VMALLOC_REGION.\n", vaddr);
+		return 0x0;
+	}
+	paddr = vaddr_to_paddr(info, vaddr);
+	if (paddr)
+		return paddr;
+
+	if (!is_vmalloc_addr_ia64(info, vaddr)) {
+		paddr = vaddr - info->kernel_start +
+			(info->phys_base & KERNEL_TR_PAGE_MASK);
+		return paddr;
+	}
+
+	if (info->mem_flags & MEMORY_PAGETABLE_4L)
+		return ia64_vtop4(info, vaddr);
+	else
+		return ia64_vtop3(info, vaddr);
+}
+
+/*
+ * Convert Virtual Address to File Offest.
+ */
+off_t
+vaddr_to_offset_ia64(struct DumpInfo *info, unsigned long long vaddr)
+{
+	unsigned long paddr;
+
+	switch (VADDR_REGION(vaddr)) {
+		case KERNEL_CACHED_REGION:
+			paddr = vaddr - (ulong)(KERNEL_CACHED_BASE);
+			break;
+
+		case KERNEL_UNCACHED_REGION:
+			paddr = vaddr - (ulong)(KERNEL_UNCACHED_BASE);
+			break;
+
+		case KERNEL_VMALLOC_REGION:
+			paddr = ia64_vtop(info, vaddr);
+			break;
+
+		default:
+			ERRMSG("Unknown region (%ld)\n", VADDR_REGION(vaddr));
+			return 0x0;
+	}
+	return paddr_to_offset(info, paddr);
+}
+
 #endif /* ia64 */
 
diff -puN backup/v1.1.3/makedumpfile.c makedumpfile/makedumpfile.c
--- backup/v1.1.3/makedumpfile.c	2007-04-13 15:44:55.000000000 +0900
+++ makedumpfile/makedumpfile.c	2007-05-31 12:03:18.000000000 +0900
@@ -16,8 +16,7 @@
 
 /*
  * TODO
- * 1. (ia64) DISCONTIGMEM support.
- * 2. (i386) fill PT_LOAD headers with appropriate virtual addresses.
+ * 1. (i386) fill PT_LOAD headers with appropriate virtual addresses.
  */
 
 #include "makedumpfile.h"
@@ -26,6 +25,7 @@ struct symbol_table	symbol_table;
 struct size_table	size_table;
 struct offset_table	offset_table;
 struct array_table	array_table;
+struct srcfile_table	srcfile_table;
 
 struct dwarf_info	dwarf_info;
 struct vm_table		*vt = 0;
@@ -65,6 +65,71 @@ paddr_to_offset(struct DumpInfo *info, u
 }
 
 /*
+ * Sames as paddr_to_offset() but makes sure that the specified offset (hint)
+ * in the segment.
+ */
+off_t
+paddr_to_offset2(struct DumpInfo *info, unsigned long long paddr, off_t hint)
+{
+	int i;
+	off_t offset;
+	unsigned long long len;
+	struct pt_load_segment *pls;
+
+	for (i = offset = 0; i < info->num_load_memory; i++) {
+		pls = &info->pt_load_segments[i];
+		len = pls->phys_end - pls->phys_start;
+		if ((paddr >= pls->phys_start)
+		    && (paddr < pls->phys_end)
+		    && (hint >= pls->file_offset)
+		    && (hint < pls->file_offset + len)) {
+			offset = (off_t)(paddr - pls->phys_start) +
+				pls->file_offset;
+				break;
+		}
+	}
+	return offset;
+}
+
+unsigned long long
+vaddr_to_paddr(struct DumpInfo *info, unsigned long long vaddr)
+{
+	int i;
+	unsigned long long paddr;
+	struct pt_load_segment *pls;
+
+	for (i = paddr = 0; i < info->num_load_memory; i++) {
+		pls = &info->pt_load_segments[i];
+		if ((vaddr >= pls->virt_start)
+		    && (vaddr < pls->virt_end)) {
+			paddr = (off_t)(vaddr - pls->virt_start) +
+				pls->phys_start;
+				break;
+		}
+	}
+	return paddr;
+}
+
+unsigned long long
+paddr_to_vaddr(struct DumpInfo *info, unsigned long long paddr)
+{
+	int i;
+	unsigned long long vaddr;
+	struct pt_load_segment *pls;
+
+	for (i = vaddr = 0; i < info->num_load_memory; i++) {
+		pls = &info->pt_load_segments[i];
+		if ((paddr >= pls->phys_start)
+		    && (paddr < pls->phys_end)) {
+			vaddr = (off_t)(paddr - pls->phys_start) +
+				pls->virt_start;
+				break;
+		}
+	}
+	return vaddr;
+}
+
+/*
  * Convert Virtual Address to File Offest.
  *  If this function returns 0x0, File Offset isn't found.
  *  The File Offset 0x0 is the ELF header.
@@ -735,6 +800,7 @@ get_elf_info(struct DumpInfo *info)
 	 *   capture(2nd)-kernel, the problem will happen.
 	 */
 	info->page_size = sysconf(_SC_PAGE_SIZE);
+	info->page_shift = ffs(info->page_size) - 1;
 
 	info->max_mapnr = get_max_mapnr(info);
 
@@ -1102,6 +1168,15 @@ is_search_symbol(int cmd)
 		return FALSE;
 }
 
+int
+is_search_srcfile(int cmd)
+{
+	if (cmd == DWARF_INFO_GET_TYPEDEF_SRCNAME)
+		return TRUE;
+	else
+		return FALSE;
+}
+
 static void
 search_structure(Dwarf *dwarfd, Dwarf_Die *die, int *found)
 {
@@ -1151,6 +1226,49 @@ search_structure(Dwarf *dwarfd, Dwarf_Di
 }
 
 static void
+search_srcfile(Dwarf *dwarfd, Dwarf_Die *die, int *found)
+{
+	int tag = 0, rtag = 0;
+	char *src_name = NULL;
+	const char *name;
+
+	switch (dwarf_info.cmd) {
+	case DWARF_INFO_GET_TYPEDEF_SRCNAME:
+		rtag = DW_TAG_typedef;
+		break;
+	}
+
+	/*
+	 * 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 != rtag) || (!name)
+		    || strcmp(name, dwarf_info.decl_name))
+			continue;
+
+		src_name = (char *)dwarf_decl_file(die);
+
+		if (!src_name)
+			break;
+
+	} while (!dwarf_siblingof(die, die));
+
+	if (!src_name)
+		return;
+
+	/*
+	 * Found the demanded one.
+	 */
+	strncpy(dwarf_info.src_name, src_name, LEN_SRCFILE);
+
+	*found = TRUE;
+}
+
+static void
 search_symbol(Dwarf *dwarfd, Dwarf_Die *die, int *found)
 {
 	int tag;
@@ -1211,6 +1329,9 @@ search_die_tree(Dwarf *dwarfd, Dwarf_Die
 
 	else if (is_search_symbol(dwarf_info.cmd))
 		search_symbol(dwarfd, die, found);
+
+	else if (is_search_srcfile(dwarf_info.cmd))
+		search_srcfile(dwarfd, die, found);
 }
 
 int
@@ -1351,6 +1472,23 @@ get_array_length(char *name01, char *nam
 	return dwarf_info.array_length;
 }
 
+/*
+ * Get the source filename.
+ */
+int
+get_source_filename(char *decl_name, char *src_name, int cmd)
+{
+	dwarf_info.cmd = cmd;
+	dwarf_info.decl_name = decl_name;
+
+	if (!get_debug_info())
+		return FALSE;
+
+	strncpy(src_name, dwarf_info.src_name, LEN_SRCFILE);
+
+	return TRUE;
+}
+
 int
 get_symbol_info(struct DumpInfo *info)
 {
@@ -1364,6 +1502,7 @@ get_symbol_info(struct DumpInfo *info)
 	SYMBOL_INIT(system_utsname, "system_utsname");
 	SYMBOL_INIT(init_uts_ns, "init_uts_ns");
 	SYMBOL_INIT(_stext, "_stext");
+	SYMBOL_INIT(swapper_pg_dir, "swapper_pg_dir");
 	SYMBOL_INIT(phys_base, "phys_base");
 	SYMBOL_INIT(node_online_map, "node_online_map");
 	SYMBOL_INIT(node_data, "node_data");
@@ -1415,6 +1554,8 @@ get_structure_info(struct DumpInfo *info
 	OFFSET_INIT(pglist_data.node_start_pfn, "pglist_data","node_start_pfn");
 	OFFSET_INIT(pglist_data.node_spanned_pages, "pglist_data",
 	    "node_spanned_pages");
+	OFFSET_INIT(pglist_data.pgdat_next, "pglist_data",
+	    "pgdat_next");
 
 	/*
 	 * Get offsets of the zone's members.
@@ -1443,6 +1584,14 @@ get_structure_info(struct DumpInfo *info
 }
 
 int
+get_srcfile_info(struct DumpInfo *info)
+{
+	TYPEDEF_SRCFILE_INIT(pud_t, "pud_t");
+
+	return TRUE;
+}
+
+int
 is_sparsemem_extreme(struct DumpInfo *info)
 {
 	if (ARRAY_LENGTH(mem_section)
@@ -1462,7 +1611,12 @@ get_mem_type(struct DumpInfo *info)
 	    || (OFFSET(page._count) == NOT_FOUND_STRUCTURE)
 	    || (OFFSET(page.mapping) == NOT_FOUND_STRUCTURE)) {
 		ret = NOT_FOUND_MEMTYPE;
-	} else if ((SYMBOL(node_data) != NOT_FOUND_SYMBOL)
+	} else if ((((SYMBOL(node_data) != NOT_FOUND_SYMBOL)
+	        && (ARRAY_LENGTH(node_data) != NOT_FOUND_STRUCTURE))
+	    || ((SYMBOL(pgdat_list) != NOT_FOUND_SYMBOL)
+	        && (OFFSET(pglist_data.pgdat_next) != NOT_FOUND_STRUCTURE))
+	    || ((SYMBOL(pgdat_list) != NOT_FOUND_SYMBOL)
+	        && (ARRAY_LENGTH(pgdat_list) != NOT_FOUND_STRUCTURE)))
 	    && (SIZE(pglist_data) != NOT_FOUND_STRUCTURE)
 	    && (OFFSET(pglist_data.node_mem_map) != NOT_FOUND_STRUCTURE)
 	    && (OFFSET(pglist_data.node_start_pfn) != NOT_FOUND_STRUCTURE)
@@ -1507,6 +1661,9 @@ generate_config(struct DumpInfo *info)
 	if (!get_structure_info(info))
 		return FALSE;
 
+	if (!get_srcfile_info(info))
+		return FALSE;
+
 	if ((SYMBOL(system_utsname) == NOT_FOUND_SYMBOL)
 	    && (SYMBOL(init_uts_ns) == NOT_FOUND_SYMBOL)) {
 		ERRMSG("Can't get the symbol of system_utsname.\n");
@@ -1539,6 +1696,7 @@ generate_config(struct DumpInfo *info)
 	WRITE_SYMBOL("system_utsname", system_utsname);
 	WRITE_SYMBOL("init_uts_ns", init_uts_ns);
 	WRITE_SYMBOL("_stext", _stext);
+	WRITE_SYMBOL("swapper_pg_dir", swapper_pg_dir);
 	WRITE_SYMBOL("phys_base", phys_base);
 	WRITE_SYMBOL("node_online_map", node_online_map);
 	WRITE_SYMBOL("node_data", node_data);
@@ -1572,6 +1730,8 @@ generate_config(struct DumpInfo *info)
 	    pglist_data.node_start_pfn);
 	WRITE_MEMBER_OFFSET("pglist_data.node_spanned_pages",
 	    pglist_data.node_spanned_pages);
+	WRITE_MEMBER_OFFSET("pglist_data.pgdat_next",
+	    pglist_data.pgdat_next);
 	WRITE_MEMBER_OFFSET("zone.free_pages", zone.free_pages);
 	WRITE_MEMBER_OFFSET("zone.free_area", zone.free_area);
 	WRITE_MEMBER_OFFSET("zone.vm_stat", zone.vm_stat);
@@ -1589,6 +1749,11 @@ generate_config(struct DumpInfo *info)
 
 	WRITE_ARRAY_LENGTH("zone.free_area", zone.free_area);
 
+	/*
+	 * write the source file of 1st kernel
+	 */
+	WRITE_SRCFILE("pud_t", pud_t);
+
 	return TRUE;
 }
 
@@ -1631,6 +1796,7 @@ read_config_basic_info(struct DumpInfo *
 			break;
 	}
 	info->page_size = page_size;
+	info->page_shift = ffs(info->page_size) - 1;
 
 	if (!get_release || !info->page_size) {
 		ERRMSG("Invalid format in %s", info->name_configfile);
@@ -1701,6 +1867,30 @@ read_config_structure(struct DumpInfo *i
 }
 
 int
+read_config_string(struct DumpInfo *info, char *str_in, char *str_out)
+{
+	char buf[BUFSIZE_FGETS];
+	unsigned int i;
+
+	if (fseek(info->file_configfile, 0, SEEK_SET) < 0) {
+		ERRMSG("Can't seek the config file(%s). %s\n",
+		    info->name_configfile, strerror(errno));
+		return FALSE;
+	}
+
+	while (fgets(buf, BUFSIZE_FGETS, info->file_configfile)) {
+		i = strlen(buf);
+		if (buf[i - 1] == '\n')
+			buf[i - 1] = '\0';
+		if (strncmp(buf, str_in, strlen(str_in)) == 0) {
+			strncpy(str_out, buf + strlen(str_in), BUFSIZE_FGETS - strlen(str_in));
+			break;
+		}
+	}
+	return TRUE;
+}
+
+int
 read_config(struct DumpInfo *info)
 {
 	if (!read_config_basic_info(info))
@@ -1713,6 +1903,7 @@ read_config(struct DumpInfo *info)
 	READ_SYMBOL("system_utsname", system_utsname);
 	READ_SYMBOL("init_uts_ns", init_uts_ns);
 	READ_SYMBOL("_stext", _stext);
+	READ_SYMBOL("swapper_pg_dir", swapper_pg_dir);
 	READ_SYMBOL("phys_base", phys_base);
 	READ_SYMBOL("node_online_map", node_online_map);
 	READ_SYMBOL("node_data", node_data);
@@ -1739,6 +1930,8 @@ read_config(struct DumpInfo *info)
 	    pglist_data.node_start_pfn);
 	READ_MEMBER_OFFSET("pglist_data.node_spanned_pages",
 	    pglist_data.node_spanned_pages);
+	READ_MEMBER_OFFSET("pglist_data.pgdat_next",
+	    pglist_data.pgdat_next);
 	READ_MEMBER_OFFSET("zone.free_pages", zone.free_pages);
 	READ_MEMBER_OFFSET("zone.free_area", zone.free_area);
 	READ_MEMBER_OFFSET("zone.vm_stat", zone.vm_stat);
@@ -1752,6 +1945,8 @@ read_config(struct DumpInfo *info)
 	READ_ARRAY_LENGTH("mem_section", mem_section);
 	READ_ARRAY_LENGTH("zone.free_area", zone.free_area);
 
+	READ_SRCFILE("pud_t", pud_t);
+
 	return TRUE;
 }
 
@@ -1837,6 +2032,7 @@ next_online_node(int first)
 unsigned long
 next_online_pgdat(struct DumpInfo *info, int node)
 {
+	int i;
 	unsigned long pgdat;
 
 	/*
@@ -1883,6 +2079,33 @@ pgdat2:
 
 pgdat3:
 	/*
+	 * linux-2.6.16 or before
+	 */
+	if ((SYMBOL(pgdat_list) == NOT_FOUND_SYMBOL)
+	    || (OFFSET(pglist_data.pgdat_next) == NOT_FOUND_STRUCTURE))
+		goto pgdat4;
+
+	if (!readmem(info, SYMBOL(pgdat_list), &pgdat, sizeof pgdat))
+		goto pgdat4;
+
+	if (!is_kvaddr(pgdat))
+		goto pgdat4;
+
+	if (node == 0)
+		return pgdat;
+
+	for (i = 1; i <= node; i++) {
+		if (!readmem(info, pgdat + OFFSET(pglist_data.pgdat_next),
+		    &pgdat, sizeof pgdat))
+			goto pgdat4;
+
+		if (!is_kvaddr(pgdat))
+			goto pgdat4;
+	}
+	return pgdat;
+
+pgdat4:
+	/*
 	 * Get the pglist_data structure from symbol "contig_page_data".
 	 */
 	if (SYMBOL(contig_page_data) == NOT_FOUND_SYMBOL)
@@ -1942,17 +2165,9 @@ get_mm_flatmem(struct DumpInfo *info)
 int
 get_mm_discontigmem(struct DumpInfo *info)
 {
-	int num_nodes, node;
+	int i, j, num_nodes, node, num_mem_map;
 	unsigned long pgdat, mem_map, pfn_start, pfn_end, node_spanned_pages;
-
-	info->num_mem_map = vt->numnodes;
-
-	if ((info->mem_map_data = (struct mem_map_data *)
-	    malloc(sizeof(struct mem_map_data)*info->num_mem_map)) == NULL) {
-		ERRMSG("Can't allocate memory for the mem_map_data. %s\n",
-		    strerror(errno));
-		return FALSE;
-	}
+	struct mem_map_data temp_mmd, mmd[vt->numnodes];
 
 	/*
 	 * Get the first node_id.
@@ -1982,7 +2197,10 @@ get_mm_discontigmem(struct DumpInfo *inf
 			return FALSE;
 		}
 		pfn_end = pfn_start + node_spanned_pages;
-		dump_mem_map(info, pfn_start, pfn_end, mem_map, num_nodes - 1);
+
+		mmd[num_nodes - 1].pfn_start = pfn_start;
+		mmd[num_nodes - 1].pfn_end   = pfn_end;
+		mmd[num_nodes - 1].mem_map   = mem_map;
 
 		/*
 		 * Get pglist_data of the next node.
@@ -1998,6 +2216,79 @@ get_mm_discontigmem(struct DumpInfo *inf
 			}
 		}
 	}
+
+	/*
+	 * Sort mem_map by pfn_start.
+	 */
+	for (i = 0; i < vt->numnodes - 1; i++) {
+		for (j = i + 1; j < vt->numnodes; j++) {
+			if (mmd[j].pfn_start < mmd[i].pfn_start) {
+				temp_mmd = mmd[j];
+				mmd[j] = mmd[i];
+				mmd[i] = temp_mmd;
+			}
+		}
+	}
+
+	/*
+	 * Calculate the number of mem_map.
+	 */
+	info->num_mem_map = vt->numnodes;
+	if (mmd[0].pfn_start != 0)
+		info->num_mem_map++;
+
+	for (i = 0; i < vt->numnodes - 1; i++) {
+		if (mmd[i].pfn_end > mmd[i + 1].pfn_start) {
+			ERRMSG("The mem_map overlapped.\n");
+			ERRMSG("mmd[%d].pfn_end   = %llx\n", i, mmd[i].pfn_end);
+			ERRMSG("mmd[%d].pfn_start = %llx\n", i + 1, mmd[i + 1].pfn_start);
+			return FALSE;
+		} else if (mmd[i].pfn_end == mmd[i + 1].pfn_start)
+			/*
+			 * Continuous mem_map
+			 */
+			continue;
+
+		/*
+		 * Discontinuous mem_map
+		 */
+		info->num_mem_map++;
+	}
+	if (mmd[vt->numnodes - 1].pfn_end != info->max_mapnr)
+		info->num_mem_map++;
+
+	if ((info->mem_map_data = (struct mem_map_data *)
+	    malloc(sizeof(struct mem_map_data)*info->num_mem_map)) == NULL) {
+		ERRMSG("Can't allocate memory for the mem_map_data. %s\n",
+		    strerror(errno));
+		return FALSE;
+	}
+
+	/*
+	 * Create mem_map data.
+	 */
+	num_mem_map = 0;
+	if (mmd[0].pfn_start != 0) {
+		dump_mem_map(info, 0, mmd[0].pfn_start, NOT_MEMMAP_ADDR,
+		    num_mem_map);
+		num_mem_map++;
+	}
+	for (i = 0; i < vt->numnodes; i++) {
+		dump_mem_map(info, mmd[i].pfn_start, mmd[i].pfn_end,
+		    mmd[i].mem_map, num_mem_map);
+		num_mem_map++;
+		if ((i < vt->numnodes - 1)
+		    && (mmd[i].pfn_end != mmd[i + 1].pfn_start)) {
+			dump_mem_map(info, mmd[i].pfn_end, mmd[i +1].pfn_start,
+			    NOT_MEMMAP_ADDR, num_mem_map);
+			num_mem_map++;
+		}
+	}
+	i = vt->numnodes - 1;
+	if (mmd[i].pfn_end != info->max_mapnr)
+		dump_mem_map(info, mmd[i].pfn_end, info->max_mapnr,
+		    NOT_MEMMAP_ADDR, num_mem_map);
+
 	return TRUE;
 }
 
@@ -2205,11 +2496,14 @@ initial(struct DumpInfo *info)
 		}
 		if (!get_structure_info(info))
 			return FALSE;
+
+		if (!get_srcfile_info(info))
+			return FALSE;
 	}
-	if (!check_release(info))
+	if (!get_machdep_info(info))
 		return FALSE;
 
-	if (!get_machdep_info(info))
+	if (!check_release(info))
 		return FALSE;
 
 	if (!get_numnodes(info))
@@ -3382,8 +3676,8 @@ print_progress(unsigned long current, un
 	} else
 		progress = 100;
 
-	ERRMSG("\r");
-	ERRMSG("[%3d %%]", progress);
+	MSG("\r");
+	MSG("[%3d %%]", progress);
 }
 
 int
@@ -3462,7 +3756,6 @@ write_elf_pages(struct DumpInfo *info)
 
 	off_seg_load  = info->offset_load_dumpfile;
 	cd_seg.offset = info->offset_load_dumpfile;
-	off_memory = 0;
 
 	if (info->flag_elf64) { /* ELF64 */
 		cd_hdr.offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr);
@@ -3488,7 +3781,7 @@ write_elf_pages(struct DumpInfo *info)
 			}
 			if (load64.p_type != PT_LOAD)
 				continue;
-
+			off_memory= load64.p_offset;
 			paddr     = load64.p_paddr;
 			pfn_start = load64.p_paddr / page_size;
 			pfn_end   = (load64.p_paddr+ load64.p_memsz)/page_size;
@@ -3501,6 +3794,7 @@ write_elf_pages(struct DumpInfo *info)
 			}
 			if (load32.p_type != PT_LOAD)
 				continue;
+			off_memory= load32.p_offset;
 			paddr     = load32.p_paddr;
 			pfn_start = load32.p_paddr / page_size;
 			pfn_end   = (load32.p_paddr+ load32.p_memsz)/page_size;
@@ -3588,7 +3882,7 @@ write_elf_pages(struct DumpInfo *info)
 			/*
 			 * Write a PT_LOAD segment.
 			 */
-			off_memory = paddr_to_offset(info, paddr);
+			off_memory = paddr_to_offset2(info, paddr, off_memory);
 			if (!off_memory) {
 				ERRMSG("Can't convert physaddr(%llx) to a offset.\n",
 				    paddr);
@@ -3680,7 +3974,7 @@ write_elf_pages(struct DumpInfo *info)
 		/*
 		 * Write a PT_LOAD segment.
 		 */
-		off_memory = paddr_to_offset(info, paddr);
+		off_memory = paddr_to_offset2(info, paddr, off_memory);
 		if (!off_memory) {
 			ERRMSG("Can't convert physaddr(%llx) to a offset.\n",
 			    paddr);
@@ -4196,7 +4490,7 @@ main(int argc, char *argv[])
 			dwarf_info.vmlinux_name = optarg;
 			break;
 		case '?':
-			ERRMSG("Commandline parameter is invalid.\n");
+			MSG("Commandline parameter is invalid.\n");
 			print_usage();
 			goto out;
 		}
@@ -4214,7 +4508,7 @@ main(int argc, char *argv[])
 		 * Check parameters to generate the configuration file.
 		 */
 		if (argc != optind) {
-			ERRMSG("Commandline parameter is invalid.\n");
+			MSG("Commandline parameter is invalid.\n");
 			print_usage();
 			goto out;
 		}
@@ -4222,7 +4516,7 @@ main(int argc, char *argv[])
 		    || info->flag_elf_dumpfile || info->flag_read_config
 		    || !info->flag_vmlinux || info->flag_flatten
 		    || info->flag_rearrange) {
-			ERRMSG("Commandline parameter is invalid.\n");
+			MSG("Commandline parameter is invalid.\n");
 			print_usage();
 			goto out;
 		}
@@ -4232,13 +4526,13 @@ main(int argc, char *argv[])
 		 */
 		if ((info->dump_level < MIN_DUMP_LEVEL)
 		    || (MAX_DUMP_LEVEL < info->dump_level)) {
-			ERRMSG("Dump_level is invalid.\n");
+			MSG("Dump_level is invalid.\n");
 			print_usage();
 			goto out;
 		}
 		if ((info->flag_compress && info->flag_elf_dumpfile)
 		    || (info->flag_vmlinux && info->flag_read_config)) {
-			ERRMSG("Commandline parameter is invalid.\n");
+			MSG("Commandline parameter is invalid.\n");
 			print_usage();
 			goto out;
 		}
@@ -4270,7 +4564,7 @@ main(int argc, char *argv[])
 			info->name_dumpfile = argv[optind];
 
 		} else {
-			ERRMSG("Commandline parameter is invalid.\n");
+			MSG("Commandline parameter is invalid.\n");
 			print_usage();
 			goto out;
 		}
@@ -4348,11 +4642,11 @@ main(int argc, char *argv[])
 	}
 	retcd = COMPLETED;
 out:
-	ERRMSG("\n");
+	MSG("\n");
 	if (retcd == COMPLETED)
 		MSG("makedumpfile Completed.\n");
 	else
-		ERRMSG("makedumpfile Failed.\n");
+		MSG("makedumpfile Failed.\n");
 
 	if (info->fd_memory)
 		close(info->fd_memory);
diff -puN backup/v1.1.3/makedumpfile.h makedumpfile/makedumpfile.h
--- backup/v1.1.3/makedumpfile.h	2007-04-13 15:44:55.000000000 +0900
+++ makedumpfile/makedumpfile.h	2007-05-31 12:03:18.000000000 +0900
@@ -64,6 +64,12 @@ enum {
 #define LSEEKED_PDESC	(2)
 #define LSEEKED_PDATA	(3)
 
+/*
+ * Memory flags
+ */
+#define MEMORY_PAGETABLE_4L	(1 << 0)
+#define MEMORY_PAGETABLE_3L	(1 << 1)
+
 static inline int
 test_bit(int nr, unsigned long addr)
 {
@@ -268,6 +274,29 @@ do { \
 } while (0)
 
 /*
+ * for source file name
+ */
+#define SRCFILE(X)		(srcfile_table.X)
+#define	TYPEDEF_SRCFILE_INIT(decl_name, str_decl_name) \
+do { \
+	get_source_filename(str_decl_name, SRCFILE(decl_name), DWARF_INFO_GET_TYPEDEF_SRCNAME); \
+} while (0)
+
+#define WRITE_SRCFILE(str_decl_name, decl_name) \
+do { \
+	if (strlen(SRCFILE(decl_name))) { \
+		fprintf(info->file_configfile, "%s%s\n", \
+		    STR_SRCFILE(str_decl_name), SRCFILE(decl_name)); \
+	} \
+} while (0)
+
+#define READ_SRCFILE(str_decl_name, decl_name) \
+do { \
+	if (!read_config_string(info, STR_SRCFILE(str_decl_name), SRCFILE(decl_name))) \
+		return FALSE; \
+} while (0)
+
+/*
  * kernel version
  */
 #define VERSION_2_6_15		(15)
@@ -289,6 +318,7 @@ do { \
 #define STR_SIZE(X)	"SIZE("X")="
 #define STR_OFFSET(X)	"OFFSET("X")="
 #define STR_LENGTH(X)	"LENGTH("X")="
+#define STR_SRCFILE(X)	"SRCFILE("X")="
 
 /*
  * common value
@@ -367,6 +397,37 @@ do { \
 #define _SECTION_SIZE_BITS	(30)
 #define _MAX_PHYSMEM_BITS	(50)
 #define SIZEOF_NODE_ONLINE_MAP	(32)
+
+/*
+ * 3 Levels paging
+ */
+#define _PAGE_PPN_MASK		(((1UL << _MAX_PHYSMEM_BITS) - 1) & ~0xfffUL)
+#define PAGE_SHIFT		(info->page_shift)
+#define PTRS_PER_PTD_SHIFT	(PAGE_SHIFT - 3)
+
+#define PMD_SHIFT		(PAGE_SHIFT + PTRS_PER_PTD_SHIFT)
+#define PGDIR_SHIFT_3L		(PMD_SHIFT  + PTRS_PER_PTD_SHIFT)
+
+#define MASK_POFFSET	((1UL << PAGE_SHIFT) - 1)
+#define MASK_PTE	((1UL << PMD_SHIFT) - 1) &~((1UL << PAGE_SHIFT) - 1)
+#define MASK_PMD	((1UL << PGDIR_SHIFT_3L) - 1) &~((1UL << PMD_SHIFT) - 1)
+#define MASK_PGD_3L	((1UL << REGION_SHIFT) - 1) & (~((1UL << PGDIR_SHIFT_3L) - 1))
+
+/*
+ * 4 Levels paging
+ */
+#define PUD_SHIFT		(PMD_SHIFT + PTRS_PER_PTD_SHIFT)
+#define PGDIR_SHIFT_4L		(PUD_SHIFT + PTRS_PER_PTD_SHIFT)
+
+#define MASK_PUD   	((1UL << REGION_SHIFT) - 1) & (~((1UL << PUD_SHIFT) - 1))
+#define MASK_PGD_4L	((1UL << REGION_SHIFT) - 1) & (~((1UL << PGDIR_SHIFT_4L) - 1))
+
+/*
+ * Key for distinguishing PGTABLE_3L or PGTABLE_4L.
+ */
+#define STR_PUD_T_3L	"include/asm-generic/pgtable-nopud.h"
+#define STR_PUD_T_4L	"include/asm/page.h"
+
 #endif          /* ia64 */
 
 /*
@@ -398,14 +459,20 @@ int get_machdep_info_ppc64();
 #ifdef __ia64__ /* ia64 */
 int get_phys_base_ia64();
 int get_machdep_info_ia64();
+off_t vaddr_to_offset_ia64();
 #define get_machdep_info(X)	get_machdep_info_ia64(X)
 #define get_phys_base(X)	get_phys_base_ia64(X)
-#define vaddr_to_offset(X, Y)	vaddr_to_offset_general(X, Y)
-#define VADDR_REGION(X)		((X) >> REGION_SHIFT)
+#define vaddr_to_offset(X, Y)	vaddr_to_offset_ia64(X, Y)
+#define VADDR_REGION(X)		(((unsigned long)(X)) >> REGION_SHIFT)
 #endif          /* ia64 */
 
 #define MSG(x...)	fprintf(stderr, x)
-#define ERRMSG(x...)	fprintf(stderr, x)
+#define ERRMSG(x...) \
+do { \
+	fprintf(stderr, __FUNCTION__); \
+	fprintf(stderr, ": "); \
+	fprintf(stderr, x); \
+} while (0)
 
 struct pt_load_segment {
 	loff_t			file_offset;
@@ -486,11 +553,14 @@ struct DumpInfo {
 	int		flag_rearrange;      /* flag of creating dumpfile from
 						flattened format */
 	long		page_size;           /* size of page */
+	long		page_shift;
 	unsigned long long	max_mapnr;   /* number of page descriptor */
 	unsigned long   section_size_bits;
 	unsigned long   max_physmem_bits;
 	unsigned long   sections_per_root;
 	unsigned long	phys_base;
+	unsigned long   kernel_start;
+	unsigned long   vmalloc_start;
 
 	/*
 	 * diskdimp info:
@@ -514,6 +584,7 @@ struct DumpInfo {
 	 */
 	unsigned int		num_mem_map;
 	struct mem_map_data	*mem_map_data;
+	unsigned int		mem_flags;
 
 	/*
 	 * Dump memory image info:
@@ -555,6 +626,7 @@ struct symbol_table {
 	unsigned long	system_utsname;
 	unsigned long	init_uts_ns;
 	unsigned long	_stext;
+	unsigned long	swapper_pg_dir;
 	unsigned long	phys_base;
 	unsigned long	node_online_map;
 	unsigned long	node_data;
@@ -593,6 +665,7 @@ struct offset_table {
 		long	node_mem_map;
 		long	node_start_pfn;
 		long	node_spanned_pages;
+		long	pgdat_next;
 	} pglist_data;
 	struct free_area {
 		long	free_list;
@@ -622,10 +695,19 @@ struct array_table {
 	} zone;
 };
 
+#define LEN_SRCFILE				(50)
+struct srcfile_table {
+	/*
+	 * typedef
+	 */
+	char	pud_t[LEN_SRCFILE];
+};
+
 extern struct symbol_table	symbol_table;
 extern struct size_table	size_table;
 extern struct offset_table	offset_table;
 extern struct array_table	array_table;
+extern struct srcfile_table	srcfile_table;
 
 /*
  * Debugging information
@@ -636,6 +718,7 @@ extern struct array_table	array_table;
 #define DWARF_INFO_GET_MEMBER_ARRAY_LENGTH	(4)
 #define DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH	(5)
 #define DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE	(6)
+#define DWARF_INFO_GET_TYPEDEF_SRCNAME		(7)
 
 struct dwarf_info {
 	unsigned int	cmd;		/* IN */
@@ -644,10 +727,17 @@ struct dwarf_info {
 	char	*struct_name;		/* IN */
 	char	*symbol_name;		/* IN */
 	char	*member_name;		/* IN */
+	char	*decl_name;		/* IN */
 	long	struct_size;		/* OUT */
 	long	member_offset;		/* OUT */
 	long	array_length;		/* OUT */
+	char	src_name[LEN_SRCFILE];	/* OUT */
 };
 
 extern struct dwarf_info	dwarf_info;
 
+int readmem();
+off_t paddr_to_offset();
+unsigned long long vaddr_to_paddr();
+unsigned long long paddr_to_vaddr();
+
_



More information about the kexec mailing list