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
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
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
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
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
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
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
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
00400
00401
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
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
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 }