Re: [PATCH makedumpfile] handle mem_section as either a pointer or an array

2018-05-14 Thread Thadeu Lima de Souza Cascardo
On Mon, May 14, 2018 at 07:40:21AM +, Masaki Tachibana wrote:
> Hi Thadeu,
> 
> So sorry for the late reply.
> I will merge the patch into V1.6.4 with the following modifying 
> because I have already accepted "Always use bigger SECTION_MAP_MASK" patch.
> 
> 63,68c63,64
> <   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 &= SECTION_MAP_MASK;
> > + mask = SECTION_MAP_MASK;
> 

Ack. That should be enough for a fixup.
Thanks.
Cascardo.

> 
> Thanks
> Tachibana
> 
> > -Original Message-
> > From: kexec [mailto:kexec-boun...@lists.infradead.org] On Behalf Of Masaki 
> > Tachibana
> > Sent: Monday, March 05, 2018 6:16 PM
> > To: Thadeu Lima de Souza Cascardo 
> > Cc: Hayashi Masahiko() ; 
> > kexec@lists.infradead.org
> > Subject: RE: [PATCH makedumpfile] handle mem_section as either a pointer or 
> > an array
> > 
> > Hi Thadeu,
> > 
> > Sorry for the late reply.
> > "handle mem_section as either a pointer or an array" patch and
> > "Always use bigger SECTION_MAP_MASK" patch modify the same line.
> > I would like to reply about both patches by the end of the next week.
> > 
> > 
> > Thanks
> > Tachibana
> > 
> > 
> > > -Original Message-
> > > From: kexec [mailto:kexec-boun...@lists.infradead.org] On Behalf Of 
> > > Thadeu Lima de Souza Cascardo
> > > Sent: Friday, March 02, 2018 11:33 PM
> > > To: kexec@lists.infradead.org
> > > Subject: Re: [PATCH makedumpfile] handle mem_section as either a pointer 
> > > or an array
> > >
> > > Any comments or reviews on the patch below?
> > >
> > > Thanks.
> > > Cascardo.
> > >
> > > On Mon, Feb 19, 2018 at 05:04:59PM -0300, Thadeu Lima de Souza Cascardo 
> > > wrote:
> > > > Some kernel versions that have been recently shipped have mem_section 
> > > > point to
> > > > a pointer to the array, instead of pointing directly to the array. That 
> > > > only
> > > > happens on SPARSEMEM_EXTREME configurations.
> > > >
> > > > As dwarf information might not be present that would have allowed us to 
> > > > detect
> > > > which type it is, we need to try it either as an array or as the 
> > > > pointer to the
> > > > array. Then, we validate all section_mem_map: they must either be 
> > > > present or
> > > > null. If any problems are found when traversing it, consider it 
> > > > invalid. Only
> > > > one way may be valid. Otherwise, fail.
> > > >
> > > > This has been tested with both types of kernels and succeeded in 
> > > > producing a
> > > > compressed dump that could be analyzed with crash 7.2.1.
> > > >
> > > > Signed-off-by: Thadeu Lima de Souza Cascardo 
> > > > ---
> > > >  makedumpfile.c | 153 
> > > > +++--
> > > >  makedumpfile.h |   1 +
> > > >  2 files changed, 118 insertions(+), 36 deletions(-)
> > > >
> > > > 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;
> > > >  }
> > > >
> > > > 

RE: [PATCH makedumpfile] handle mem_section as either a pointer or an array

2018-05-14 Thread Masaki Tachibana
Hi Thadeu,

So sorry for the late reply.
I will merge the patch into V1.6.4 with the following modifying 
because I have already accepted "Always use bigger SECTION_MAP_MASK" patch.

63,68c63,64
<   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 &= SECTION_MAP_MASK;
> + mask = SECTION_MAP_MASK;


Thanks
Tachibana

> -Original Message-
> From: kexec [mailto:kexec-boun...@lists.infradead.org] On Behalf Of Masaki 
> Tachibana
> Sent: Monday, March 05, 2018 6:16 PM
> To: Thadeu Lima de Souza Cascardo 
> Cc: Hayashi Masahiko() ; kexec@lists.infradead.org
> Subject: RE: [PATCH makedumpfile] handle mem_section as either a pointer or 
> an array
> 
> Hi Thadeu,
> 
> Sorry for the late reply.
> "handle mem_section as either a pointer or an array" patch and
> "Always use bigger SECTION_MAP_MASK" patch modify the same line.
> I would like to reply about both patches by the end of the next week.
> 
> 
> Thanks
> Tachibana
> 
> 
> > -Original Message-
> > From: kexec [mailto:kexec-boun...@lists.infradead.org] On Behalf Of Thadeu 
> > Lima de Souza Cascardo
> > Sent: Friday, March 02, 2018 11:33 PM
> > To: kexec@lists.infradead.org
> > Subject: Re: [PATCH makedumpfile] handle mem_section as either a pointer or 
> > an array
> >
> > Any comments or reviews on the patch below?
> >
> > Thanks.
> > Cascardo.
> >
> > On Mon, Feb 19, 2018 at 05:04:59PM -0300, Thadeu Lima de Souza Cascardo 
> > wrote:
> > > Some kernel versions that have been recently shipped have mem_section 
> > > point to
> > > a pointer to the array, instead of pointing directly to the array. That 
> > > only
> > > happens on SPARSEMEM_EXTREME configurations.
> > >
> > > As dwarf information might not be present that would have allowed us to 
> > > detect
> > > which type it is, we need to try it either as an array or as the pointer 
> > > to the
> > > array. Then, we validate all section_mem_map: they must either be present 
> > > or
> > > null. If any problems are found when traversing it, consider it invalid. 
> > > Only
> > > one way may be valid. Otherwise, fail.
> > >
> > > This has been tested with both types of kernels and succeeded in 
> > > producing a
> > > compressed dump that could be analyzed with crash 7.2.1.
> > >
> > > Signed-off-by: Thadeu Lima de Souza Cascardo 
> > > ---
> > >  makedumpfile.c | 153 
> > > +++--
> > >  makedumpfile.h |   1 +
> > >  2 files changed, 118 insertions(+), 36 deletions(-)
> > >
> > > 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

