Home | History | Annotate | Download | only in daemon
      1 /**
      2  * @file daemon/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  * Modified by Aravind Menon for Xen
     11  * These modifications are:
     12  * Copyright (C) 2005 Hewlett-Packard Co.
     13  */
     14 
     15 #include "opd_kernel.h"
     16 #include "opd_sfile.h"
     17 #include "opd_trans.h"
     18 #include "opd_printf.h"
     19 #include "opd_stats.h"
     20 #include "oprofiled.h"
     21 
     22 #include "op_fileio.h"
     23 #include "op_config.h"
     24 #include "op_libiberty.h"
     25 
     26 #include <string.h>
     27 #include <stdlib.h>
     28 #include <errno.h>
     29 #include <assert.h>
     30 
     31 static LIST_HEAD(modules);
     32 
     33 static struct kernel_image vmlinux_image;
     34 
     35 static struct kernel_image xen_image;
     36 
     37 void opd_create_vmlinux(char const * name, char const * arg)
     38 {
     39 	/* vmlinux is *not* on the list of modules */
     40 	list_init(&vmlinux_image.list);
     41 
     42 	/* for no vmlinux */
     43 	if (no_vmlinux) {
     44 		vmlinux_image.name = "no-vmlinux";
     45 		return;
     46 	}
     47 
     48 	vmlinux_image.name = xstrdup(name);
     49 
     50 	sscanf(arg, "%llx,%llx", &vmlinux_image.start, &vmlinux_image.end);
     51 
     52 	verbprintf(vmisc, "kernel_start = %llx, kernel_end = %llx\n",
     53 	           vmlinux_image.start, vmlinux_image.end);
     54 
     55 	if (!vmlinux_image.start && !vmlinux_image.end) {
     56 		fprintf(stderr, "error: mis-parsed kernel range: %llx-%llx\n",
     57 		        vmlinux_image.start, vmlinux_image.end);
     58 		exit(EXIT_FAILURE);
     59 	}
     60 }
     61 
     62 void opd_create_xen(char const * name, char const * arg)
     63 {
     64 	/* xen is *not* on the list of modules */
     65 	list_init(&xen_image.list);
     66 
     67 	/* for no xen */
     68 	if (no_xen) {
     69 		xen_image.name = "no-xen";
     70 		return;
     71 	}
     72 
     73 	xen_image.name = xstrdup(name);
     74 
     75 	sscanf(arg, "%llx,%llx", &xen_image.start, &xen_image.end);
     76 
     77 	verbprintf(vmisc, "xen_start = %llx, xen_end = %llx\n",
     78 	           xen_image.start, xen_image.end);
     79 
     80 	if (!xen_image.start && !xen_image.end) {
     81 		fprintf(stderr, "error: mis-parsed xen range: %llx-%llx\n",
     82 		        xen_image.start, xen_image.end);
     83 		exit(EXIT_FAILURE);
     84 	}
     85 }
     86 
     87 
     88 /**
     89  * Allocate and initialise a kernel image description
     90  * @param name image name
     91  * @param start start address
     92  * @param end end address
     93  */
     94 static struct kernel_image *
     95 opd_create_module(char const * name, vma_t start, vma_t end)
     96 {
     97 	struct kernel_image * image = xmalloc(sizeof(struct kernel_image));
     98 
     99 	image->name = xstrdup(name);
    100 	image->start = start;
    101 	image->end = end;
    102 	list_add(&image->list, &modules);
    103 
    104 	return image;
    105 }
    106 
    107 
    108 /**
    109  * Clear and free all kernel image information and reset
    110  * values.
    111  */
    112 static void opd_clear_modules(void)
    113 {
    114 	struct list_head * pos;
    115 	struct list_head * pos2;
    116 	struct kernel_image * image;
    117 
    118 	list_for_each_safe(pos, pos2, &modules) {
    119 		image = list_entry(pos, struct kernel_image, list);
    120 		if (image->name)
    121 			free(image->name);
    122 		free(image);
    123 	}
    124 
    125 	list_init(&modules);
    126 
    127 	/* clear out lingering references */
    128 	sfile_clear_kernel();
    129 }
    130 
    131 
    132 /*
    133  * each line is in the format:
    134  *
    135  * module_name 16480 1 dependencies Live 0xe091e000
    136  *
    137  * without any blank space in each field
    138  */
    139 void opd_reread_module_info(void)
    140 {
    141 	FILE * fp;
    142 	char * line;
    143 	struct kernel_image * image;
    144 	int module_size;
    145 	char ref_count[32+1];
    146 	int ret;
    147 	char module_name[256+1];
    148 	char live_info[32+1];
    149 	char dependencies[4096+1];
    150 	unsigned long long start_address;
    151 
    152 	if (no_vmlinux)
    153 		return;
    154 
    155 	opd_clear_modules();
    156 
    157 	printf("Reading module info.\n");
    158 
    159 	fp = op_try_open_file("/proc/modules", "r");
    160 
    161 	if (!fp) {
    162 		printf("oprofiled: /proc/modules not readable, "
    163 			"can't process module samples.\n");
    164 		return;
    165 	}
    166 
    167 	while (1) {
    168 		line = op_get_line(fp);
    169 
    170 		if (!line)
    171 			break;
    172 
    173 		if (line[0] == '\0') {
    174 			free(line);
    175 			continue;
    176 		}
    177 
    178 		ret = sscanf(line, "%256s %u %32s %4096s %32s %llx",
    179 			     module_name, &module_size, ref_count,
    180 			     dependencies, live_info, &start_address);
    181 		if (ret != 6) {
    182 			printf("bad /proc/modules entry: %s\n", line);
    183 			free(line);
    184 			continue;
    185 		}
    186 
    187 		image = opd_create_module(module_name, start_address,
    188 		                          start_address + module_size);
    189 
    190 		verbprintf(vmodule, "module %s start %llx end %llx\n",
    191 			   image->name, image->start, image->end);
    192 
    193 		free(line);
    194 	}
    195 
    196 	op_close_file(fp);
    197 }
    198 
    199 
    200 /**
    201  * find a kernel image by PC value
    202  * @param trans holds PC value to look up
    203  *
    204  * find the kernel image which contains this PC.
    205  *
    206  * Return %NULL if not found.
    207  */
    208 struct kernel_image * find_kernel_image(struct transient const * trans)
    209 {
    210 	struct list_head * pos;
    211 	struct kernel_image * image = &vmlinux_image;
    212 
    213 	if (no_vmlinux)
    214 		return image;
    215 
    216 	if (image->start <= trans->pc && image->end > trans->pc)
    217 		return image;
    218 
    219 	list_for_each(pos, &modules) {
    220 		image = list_entry(pos, struct kernel_image, list);
    221 		if (image->start <= trans->pc && image->end > trans->pc)
    222 			return image;
    223 	}
    224 
    225 	if (xen_image.start <= trans->pc && xen_image.end > trans->pc)
    226 		return &xen_image;
    227 
    228 	return NULL;
    229 }
    230