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