opd_kernel.c

Go to the documentation of this file.
00001 
00012 #include "opd_kernel.h"
00013 #include "opd_proc.h"
00014 #include "opd_image.h"
00015 #include "opd_mapping.h"
00016 #include "opd_printf.h"
00017 #include "opd_24_stats.h"
00018 #include "oprofiled.h"
00019 
00020 #include "op_fileio.h"
00021 #include "op_config_24.h"
00022 #include "op_libiberty.h"
00023 
00024 #include "p_module.h"
00025 #include <string.h>
00026 #include <stdlib.h>
00027 #include <errno.h>
00028 
00029 /* kernel module */
00030 struct opd_module {
00031     char * name;
00032     struct opd_image * image;
00033     unsigned long start;
00034     unsigned long end;
00035     struct list_head module_list;
00036 };
00037 
00038 static struct opd_image * kernel_image;
00039 
00040 /* kernel and module support */
00041 static unsigned long kernel_start;
00042 static unsigned long kernel_end;
00043 static struct list_head opd_modules = { &opd_modules, &opd_modules };
00044 static unsigned int nr_modules=0;
00045 
00046 void opd_init_kernel_image(void)
00047 {
00048     /* for no vmlinux */
00049     if (!vmlinux)
00050         vmlinux = "no-vmlinux";
00051     kernel_image = opd_get_kernel_image(vmlinux, NULL, 0, 0);
00052     kernel_image->ref_count++;
00053 }
00054 
00055 
00056 void opd_parse_kernel_range(char const * arg)
00057 {
00058     sscanf(arg, "%lx,%lx", &kernel_start, &kernel_end);
00059 
00060     verbprintf(vmisc, "OPD_PARSE_KERNEL_RANGE: kernel_start = %lx, kernel_end = %lx\n",
00061            kernel_start, kernel_end);
00062 
00063     if (!kernel_start && !kernel_end) {
00064         fprintf(stderr,
00065             "Warning: mis-parsed kernel range: %lx-%lx\n",
00066             kernel_start, kernel_end);
00067         fprintf(stderr, "kernel profiles will be wrong.\n");
00068     }
00069 }
00070 
00071 
00078 static struct opd_module *
00079 opd_create_module(char * name, unsigned long start, unsigned long end)
00080 {
00081     struct opd_module * module = xmalloc(sizeof(struct opd_module));
00082 
00083     module->name = xstrdup(name);
00084     module->image = NULL;
00085     module->start = start;
00086     module->end = end;
00087     list_add(&module->module_list, &opd_modules);
00088 
00089     return module;
00090 }
00091 
00092 
00098 static struct opd_module * opd_find_module_by_name(char * name)
00099 {
00100     struct list_head * pos;
00101     struct opd_module * module;
00102 
00103     list_for_each(pos, &opd_modules) {
00104         module = list_entry(pos, struct opd_module, module_list);
00105         if (!strcmp(name, module->name))
00106             return module;
00107     }
00108 
00109     return opd_create_module(name, 0, 0);
00110 }
00111 
00112 
00113 void opd_clear_module_info(void)
00114 {
00115     struct list_head * pos;
00116     struct list_head * pos2;
00117     struct opd_module * module;
00118 
00119     verbprintf(vmodule, "Removing module list\n");
00120     list_for_each_safe(pos, pos2, &opd_modules) {
00121         module = list_entry(pos, struct opd_module, module_list);
00122         free(module->name);
00123         free(module);
00124     }
00125 
00126     list_init(&opd_modules);
00127 
00128     opd_clear_kernel_mapping();
00129 }
00130 
00131 
00149 static void opd_get_module_info(void)
00150 {
00151     char * line;
00152     char * cp, * cp2, * cp3;
00153     FILE * fp;
00154     struct opd_module * mod;
00155     char * modname;
00156     char * filename;
00157 
00158     nr_modules=0;
00159 
00160     fp = op_try_open_file("/proc/ksyms", "r");
00161 
00162     if (!fp) {
00163         printf("oprofiled: /proc/ksyms not readable, can't process module samples.\n");
00164         return;
00165     }
00166 
00167     verbprintf(vmodule, "Read module info.\n");
00168 
00169     while (1) {
00170         line = op_get_line(fp);
00171 
00172         if (!line)
00173             break;
00174 
00175         if (!strcmp("", line)) {
00176             free(line);
00177             continue;
00178         }
00179 
00180         if (strlen(line) < 9) {
00181             printf("oprofiled: corrupt /proc/ksyms line \"%s\"\n", line);
00182             break;
00183         }
00184 
00185         if (strncmp("__insmod_", line + 9, 9)) {
00186             free(line);
00187             continue;
00188         }
00189 
00190         cp = line + 18;
00191         cp2 = cp;
00192         while ((*cp2) && !!strncmp("_S", cp2+1, 2) && !!strncmp("_O", cp2+1, 2))
00193             cp2++;
00194 
00195         if (!*cp2) {
00196             printf("oprofiled: corrupt /proc/ksyms line \"%s\"\n", line);
00197             break;
00198         }
00199 
00200         cp2++;
00201 
00202         modname = xmalloc((size_t)((cp2-cp) + 1));
00203         strncpy(modname, cp, (size_t)((cp2-cp)));
00204         modname[cp2-cp] = '\0';
00205 
00206         mod = opd_find_module_by_name(modname);
00207 
00208         free(modname);
00209 
00210         switch (*(++cp2)) {
00211             case 'O':
00212                 /* get filename */
00213                 cp2++;
00214                 cp3 = cp2;
00215 
00216                 while ((*cp3) && !!strncmp("_M", cp3+1, 2))
00217                     cp3++;
00218 
00219                 if (!*cp3) {
00220                     free(line);
00221                     continue;
00222                 }
00223 
00224                 cp3++;
00225                 filename = xmalloc((size_t)(cp3 - cp2 + 1));
00226                 strncpy(filename, cp2, (size_t)(cp3 - cp2));
00227                 filename[cp3-cp2] = '\0';
00228 
00229                 mod->image = opd_get_kernel_image(filename, NULL, 0, 0);
00230                 mod->image->ref_count++;
00231                 free(filename);
00232                 break;
00233 
00234             case 'S':
00235                 /* get extent of .text section */
00236                 cp2++;
00237                 if (strncmp(".text_L", cp2, 7)) {
00238                     free(line);
00239                     continue;
00240                 }
00241 
00242                 cp2 += 7;
00243                 sscanf(line, "%lx", &mod->start);
00244                 sscanf(cp2, "%lu", &mod->end);
00245                 mod->end += mod->start;
00246                 break;
00247         }
00248 
00249         free(line);
00250     }
00251 
00252     if (line)
00253         free(line);
00254     op_close_file(fp);
00255 }
00256  
00257 
00271 static void opd_drop_module_sample(unsigned long eip)
00272 {
00273     char * module_names;
00274     char * name;
00275     size_t size = 1024;
00276     size_t ret;
00277     uint nr_mods;
00278     uint mod = 0;
00279 
00280     opd_24_stats[OPD_LOST_MODULE]++;
00281 
00282     module_names = xmalloc(size);
00283     while (query_module(NULL, QM_MODULES, module_names, size, &ret)) {
00284         if (errno != ENOSPC) {
00285             verbprintf(vmodule, "query_module failed: %s\n", strerror(errno));
00286             return;
00287         }
00288         size = ret;
00289         module_names = xrealloc(module_names, size);
00290     }
00291 
00292     nr_mods = ret;
00293     name = module_names;
00294 
00295     while (mod < nr_mods) {
00296         struct module_info info;
00297         if (!query_module(name, QM_INFO, &info, sizeof(info), &ret)) {
00298             if (eip >= info.addr && eip < info.addr + info.size) {
00299                 verbprintf(vmodule, "Sample from unprofilable module %s\n", name);
00300                 opd_create_module(name, info.addr, info.addr + info.size);
00301                 break;
00302             }
00303         }
00304         mod++;
00305         name += strlen(name) + 1;
00306     }
00307 
00308     if (module_names)
00309         free(module_names);
00310 }
00311 
00312 
00321 static struct opd_module * opd_find_module_by_eip(unsigned long eip)
00322 {
00323     struct list_head * pos;
00324     struct opd_module * module;
00325 
00326     list_for_each(pos, &opd_modules) {
00327         module = list_entry(pos, struct opd_module, module_list);
00328         if (module->start <= eip && module->end > eip)
00329             return module;
00330     }
00331 
00332     return NULL;
00333 }
00334 
00335 
00352 static void opd_handle_module_sample(unsigned long eip, u32 counter)
00353 {
00354     struct opd_module * module;
00355 
00356     module = opd_find_module_by_eip(eip);
00357     if (!module) {
00358         /* not found in known modules, re-read our info and retry */
00359         opd_clear_module_info();
00360         opd_get_module_info();
00361 
00362         module = opd_find_module_by_eip(eip);
00363     }
00364 
00365     if (module) {
00366         if (module->image != NULL) {
00367             opd_24_stats[OPD_MODULE]++;
00368             opd_put_image_sample(module->image,
00369                          eip - module->start, counter);
00370         } else {
00371             opd_24_stats[OPD_LOST_MODULE]++;
00372             verbprintf(vmodule, "No image for sampled module %s\n",
00373                    module->name);
00374         }
00375     } else {
00376         opd_drop_module_sample(eip);
00377     }
00378 }
00379 
00380 
00381 void opd_handle_kernel_sample(unsigned long eip, u32 counter)
00382 {
00383     if (no_vmlinux || eip < kernel_end) {
00384         opd_24_stats[OPD_KERNEL]++;
00385         opd_put_image_sample(kernel_image, eip - kernel_start, counter);
00386         return;
00387     }
00388 
00389     /* in a module */
00390     opd_handle_module_sample(eip, counter);
00391 }
00392  
00393 
00394 int opd_eip_is_kernel(unsigned long eip)
00395 {
00396 #ifdef __i386
00397 #define KERNEL_OFFSET 0xC0000000
00398     /*
00399      * kernel_start == 0 when using --no-vmlinux.
00400      * This is wrong, wrong, wrong, wrong, but we don't have much
00401      * choice. It obviously breaks for IA64.
00402      */
00403     if (!kernel_start)
00404         return eip >= KERNEL_OFFSET;
00405 #endif
00406 
00407     return eip >= kernel_start;
00408 }
00409 
00410 
00411 void opd_add_kernel_map(struct opd_proc * proc, unsigned long eip)
00412 {
00413     struct opd_module * module;
00414     struct opd_image * image;
00415     char const * app_name;
00416 
00417     app_name = proc->name;
00418     if (!app_name) {
00419         verbprintf(vmisc, "un-named proc for tid %d\n", proc->tid);
00420         return;
00421     }
00422 
00423 
00424     if (eip < kernel_end) {
00425         image = opd_get_kernel_image(vmlinux, app_name, proc->tid, proc->tgid);
00426         if (!image) {
00427             verbprintf(vmisc, "Can't create image for %s %s\n", vmlinux, app_name);
00428             return;
00429         }
00430 
00431         opd_add_mapping(proc, image, kernel_start, 0, kernel_end);
00432         return;
00433     }
00434 
00435     module = opd_find_module_by_eip(eip);
00436     if (!module) {
00437         /* not found in known modules, re-read our info and retry */
00438         opd_clear_module_info();
00439         opd_get_module_info();
00440 
00441         module = opd_find_module_by_eip(eip);
00442     }
00443 
00444     if (module) {
00445         /* module->name is only the module name not the full path */
00446         char const * module_name = 0;
00447         if (module->image)
00448             module_name = module->image->name;
00449         if (!module_name) {
00450             verbprintf(vmodule, "unable to get path name for module %s\n",
00451                    module->name);
00452             module_name = module->name;
00453         }
00454         image = opd_get_kernel_image(module_name, app_name, proc->tid, proc->tgid);
00455         if (!image) {
00456             verbprintf(vmodule, "Can't create image for %s %s\n",
00457                    module->name, app_name);
00458             return;
00459         }
00460         opd_add_mapping(proc, image, module->start, 0, module->end);
00461     } else {
00462         opd_drop_module_sample(eip);
00463     }
00464 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1