Modultils工具源码分析之ksyms篇

一般来说,内核只会导出由EXPORT_PARM宏指定的符号给模块使用。为了使debugger提供更好的调试功能,需要使用kallsyms工具为内核生成__kallsyms段数据,该段描述所有不处在堆栈上的内核符号。这样debugger就能更好地解析内核符号,而不仅仅是内核指定导出的符号。

刚刚编译好的内核是不带__kallsyms段的。要在内核中加入__kallsyms段,man给出了一个方法,这个方法实际上也是insmod程序里使用的方法。

insmod里,我们已经看到,在内存中生成所有其他段之后,insmod调用obj_kallsyms生成__kallsyms段,这时这个段里的符号,还没经过重定位。但是,大小已经确定,可以使obj_load_size的计算正确。然后在obj_relocate进行重定位后,重新调用obj_kallsyms,生成内容正确的__kallsyms段。

在内核里引入__kallsyms段,也是类似的方法,以下就是man里的提示。

1)            对编译好的内核,运行kallsyms程序,保存输出文件(kallsyms只输出到stdout,见下面的源码,因此要重定向输出到指定文件)。

2)            将输出文件和内核链接,对生成文件运行kallsyms,保存输出文件。

3)            重复第2步。

4)            链接内核与第3步的输出文件,即完成。

这里比insmod里的调用多了一次。是因为第2步链接产生的文件,由于添加了__kallsyms段(insmod在调用前就添加了这个段,见add_kallsyms函数,所以,运行obj_kallsyms直接产生了第2步的效果),所以文件大小、段的数目、符号的位置都变了,运行kallsyms生成的输出文件里的内容可能还不是正确的。但是__kallsyms的大小已经固定了。在运行一次,就对了。

来看代码。作为insmod工具组的一员,它的开始和其他工具类似。首先是./modutils-2.4.0/insmod/insmod.c

 

1970       #ifdef COMBINE_kallsyms

1971                     { "kallsyms", &kallsyms_main },

1972       #endif

 

接着,在./modutils-2.4.0/insmod/kallsyms.c里。

 

62    #if defined(COMMON_3264) && defined(ONLY_32)

63           #define KALLSYMS_MAIN kallsyms_main_32  /* 32 bit version */

64    #elif defined(COMMON_3264) && defined(ONLY_64)

65           #define KALLSYMS_MAIN kallsyms_main_64  /* 64 bit version */

66    #else

67           #define KALLSYMS_MAIN kallsyms_main       /* Not common code */

68       #endif

 

KALLSYMS_MAIN在同一文件里。

kallsyms——KALLSYMS_MAIN函数

70    int KALLSYMS_MAIN (int argc, char **argv)

71    {

72        struct option long_opts[] = {

73               {"version", 0, 0, 'V'},

74               {"help", 0, 0, 'h'},

75               {0, 0, 0, 0}

76        };

77        char *filename = NULL;

78        int fp;

79        struct obj_file *fin, *fout;

80        int i, c;

81

82        error_file = "kallsyms";

83   

84        /* To handle repeated calls from combined modprobe */

85        errors = optind = 0;

86

87        /* Process the command line.  */

88        while ((c = getopt_long(argc, argv, "Vh",

89                             &long_opts[0], NULL)) != EOF)

90           switch (c) {

91           case 'V':

92               fputs("kallsyms version " MODUTILS_VERSION "/n", stderr);

93               return(0);

94           case 'h':       /* Print the usage message. */

95               kallsyms_usage();

96               return(0);

97           default:

98               kallsyms_usage();

99               return(1);

100         }

101

102      if (optind != argc-1) {

103                kallsyms_usage();

104                return(1);

105      }

106

107      filename = argv[optind++];

108      error_file = filename;

109      if ((fp = gzf_open(filename, O_RDONLY)) < 0) {

110                error("%s: %m", filename);

111                return 1;

112      }

113

114      if ((fin = obj_load(fp, ET_EXEC, filename)) == NULL) {

115                gzf_close(fp);

116                return 1;

117      }

118      gzf_close(fp);

119

120      error_file = "kallsyms";

121      if (obj_kallsyms(fin, &fout))

122                return 1;

123

124      /* Write the extracted data */

125      fwrite(&fout->header, sizeof(fout->header), 1, stdout);

126      for (i = 0; i < fout->header.e_shnum; ++i)

127                fwrite(&fout->sections[i]->header, fout->header.e_shentsize, 1, stdout);

128      for (i = 0; i < fout->header.e_shnum; ++i) {

129                if (fout->sections[i]->header.sh_size) {

130                    fseek(stdout, fout->sections[i]->header.sh_offset, SEEK_SET);

131                    fwrite(fout->sections[i]->contents,

132                           fout->sections[i]->header.sh_size, 1, stdout);

133                }

134      }

135

136      return 0;

137    }

 

有了前面分析工具的基础,这里没有什么可多说的。注意109行,这个工具不象insmod这么强悍,它需要提供路径名,而不能只是模块名。

另外,在121行的obj_kallsyms里调用arch_new_section,通过mallocfout分配资源。这里fout是局部变量,但在上面的代码中并没有对应的free调用。在insmod中的add_kallsyms在调用了obj_kallsyms之后,则为生成的obj_file对象调用了obj_free进行内存释放。所以,这里可能存在内存泄漏。

还有注意,kallsyms固定输出到stdout,因此,如果要保存输出文件,需要重定向输出。

你可能感兴趣的:(struct,File,command,null,工具,FP)