opd_kernel.c revision cc2ee177dbb3befca43e36cfc56778b006c3d050
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 */
30struct 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
38static struct opd_image * kernel_image;
39
40/* kernel and module support */
41static unsigned long kernel_start;
42static unsigned long kernel_end;
43static struct list_head opd_modules = { &opd_modules, &opd_modules };
44static unsigned int nr_modules=0;
45
46void 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
56void 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 */
78static struct opd_module *
79opd_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 */
98static 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
113void 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 */
149static 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@fc.hp.com>
269 *
270 */
271static 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 */
321static 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 */
352static 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
381void 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
394int 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
411void 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