Home | History | Annotate | Download | only in liblegacy
      1 /**
      2  * @file daemon/liblegacy/opd_kernel.c
      3  * Dealing with the kernel and kernel module samples
      4  *
      5  * @remark Copyright 2002 OProfile authors
      6  * @remark Read the file COPYING
      7  *
      8  * @author John Levon
      9  * @author Philippe Elie
     10  */
     11 
     12 #include "opd_kernel.h"
     13 #include "opd_proc.h"
     14 #include "opd_image.h"
     15 #include "opd_mapping.h"
     16 #include "opd_printf.h"
     17 #include "opd_24_stats.h"
     18 #include "oprofiled.h"
     19 
     20 #include "op_fileio.h"
     21 #include "op_config_24.h"
     22 #include "op_libiberty.h"
     23 
     24 #include "p_module.h"
     25 #include <string.h>
     26 #include <stdlib.h>
     27 #include <errno.h>
     28 
     29 /* kernel module */
     30 struct opd_module {
     31 	char * name;
     32 	struct opd_image * image;
     33 	unsigned long start;
     34 	unsigned long end;
     35 	struct list_head module_list;
     36 };
     37 
     38 static struct opd_image * kernel_image;
     39 
     40 /* kernel and module support */
     41 static unsigned long kernel_start;
     42 static unsigned long kernel_end;
     43 static struct list_head opd_modules = { &opd_modules, &opd_modules };
     44 static unsigned int nr_modules=0;
     45 
     46 void opd_init_kernel_image(void)
     47 {
     48 	/* for no vmlinux */
     49 	if (!vmlinux)
     50 		vmlinux = "no-vmlinux";
     51 	kernel_image = opd_get_kernel_image(vmlinux, NULL, 0, 0);
     52 	kernel_image->ref_count++;
     53 }
     54 
     55 
     56 void opd_parse_kernel_range(char const * arg)
     57 {
     58 	sscanf(arg, "%lx,%lx", &kernel_start, &kernel_end);
     59 
     60 	verbprintf(vmisc, "OPD_PARSE_KERNEL_RANGE: kernel_start = %lx, kernel_end = %lx\n",
     61 		   kernel_start, kernel_end);
     62 
     63 	if (!kernel_start && !kernel_end) {
     64 		fprintf(stderr,
     65 			"Warning: mis-parsed kernel range: %lx-%lx\n",
     66 			kernel_start, kernel_end);
     67 		fprintf(stderr, "kernel profiles will be wrong.\n");
     68 	}
     69 }
     70 
     71 
     72 /**
     73  * opd_create_module - allocate and initialise a module description
     74  * @param name module name
     75  * @param start start address
     76  * @param end end address
     77  */
     78 static struct opd_module *
     79 opd_create_module(char * name, unsigned long start, unsigned long end)
     80 {
     81 	struct opd_module * module = xmalloc(sizeof(struct opd_module));
     82 
     83 	module->name = xstrdup(name);
     84 	module->image = NULL;
     85 	module->start = start;
     86 	module->end = end;
     87 	list_add(&module->module_list, &opd_modules);
     88 
     89 	return module;
     90 }
     91 
     92 
     93 /**
     94  * opd_find_module_by_name - find a module by name, ccreating a new once if
     95  * search fail
     96  * @param name module name
     97  */
     98 static struct opd_module * opd_find_module_by_name(char * name)
     99 {
    100 	struct list_head * pos;
    101 	struct opd_module * module;
    102 
    103 	list_for_each(pos, &opd_modules) {
    104 		module = list_entry(pos, struct opd_module, module_list);
    105 		if (!strcmp(name, module->name))
    106 			return module;
    107 	}
    108 
    109 	return opd_create_module(name, 0, 0);
    110 }
    111 
    112 
    113 void opd_clear_module_info(void)
    114 {
    115 	struct list_head * pos;
    116 	struct list_head * pos2;
    117 	struct opd_module * module;
    118 
    119 	verbprintf(vmodule, "Removing module list\n");
    120 	list_for_each_safe(pos, pos2, &opd_modules) {
    121 		module = list_entry(pos, struct opd_module, module_list);
    122 		free(module->name);
    123 		free(module);
    124 	}
    125 
    126 	list_init(&opd_modules);
    127 
    128 	opd_clear_kernel_mapping();
    129 }
    130 
    131 
    132 /**
    133  * opd_get_module_info - parse mapping information for kernel modules
    134  *
    135  * Parse the file /proc/ksyms to read in mapping information for
    136  * all kernel modules. The modutils package adds special symbols
    137  * to this file which allows determination of the module image
    138  * and mapping addresses of the form :
    139  *
    140  * __insmod_modulename_Oobjectfile_Mmtime_Vversion
    141  * __insmod_modulename_Ssectionname_Llength
    142  *
    143  * Currently the image file "objectfile" is stored, and details of
    144  * ".text" sections.
    145  *
    146  * There is no query_module API that allow to get directly the pathname
    147  * of a module so we need to parse all the /proc/ksyms.
    148  */
    149 static void opd_get_module_info(void)
    150 {
    151 	char * line;
    152 	char * cp, * cp2, * cp3;
    153 	FILE * fp;
    154 	struct opd_module * mod;
    155 	char * modname;
    156 	char * filename;
    157 
    158 	nr_modules=0;
    159 
    160 	fp = op_try_open_file("/proc/ksyms", "r");
    161 
    162 	if (!fp) {
    163 		printf("oprofiled: /proc/ksyms not readable, can't process module samples.\n");
    164 		return;
    165 	}
    166 
    167 	verbprintf(vmodule, "Read module info.\n");
    168 
    169 	while (1) {
    170 		line = op_get_line(fp);
    171 
    172 		if (!line)
    173 			break;
    174 
    175 		if (!strcmp("", line)) {
    176 			free(line);
    177 			continue;
    178 		}
    179 
    180 		if (strlen(line) < 9) {
    181 			printf("oprofiled: corrupt /proc/ksyms line \"%s\"\n", line);
    182 			break;
    183 		}
    184 
    185 		if (strncmp("__insmod_", line + 9, 9)) {
    186 			free(line);
    187 			continue;
    188 		}
    189 
    190 		cp = line + 18;
    191 		cp2 = cp;
    192 		while ((*cp2) && !!strncmp("_S", cp2+1, 2) && !!strncmp("_O", cp2+1, 2))
    193 			cp2++;
    194 
    195 		if (!*cp2) {
    196 			printf("oprofiled: corrupt /proc/ksyms line \"%s\"\n", line);
    197 			break;
    198 		}
    199 
    200 		cp2++;
    201 
    202 		modname = xmalloc((size_t)((cp2-cp) + 1));
    203 		strncpy(modname, cp, (size_t)((cp2-cp)));
    204 		modname[cp2-cp] = '\0';
    205 
    206 		mod = opd_find_module_by_name(modname);
    207 
    208 		free(modname);
    209 
    210 		switch (*(++cp2)) {
    211 			case 'O':
    212 				/* get filename */
    213 				cp2++;
    214 				cp3 = cp2;
    215 
    216 				while ((*cp3) && !!strncmp("_M", cp3+1, 2))
    217 					cp3++;
    218 
    219 				if (!*cp3) {
    220 					free(line);
    221 					continue;
    222 				}
    223 
    224 				cp3++;
    225 				filename = xmalloc((size_t)(cp3 - cp2 + 1));
    226 				strncpy(filename, cp2, (size_t)(cp3 - cp2));
    227 				filename[cp3-cp2] = '\0';
    228 
    229 				mod->image = opd_get_kernel_image(filename, NULL, 0, 0);
    230 				mod->image->ref_count++;
    231 				free(filename);
    232 				break;
    233 
    234 			case 'S':
    235 				/* get extent of .text section */
    236 				cp2++;
    237 				if (strncmp(".text_L", cp2, 7)) {
    238 					free(line);
    239 					continue;
    240 				}
    241 
    242 				cp2 += 7;
    243 				sscanf(line, "%lx", &mod->start);
    244 				sscanf(cp2, "%lu", &mod->end);
    245 				mod->end += mod->start;
    246 				break;
    247 		}
    248 
    249 		free(line);
    250 	}
    251 
    252 	if (line)
    253 		free(line);
    254 	op_close_file(fp);
    255 }
    256 
    257 
    258 /**
    259  * opd_drop_module_sample - drop a module sample efficiently
    260  * @param eip  eip of sample
    261  *
    262  * This function is called to recover from failing to put a samples even
    263  * after re-reading /proc/ksyms. It's either a rogue sample, or from a module
    264  * that didn't create symbols (like in some initrd setups). So we check with
    265  * query_module() if we can place it in a symbol-less module, and if so create
    266  * a negative entry for it, to quickly ignore future samples.
    267  *
    268  * Problem uncovered by Bob Montgomery <bobm (at) fc.hp.com>
    269  *
    270  */
    271 static void opd_drop_module_sample(unsigned long eip)
    272 {
    273 	char * module_names;
    274 	char * name;
    275 	size_t size = 1024;
    276 	size_t ret;
    277 	uint nr_mods;
    278 	uint mod = 0;
    279 
    280 	opd_24_stats[OPD_LOST_MODULE]++;
    281 
    282 	module_names = xmalloc(size);
    283 	while (query_module(NULL, QM_MODULES, module_names, size, &ret)) {
    284 		if (errno != ENOSPC) {
    285 			verbprintf(vmodule, "query_module failed: %s\n", strerror(errno));
    286 			return;
    287 		}
    288 		size = ret;
    289 		module_names = xrealloc(module_names, size);
    290 	}
    291 
    292 	nr_mods = ret;
    293 	name = module_names;
    294 
    295 	while (mod < nr_mods) {
    296 		struct module_info info;
    297 		if (!query_module(name, QM_INFO, &info, sizeof(info), &ret)) {
    298 			if (eip >= info.addr && eip < info.addr + info.size) {
    299 				verbprintf(vmodule, "Sample from unprofilable module %s\n", name);
    300 				opd_create_module(name, info.addr, info.addr + info.size);
    301 				break;
    302 			}
    303 		}
    304 		mod++;
    305 		name += strlen(name) + 1;
    306 	}
    307 
    308 	if (module_names)
    309 		free(module_names);
    310 }
    311 
    312 
    313 /**
    314  * opd_find_module_by_eip - find a module by its eip
    315  * @param eip  EIP value
    316  *
    317  * find in the modules container the module which
    318  * contain this eip return %NULL if not found.
    319  * caller must check than the module image is valid
    320  */
    321 static struct opd_module * opd_find_module_by_eip(unsigned long eip)
    322 {
    323 	struct list_head * pos;
    324 	struct opd_module * module;
    325 
    326 	list_for_each(pos, &opd_modules) {
    327 		module = list_entry(pos, struct opd_module, module_list);
    328 		if (module->start <= eip && module->end > eip)
    329 			return module;
    330 	}
    331 
    332 	return NULL;
    333 }
    334 
    335 
    336 /**
    337  * opd_handle_module_sample - process a module sample
    338  * @param eip  EIP value
    339  * @param counter  counter number
    340  *
    341  * Process a sample in module address space. The sample eip
    342  * is matched against module information. If the search was
    343  * successful, the sample is output to the relevant file.
    344  *
    345  * Note that for modules and the kernel, the offset will be
    346  * wrong in the file, as it is not a file offset, but the offset
    347  * from the text section. This is fixed up in pp.
    348  *
    349  * If the sample could not be located in a module, it is treated
    350  * as a kernel sample.
    351  */
    352 static void opd_handle_module_sample(unsigned long eip, u32 counter)
    353 {
    354 	struct opd_module * module;
    355 
    356 	module = opd_find_module_by_eip(eip);
    357 	if (!module) {
    358 		/* not found in known modules, re-read our info and retry */
    359 		opd_clear_module_info();
    360 		opd_get_module_info();
    361 
    362 		module = opd_find_module_by_eip(eip);
    363 	}
    364 
    365 	if (module) {
    366 		if (module->image != NULL) {
    367 			opd_24_stats[OPD_MODULE]++;
    368 			opd_put_image_sample(module->image,
    369 					     eip - module->start, counter);
    370 		} else {
    371 			opd_24_stats[OPD_LOST_MODULE]++;
    372 			verbprintf(vmodule, "No image for sampled module %s\n",
    373 				   module->name);
    374 		}
    375 	} else {
    376 		opd_drop_module_sample(eip);
    377 	}
    378 }
    379 
    380 
    381 void opd_handle_kernel_sample(unsigned long eip, u32 counter)
    382 {
    383 	if (no_vmlinux || eip < kernel_end) {
    384 		opd_24_stats[OPD_KERNEL]++;
    385 		opd_put_image_sample(kernel_image, eip - kernel_start, counter);
    386 		return;
    387 	}
    388 
    389 	/* in a module */
    390 	opd_handle_module_sample(eip, counter);
    391 }
    392 
    393 
    394 int opd_eip_is_kernel(unsigned long eip)
    395 {
    396 #ifdef __i386__
    397 #define KERNEL_OFFSET 0xC0000000
    398 	/*
    399 	 * kernel_start == 0 when using --no-vmlinux.
    400 	 * This is wrong, wrong, wrong, wrong, but we don't have much
    401 	 * choice. It obviously breaks for IA64.
    402 	 */
    403 	if (!kernel_start)
    404 		return eip >= KERNEL_OFFSET;
    405 #endif
    406 
    407 	return eip >= kernel_start;
    408 }
    409 
    410 
    411 void opd_add_kernel_map(struct opd_proc * proc, unsigned long eip)
    412 {
    413 	struct opd_module * module;
    414 	struct opd_image * image;
    415 	char const * app_name;
    416 
    417 	app_name = proc->name;
    418 	if (!app_name) {
    419 		verbprintf(vmisc, "un-named proc for tid %d\n", proc->tid);
    420 		return;
    421 	}
    422 
    423 
    424 	if (eip < kernel_end) {
    425 		image = opd_get_kernel_image(vmlinux, app_name, proc->tid, proc->tgid);
    426 		if (!image) {
    427 			verbprintf(vmisc, "Can't create image for %s %s\n", vmlinux, app_name);
    428 			return;
    429 		}
    430 
    431 		opd_add_mapping(proc, image, kernel_start, 0, kernel_end);
    432 		return;
    433 	}
    434 
    435 	module = opd_find_module_by_eip(eip);
    436 	if (!module) {
    437 		/* not found in known modules, re-read our info and retry */
    438 		opd_clear_module_info();
    439 		opd_get_module_info();
    440 
    441 		module = opd_find_module_by_eip(eip);
    442 	}
    443 
    444 	if (module) {
    445 		/* module->name is only the module name not the full path */
    446 		char const * module_name = 0;
    447 		if (module->image)
    448 			module_name = module->image->name;
    449 		if (!module_name) {
    450 			verbprintf(vmodule, "unable to get path name for module %s\n",
    451 			       module->name);
    452 			module_name = module->name;
    453 		}
    454 		image = opd_get_kernel_image(module_name, app_name, proc->tid, proc->tgid);
    455 		if (!image) {
    456 			verbprintf(vmodule, "Can't create image for %s %s\n",
    457 			       module->name, app_name);
    458 			return;
    459 		}
    460 		opd_add_mapping(proc, image, module->start, 0, module->end);
    461 	} else {
    462 		opd_drop_module_sample(eip);
    463 	}
    464 }
    465