• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
opd_create_vmlinux(char const * name,char const * arg)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 
opd_create_xen(char const * name,char const * arg)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 *
opd_create_module(char const * name,vma_t start,vma_t end)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  */
opd_clear_modules(void)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  */
opd_reread_module_info(void)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  */
find_kernel_image(struct transient const * trans)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