RE: [PATCH makedumpfile] handle mem_section as either a pointer or an array

2018-03-05 Thread Masaki Tachibana
Hi Thadeu,

Sorry for the late reply.
"handle mem_section as either a pointer or an array" patch and
"Always use bigger SECTION_MAP_MASK" patch modify the same line.
I would like to reply about both patches by the end of the next week.


Thanks
Tachibana


> -Original Message-
> From: kexec [mailto:kexec-boun...@lists.infradead.org] On Behalf Of Thadeu 
> Lima de Souza Cascardo
> Sent: Friday, March 02, 2018 11:33 PM
> To: kexec@lists.infradead.org
> Subject: Re: [PATCH makedumpfile] handle mem_section as either a pointer or 
> an array
> 
> Any comments or reviews on the patch below?
> 
> Thanks.
> Cascardo.
> 
> On Mon, Feb 19, 2018 at 05:04:59PM -0300, Thadeu Lima de Souza Cascardo wrote:
> > Some kernel versions that have been recently shipped have mem_section point 
> > to
> > a pointer to the array, instead of pointing directly to the array. That only
> > happens on SPARSEMEM_EXTREME configurations.
> >
> > As dwarf information might not be present that would have allowed us to 
> > detect
> > which type it is, we need to try it either as an array or as the pointer to 
> > the
> > array. Then, we validate all section_mem_map: they must either be present or
> > null. If any problems are found when traversing it, consider it invalid. 
> > Only
> > one way may be valid. Otherwise, fail.
> >
> > This has been tested with both types of kernels and succeeded in producing a
> > compressed dump that could be analyzed with crash 7.2.1.
> >
> > Signed-off-by: Thadeu Lima de Souza Cascardo 
> > ---
> >  makedumpfile.c | 153 
> > +++--
> >  makedumpfile.h |   1 +
> >  2 files changed, 118 insertions(+), 36 deletions(-)
> >
> > 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, _mask);
> > +   if (!(map_mask & SECTION_MARKED_PRESENT)) {
> > +   return FALSE;
> > +   }
> > + 

Re: [PATCH makedumpfile] handle mem_section as either a pointer or an array

2018-03-02 Thread Thadeu Lima de Souza Cascardo
Any comments or reviews on the patch below?

Thanks.
Cascardo.

On Mon, Feb 19, 2018 at 05:04:59PM -0300, Thadeu Lima de Souza Cascardo wrote:
> Some kernel versions that have been recently shipped have mem_section point to
> a pointer to the array, instead of pointing directly to the array. That only
> happens on SPARSEMEM_EXTREME configurations.
> 
> As dwarf information might not be present that would have allowed us to detect
> which type it is, we need to try it either as an array or as the pointer to 
> the
> array. Then, we validate all section_mem_map: they must either be present or
> null. If any problems are found when traversing it, consider it invalid. Only
> one way may be valid. Otherwise, fail.
> 
> This has been tested with both types of kernels and succeeded in producing a
> compressed dump that could be analyzed with crash 7.2.1.
> 
> Signed-off-by: Thadeu Lima de Souza Cascardo 
> ---
>  makedumpfile.c | 153 
> +++--
>  makedumpfile.h |   1 +
>  2 files changed, 118 insertions(+), 36 deletions(-)
> 
> 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, _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)
> +{
> + 

[PATCH makedumpfile] handle mem_section as either a pointer or an array

2018-02-19 Thread Thadeu Lima de Souza Cascardo
Some kernel versions that have been recently shipped have mem_section point to
a pointer to the array, instead of pointing directly to the array. That only
happens on SPARSEMEM_EXTREME configurations.

As dwarf information might not be present that would have allowed us to detect
which type it is, we need to try it either as an array or as the pointer to the
array. Then, we validate all section_mem_map: they must either be present or
null. If any problems are found when traversing it, consider it invalid. Only
one way may be valid. Otherwise, fail.

This has been tested with both types of kernels and succeeded in producing a
compressed dump that could be analyzed with crash 7.2.1.

Signed-off-by: Thadeu Lima de Souza Cascardo 
---
 makedumpfile.c | 153 +++--
 makedumpfile.h |   1 +
 2 files changed, 118 insertions(+), 36 deletions(-)

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, _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;
+