diff -Nru makedumpfile-1.6.3/debian/changelog makedumpfile-1.6.3/debian/changelog --- makedumpfile-1.6.3/debian/changelog 2018-02-06 12:53:14.000000000 -0200 +++ makedumpfile-1.6.3/debian/changelog 2018-02-15 11:46:12.000000000 -0200 @@ -1,3 +1,9 @@ +makedumpfile (1:1.6.3-1ubuntu1) unstable; urgency=medium + + * Add support for SPARSEMEM_EXTREME mem_section as a pointer. (LP: #1750021) + + -- Thadeu Lima de Souza Cascardo Thu, 15 Feb 2018 11:46:12 -0200 + makedumpfile (1:1.6.3-1) unstable; urgency=medium * New upstream release. Main new feature: diff -Nru makedumpfile-1.6.3/debian/patches/0003-sparsemem_extreme.patch makedumpfile-1.6.3/debian/patches/0003-sparsemem_extreme.patch --- makedumpfile-1.6.3/debian/patches/0003-sparsemem_extreme.patch 1969-12-31 21:00:00.000000000 -0300 +++ makedumpfile-1.6.3/debian/patches/0003-sparsemem_extreme.patch 2018-02-15 11:46:12.000000000 -0200 @@ -0,0 +1,239 @@ +diff --git a/makedumpfile.c b/makedumpfile.c +index ed138d3..cd3fa4d 100644 +--- a/makedumpfile.c ++++ b/makedumpfile.c +@@ -3297,7 +3297,7 @@ get_mm_discontigmem(void) + return TRUE; + } + +-unsigned long ++static unsigned long + nr_to_section(unsigned long nr, unsigned long *mem_sec) + { + unsigned long addr; +@@ -3311,17 +3311,17 @@ nr_to_section(unsigned long nr, unsigned long *mem_sec) + addr = SYMBOL(mem_section) + (nr * SIZE(mem_section)); + } + +- if (!is_kvaddr(addr)) +- return NOT_KV_ADDR; +- + return addr; + } + +-unsigned long +-section_mem_map_addr(unsigned long addr) ++static unsigned long ++section_mem_map_addr(unsigned long addr, unsigned long *map_mask) + { + char *mem_section; + unsigned long map; ++ unsigned long mask; ++ ++ *map_mask = 0; + + if (!is_kvaddr(addr)) + return NOT_KV_ADDR; +@@ -3338,15 +3338,19 @@ section_mem_map_addr(unsigned long addr) + } + map = ULONG(mem_section + OFFSET(mem_section.section_mem_map)); + if (info->kernel_version < KERNEL_VERSION(4, 13, 0)) +- map &= SECTION_MAP_MASK_4_12; ++ mask = SECTION_MAP_MASK_4_12; + else +- map &= SECTION_MAP_MASK; ++ mask = SECTION_MAP_MASK; ++ *map_mask = map & ~mask; ++ if (map == 0x0) ++ *map_mask |= SECTION_MARKED_PRESENT; ++ map &= mask; + free(mem_section); + + return map; + } + +-unsigned long ++static unsigned long + sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long section_nr) + { + unsigned long mem_map; +@@ -3354,17 +3358,110 @@ sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long section_nr) + mem_map = coded_mem_map + + (SECTION_NR_TO_PFN(section_nr) * SIZE(page)); + +- if (!is_kvaddr(mem_map)) +- return NOT_KV_ADDR; + return mem_map; + } ++ ++/* ++ * On some kernels, mem_section may be a pointer or an array, when ++ * SPARSEMEM_EXTREME is on. ++ * ++ * We assume that section_mem_map is either 0 or has the present bit set. ++ * ++ */ ++ ++static int ++validate_mem_section(unsigned long *mem_sec, ++ unsigned long mem_section_ptr, unsigned int mem_section_size, ++ unsigned long *mem_maps, unsigned int num_section) ++{ ++ unsigned int section_nr; ++ unsigned long map_mask; ++ unsigned long section, mem_map; ++ if (!readmem(VADDR, mem_section_ptr, mem_sec, mem_section_size)) { ++ ERRMSG("Can't read mem_section array.\n"); ++ return FALSE; ++ } ++ for (section_nr = 0; section_nr < num_section; section_nr++) { ++ section = nr_to_section(section_nr, mem_sec); ++ if (section == NOT_KV_ADDR) { ++ mem_map = NOT_MEMMAP_ADDR; ++ } else { ++ mem_map = section_mem_map_addr(section, &map_mask); ++ if (!(map_mask & SECTION_MARKED_PRESENT)) { ++ return FALSE; ++ } ++ if (mem_map == 0) { ++ mem_map = NOT_MEMMAP_ADDR; ++ } else { ++ mem_map = sparse_decode_mem_map(mem_map, ++ section_nr); ++ if (!is_kvaddr(mem_map)) { ++ return FALSE; ++ } ++ } ++ } ++ mem_maps[section_nr] = mem_map; ++ } ++ return TRUE; ++} ++ ++static int ++get_mem_section(unsigned int mem_section_size, unsigned long *mem_maps, ++ unsigned int num_section) ++{ ++ unsigned long mem_section_ptr; ++ int ret = FALSE; ++ unsigned long *mem_sec = NULL; ++ ++ if ((mem_sec = malloc(mem_section_size)) == NULL) { ++ ERRMSG("Can't allocate memory for the mem_section. %s\n", ++ strerror(errno)); ++ return FALSE; ++ } ++ ret = validate_mem_section(mem_sec, SYMBOL(mem_section), ++ mem_section_size, mem_maps, num_section); ++ ++ if (is_sparsemem_extreme()) { ++ int symbol_valid = ret; ++ int pointer_valid; ++ int mem_maps_size = sizeof(*mem_maps) * num_section; ++ unsigned long *mem_maps_ex = NULL; ++ if (!readmem(VADDR, SYMBOL(mem_section), &mem_section_ptr, ++ sizeof(mem_section_ptr))) ++ goto out; ++ ++ if ((mem_maps_ex = malloc(mem_maps_size)) == NULL) { ++ ERRMSG("Can't allocate memory for the mem_maps. %s\n", ++ strerror(errno)); ++ goto out; ++ } ++ ++ pointer_valid = validate_mem_section(mem_sec, ++ mem_section_ptr, ++ mem_section_size, ++ mem_maps_ex, ++ num_section); ++ if (pointer_valid) ++ memcpy(mem_maps, mem_maps_ex, mem_maps_size); ++ if (mem_maps_ex) ++ free(mem_maps_ex); ++ ret = symbol_valid ^ pointer_valid; ++ if (!ret) { ++ ERRMSG("Could not validate mem_section.\n"); ++ } ++ } ++out: ++ if (mem_sec != NULL) ++ free(mem_sec); ++ return ret; ++} ++ + int + get_mm_sparsemem(void) + { + unsigned int section_nr, mem_section_size, num_section; + mdf_pfn_t pfn_start, pfn_end; +- unsigned long section, mem_map; +- unsigned long *mem_sec = NULL; ++ unsigned long *mem_maps = NULL; + + int ret = FALSE; + +@@ -3379,13 +3476,12 @@ get_mm_sparsemem(void) + info->sections_per_root = _SECTIONS_PER_ROOT(); + mem_section_size = SIZE(mem_section) * NR_SECTION_ROOTS(); + } +- if ((mem_sec = malloc(mem_section_size)) == NULL) { +- ERRMSG("Can't allocate memory for the mem_section. %s\n", +- strerror(errno)); ++ if ((mem_maps = malloc(sizeof(*mem_maps) * num_section)) == NULL) { ++ ERRMSG("Can't allocate memory for the mem_maps. %s\n", ++ strerror(errno)); + return FALSE; + } +- if (!readmem(VADDR, SYMBOL(mem_section), mem_sec, +- mem_section_size)) { ++ if (!get_mem_section(mem_section_size, mem_maps, num_section)) { + ERRMSG("Can't get the address of mem_section.\n"); + goto out; + } +@@ -3397,31 +3493,16 @@ get_mm_sparsemem(void) + goto out; + } + for (section_nr = 0; section_nr < num_section; section_nr++) { +- section = nr_to_section(section_nr, mem_sec); +- if (section == NOT_KV_ADDR) { +- mem_map = NOT_MEMMAP_ADDR; +- } else { +- mem_map = section_mem_map_addr(section); +- if (mem_map == 0) { +- mem_map = NOT_MEMMAP_ADDR; +- } else { +- mem_map = sparse_decode_mem_map(mem_map, +- section_nr); +- if (!is_kvaddr(mem_map)) +- mem_map = NOT_MEMMAP_ADDR; +- } +- } + pfn_start = section_nr * PAGES_PER_SECTION(); + pfn_end = pfn_start + PAGES_PER_SECTION(); + if (info->max_mapnr < pfn_end) + pfn_end = info->max_mapnr; +- dump_mem_map(pfn_start, pfn_end, mem_map, section_nr); ++ dump_mem_map(pfn_start, pfn_end, mem_maps[section_nr], section_nr); + } + ret = TRUE; + out: +- if (mem_sec != NULL) +- free(mem_sec); +- ++ if (mem_maps != NULL) ++ free(mem_maps); + return ret; + } + +diff --git a/makedumpfile.h b/makedumpfile.h +index 01eece2..58e1aaa 100644 +--- a/makedumpfile.h ++++ b/makedumpfile.h +@@ -184,6 +184,7 @@ isAnon(unsigned long mapping) + #define SECTIONS_PER_ROOT() (info->sections_per_root) + #define SECTION_ROOT_MASK() (SECTIONS_PER_ROOT() - 1) + #define SECTION_NR_TO_ROOT(sec) ((sec) / SECTIONS_PER_ROOT()) ++#define SECTION_MARKED_PRESENT (1UL<<0) + #define SECTION_IS_ONLINE (1UL<<2) + #define SECTION_MAP_LAST_BIT (1UL<<3) + #define SECTION_MAP_MASK_4_12 (~(SECTION_IS_ONLINE-1)) diff -Nru makedumpfile-1.6.3/debian/patches/series makedumpfile-1.6.3/debian/patches/series --- makedumpfile-1.6.3/debian/patches/series 2018-02-06 11:52:01.000000000 -0200 +++ makedumpfile-1.6.3/debian/patches/series 2018-02-15 11:46:12.000000000 -0200 @@ -1,2 +1,3 @@ 0001-Remove-libebl-linkage.patch 0002-adapt-makefile-to-debian.patch +0003-sparsemem_extreme.patch