Skip to contentSkip to conversation

insmod bug causes kernel unwind failures for module text

Linux-ia64 Keith Owens 2 participants 5 messages Jul 30, 2002 – Jul 31, 2002

lore
Share & tools
lore
#0 lore raw
Quoted 5 lines · Dave Anderson

There is a bug in the initialization of the unw_table_entry structures for all kernel modules, such that any unwind operation that comes upon a kernel module text address will fail to find its associated unwind info data in the build_script() routine. (Actually it won't be able to determine what module it belongs to.)

This patch against modutils 2.4.18 fixes it for me. Unless I hear any complaints in the next 24 hours, I will roll modutils 2.4.19 with this change on July 31 11:00 UTC.

Segment base is pretty arbitrary for modules, changing it from start of text to start of module makes it easier to convert offsets to addresses. It is also what hppa{64} does for SEGREL.

Index: 18.2/obj/obj_ia64.c

obj/obj_ia64.c Tue, 30 Jul 2002 17:47:02 +1000 kaos (modutils-2.4/c/0_obj_ia64.c 1.7 644) renamed from obj/obj_ia64.c Fri, 01 Mar 2002 11:39:06 +1100 kaos (modutils-2.4/c/0_obj_ia64.c 1.5 644) +3 -7
@@ -911,12 +911,8 @@ arch_apply_relocation(struct obj_file *f
 
     case R_IA64_SEGREL32LSB :   /* @segrel(sym + add), data4 LSB */
     case R_IA64_SEGREL64LSB :   /* @segrel(sym + add), data8 LSB */
-	if (targsec->header.sh_type & SHT_NOBITS)
-	    v = ifile->bss - v;
-	else if (targsec->header.sh_flags & SHF_EXECINSTR)
-	    v = ifile->text - v;
-	else
-	    v = ifile->data - v;
+	/* Only one segment for modules, see segment_base in arch_archdata */
+	v -= f->baseaddr;
 	if (r_info = R_IA64_SEGREL32LSB)
 	    COPY_32LSB(loc, v);
 	else
@@ -1010,7 +1006,7 @@ arch_archdata (struct obj_file *f, struc
     ad->unw_start = 0;
     ad->unw_end = 0;
     ad->unw_table = 0;
-    ad->segment_base = f->sections[1]->header.sh_addr;
+    ad->segment_base = f->baseaddr;
     for (i = 0; i < f->header.e_shnum; ++i)
     {
 	sec = f->sections[i];
#1 lore raw

Keith,

Unfortunately the patch won't work, at least in the context of the current kernel code, because the following range check in ia64_module_init() causes the insmod to fail:

  if (!mod_bound(archdata->segment_base, 0, mod))
  {
        printk(KERN_ERR "module_arch_init: archdata->unw_table out of bounds.\n");
        return 1;
  }

mod_bound() doesn't include the module struct as part of the module:

  #define mod_bound(p, n, m) ((unsigned long)(p) >= ((unsigned long)(m) +
  ((m)->size_of_struct)) && \
                   (unsigned long)((p)+(n)) <= (unsigned long)(m) + (m)->size)

Dave Anderson

Quoted 43 lines · Keith Owens
Quoted 5 lines · Dave Anderson

There is a bug in the initialization of the unw_table_entry structures for all kernel modules, such that any unwind operation that comes upon a kernel module text address will fail to find its associated unwind info data in the build_script() routine. (Actually it won't be able to determine what module it belongs to.)

This patch against modutils 2.4.18 fixes it for me. Unless I hear any complaints in the next 24 hours, I will roll modutils 2.4.19 with this change on July 31 11:00 UTC.

Segment base is pretty arbitrary for modules, changing it from start of text to start of module makes it easier to convert offsets to addresses. It is also what hppa{64} does for SEGREL.

Index: 18.2/obj/obj_ia64.c

obj/obj_ia64.c Tue, 30 Jul 2002 17:47:02 +1000 kaos (modutils-2.4/c/0_obj_ia64.c 1.7 644) renamed from obj/obj_ia64.c Fri, 01 Mar 2002 11:39:06 +1100 kaos (modutils-2.4/c/0_obj_ia64.c 1.5 644) +3 -7
@@ -911,12 +911,8 @@ arch_apply_relocation(struct obj_file *f
 
     case R_IA64_SEGREL32LSB :   /* @segrel(sym + add), data4 LSB */
     case R_IA64_SEGREL64LSB :   /* @segrel(sym + add), data8 LSB */
-       if (targsec->header.sh_type & SHT_NOBITS)
-           v = ifile->bss - v;
-       else if (targsec->header.sh_flags & SHF_EXECINSTR)
-           v = ifile->text - v;
-       else
-           v = ifile->data - v;
+       /* Only one segment for modules, see segment_base in arch_archdata */
+       v -= f->baseaddr;
        if (r_info = R_IA64_SEGREL32LSB)
            COPY_32LSB(loc, v);
        else
@@ -1010,7 +1006,7 @@ arch_archdata (struct obj_file *f, struc
     ad->unw_start = 0;
     ad->unw_end = 0;
     ad->unw_table = 0;
-    ad->segment_base = f->sections[1]->header.sh_addr;
+    ad->segment_base = f->baseaddr;
     for (i = 0; i < f->header.e_shnum; ++i)
     {
        sec = f->sections[i];
#2 lore raw
In reply to Keith Owens
Quoted 3 lines

if (!mod_bound(archdata->segment_base, 0, mod))

{
      printk(KERN_ERR "module_arch_init: archdata->unw_table out of

bounds.\n");

Quoted 2 lines
      return 1;
}

BTW, the error message is apparently a cut-and-paste error in the kernel code...

Dave Anderson

#3 lore raw
In reply to Keith Owens
Quoted 3 lines · Dave Anderson

Unfortunately the patch won't work, at least in the context of the current kernel code, because the following range check in ia64_module_init() causes the insmod to fail:

Not sure why it worked for me, probably operator error. Revert segment_base to start of first section. Against a clean modutils 2.4.18.

Index: 18.2/obj/obj_ia64.c

obj/obj_ia64.c Wed, 31 Jul 2002 10:41:20 +1000 kaos (modutils-2.4/c/0_obj_ia64.c 1.8 644) renamed from obj/obj_ia64.c Fri, 01 Mar 2002 11:39:06 +1100 kaos (modutils-2.4/c/0_obj_ia64.c 1.5 644) +2 -6
@@ -911,12 +911,8 @@ arch_apply_relocation(struct obj_file *f
 
     case R_IA64_SEGREL32LSB :   /* @segrel(sym + add), data4 LSB */
     case R_IA64_SEGREL64LSB :   /* @segrel(sym + add), data8 LSB */
-	if (targsec->header.sh_type & SHT_NOBITS)
-	    v = ifile->bss - v;
-	else if (targsec->header.sh_flags & SHF_EXECINSTR)
-	    v = ifile->text - v;
-	else
-	    v = ifile->data - v;
+	/* Only one segment for modules, see segment_base in arch_archdata */
+	v -= f->sections[1]->header.sh_addr;
 	if (r_info = R_IA64_SEGREL32LSB)
 	    COPY_32LSB(loc, v);
 	else
#4 lore raw
In reply to Keith Owens

This one works just fine -- ship it!

Thanks,
Dave Anderson

Quoted 28 lines · Keith Owens
Quoted 3 lines · Dave Anderson

Unfortunately the patch won't work, at least in the context of the current kernel code, because the following range check in ia64_module_init() causes the insmod to fail:

Not sure why it worked for me, probably operator error. Revert segment_base to start of first section. Against a clean modutils 2.4.18.

Index: 18.2/obj/obj_ia64.c

obj/obj_ia64.c Wed, 31 Jul 2002 10:41:20 +1000 kaos (modutils-2.4/c/0_obj_ia64.c 1.8 644) renamed from obj/obj_ia64.c Fri, 01 Mar 2002 11:39:06 +1100 kaos (modutils-2.4/c/0_obj_ia64.c 1.5 644) +2 -6
@@ -911,12 +911,8 @@ arch_apply_relocation(struct obj_file *f
 
     case R_IA64_SEGREL32LSB :   /* @segrel(sym + add), data4 LSB */
     case R_IA64_SEGREL64LSB :   /* @segrel(sym + add), data8 LSB */
-       if (targsec->header.sh_type & SHT_NOBITS)
-           v = ifile->bss - v;
-       else if (targsec->header.sh_flags & SHF_EXECINSTR)
-           v = ifile->text - v;
-       else
-           v = ifile->data - v;
+       /* Only one segment for modules, see segment_base in arch_archdata */
+       v -= f->sections[1]->header.sh_addr;
        if (r_info = R_IA64_SEGREL32LSB)
            COPY_32LSB(loc, v);
        else