Home | History | Annotate | Download | only in liblegacy
      1 /**
      2  * @file opd_image.c
      3  * Management of binary images
      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_image.h"
     13 #include "opd_printf.h"
     14 #include "opd_sample_files.h"
     15 #include "opd_24_stats.h"
     16 #include "oprofiled.h"
     17 
     18 #include "op_file.h"
     19 #include "op_config_24.h"
     20 #include "op_libiberty.h"
     21 #include "op_string.h"
     22 
     23 #include <string.h>
     24 #include <stdlib.h>
     25 #include <stdio.h>
     26 
     27 /* maintained for statistics purpose only */
     28 static int nr_images;
     29 
     30 /* list of images */
     31 #define OPD_IMAGE_HASH_SIZE 2048
     32 static struct list_head opd_images[OPD_IMAGE_HASH_SIZE];
     33 
     34 
     35 void opd_init_images(void)
     36 {
     37 	int i;
     38 	for (i = 0; i < OPD_IMAGE_HASH_SIZE; ++i)
     39 		list_init(&opd_images[i]);
     40 }
     41 
     42 
     43 int opd_get_nr_images(void)
     44 {
     45 	return nr_images;
     46 }
     47 
     48 
     49 void opd_delete_image(struct opd_image * image)
     50 {
     51 	verbprintf(vmisc, "Deleting image: name %s app_name %s, kernel %d, "
     52 	           "tid %d, tgid %d ref count %u\n",
     53 	           image->name, image->app_name, image->kernel,
     54 	           image->tid, image->tgid, (int)image->ref_count);
     55 
     56 	if (image->ref_count <= 0) {
     57 		printf("image->ref_count < 0 for image: name %s app_name %s, "
     58 		       "kernel %d, tid %d, tgid %d ref count %u\n",
     59 		       image->name, image->app_name, image->kernel,
     60 		       image->tid, image->tgid, image->ref_count);
     61 		abort();
     62 	}
     63 
     64 	if (--image->ref_count != 0)
     65 		return;
     66 
     67 	if (image->name)
     68 		free(image->name);
     69 	if (image->app_name)
     70 		free(image->app_name);
     71 	list_del(&image->hash_next);
     72 	opd_close_image_samples_files(image);
     73 	free(image);
     74 
     75 	nr_images--;
     76 }
     77 
     78 
     79 void opd_for_each_image(opd_image_cb image_cb)
     80 {
     81 	struct list_head * pos;
     82 	struct list_head * pos2;
     83 	int i;
     84 
     85 	for (i = 0; i < OPD_IMAGE_HASH_SIZE; ++i) {
     86 		list_for_each_safe(pos, pos2, &opd_images[i]) {
     87 			struct opd_image * image =
     88 				list_entry(pos, struct opd_image, hash_next);
     89 			image_cb(image);
     90 		}
     91 	}
     92 }
     93 
     94 
     95 /**
     96  * opd_hash_image - hash an image
     97  * @param hash  hash of image name
     98  * @param tid  thread id
     99  * @param tgid  thread group id
    100  *
    101  * return the hash code for the passed parameters
    102  */
    103 static size_t opd_hash_image(char const * name, pid_t tid, pid_t tgid)
    104 {
    105 	size_t hash = op_hash_string(name);
    106 	if (separate_thread)
    107 		hash += tid + tgid;
    108 	return  hash % OPD_IMAGE_HASH_SIZE;
    109 }
    110 
    111 
    112 /**
    113  * opd_new_image - create an image sample file
    114  * @param app_name  the application name where belongs this image
    115  * @param name  name of the image to add
    116  * @param kernel  is the image a kernel/module image
    117  * @param tid  thread id
    118  * @param tgid  thread group id
    119  *
    120  * image at funtion entry is uninitialised
    121  * name is copied i.e. should be GC'd separately from the
    122  * image structure if appropriate.
    123  *
    124  * Initialise an opd_image struct for the image image
    125  * without opening the associated samples files. At return
    126  * the image is fully initialized.
    127  */
    128 static struct opd_image *
    129 opd_new_image(char const * name, char const * app_name, int kernel,
    130               pid_t tid, pid_t tgid)
    131 {
    132 	size_t hash_image;
    133 	struct opd_image * image;
    134 
    135 	verbprintf(vmisc, "Creating image: %s %s, kernel %d, tid %d, "
    136 	           "tgid %d\n", name, app_name, kernel, tid, tgid);
    137 
    138 	image = xmalloc(sizeof(struct opd_image));
    139 
    140 	list_init(&image->hash_next);
    141 	image->name = xstrdup(name);
    142 	image->kernel = kernel;
    143 	image->tid = tid;
    144 	image->tgid = tgid;
    145 	image->ref_count = 0;
    146 	image->app_name = app_name ? xstrdup(app_name) : NULL;
    147 	image->mtime = op_get_mtime(image->name);
    148 
    149 	image->ignored = 1;
    150 	if (separate_lib && app_name)
    151 		image->ignored = is_image_ignored(app_name);
    152 	if (image->ignored)
    153 		image->ignored = is_image_ignored(name);
    154 
    155 	memset(image->sfiles, '\0', NR_CPUS * sizeof(struct opd_24_sfile **));
    156 
    157 	hash_image = opd_hash_image(name, tid, tgid);
    158 	list_add(&image->hash_next, &opd_images[hash_image]);
    159 
    160 	nr_images++;
    161 
    162 	return image;
    163 }
    164 
    165 
    166 /**
    167  * is_same_image - check for identical image
    168  * @param image  image to compare
    169  * @param name  name of image
    170  * @param app_name image must belong to this application name
    171  * @param tid  thread id
    172  * @param tgid  thread group id
    173  *
    174  * on entry caller have checked than strcmp(image->name, name) == 0
    175  * return 0 if the couple (name, app_name) refers to same image
    176  */
    177 static int is_same_image(struct opd_image const * image, char const * app_name,
    178                          pid_t tid, pid_t tgid)
    179 {
    180 	/* correctness is really important here, if we fail to recognize
    181 	 * identical image we will open/mmap multiple time the same samples
    182 	 * files which is not supported by the kernel, strange assertion
    183 	 * failure in libfd is a typical symptom of that */
    184 
    185 	if (separate_thread) {
    186 		if (image->tid != tid || image->tgid != tgid)
    187 			return 1;
    188 	}
    189 
    190 	/* if !separate_lib, the comparison made by caller is enough */
    191 	if (!separate_lib)
    192 		return 0;
    193 
    194 	if (image->app_name == NULL && app_name == NULL)
    195 		return 0;
    196 
    197 	if (image->app_name != NULL && app_name != NULL &&
    198 	    !strcmp(image->app_name, app_name))
    199 		return 0;
    200 
    201 	/* /proc parsed image come with a non null app_name but notification
    202 	 * for application itself come with a null app_name, in this case
    203 	 * the test above fail so check for this case. */
    204 	if (image->app_name && !app_name && !strcmp(image->app_name, image->name))
    205 		return 0;
    206 
    207 	return 1;
    208 }
    209 
    210 
    211 /**
    212  * opd_find_image - find an image
    213  * @param name  name of image to find
    214  * @param hash  hash of image to find
    215  * @param app_name  the application name where belongs this image
    216  * @param tid  thread id
    217  * @param tgid  thread group id
    218  *
    219  * Returns the image pointer for the file specified by name, or %NULL.
    220  */
    221 static struct opd_image * opd_find_image(char const * name,
    222                                 char const * app_name, pid_t tid, pid_t tgid)
    223 {
    224 	/* suppress uninitialized use warning */
    225 	struct opd_image * image = 0;
    226 	struct list_head * pos;
    227 	size_t bucket;
    228 
    229 	opd_24_stats[OPD_IMAGE_HASH_ACCESS]++;
    230 	bucket = opd_hash_image(name, tid, tgid);
    231 	list_for_each(pos, &opd_images[bucket]) {
    232 		opd_24_stats[OPD_IMAGE_HASH_DEPTH]++;
    233 		image = list_entry(pos, struct opd_image, hash_next);
    234 
    235 		if (!strcmp(image->name, name)) {
    236 			if (!is_same_image(image, app_name, tid, tgid))
    237 				break;
    238 		}
    239 	}
    240 
    241 	if (pos == &opd_images[bucket])
    242 		return NULL;
    243 
    244 	/* The app_name field is always valid */
    245 	return image;
    246 }
    247 
    248 
    249 struct opd_image * opd_get_image(char const * name, char const * app_name,
    250                                  int kernel, pid_t tid, pid_t tgid)
    251 {
    252 	struct opd_image * image;
    253 	if ((image = opd_find_image(name, app_name, tid, tgid)) == NULL)
    254 		image = opd_new_image(name, app_name, kernel, tid, tgid);
    255 
    256 	return image;
    257 }
    258 
    259 
    260 struct opd_image * opd_get_kernel_image(char const * name,
    261                                char const * app_name, pid_t tid, pid_t tgid)
    262 {
    263 	return opd_get_image(name, app_name, 1, tid, tgid);
    264 }
    265