Home | History | Annotate | Download | only in liblegacy
      1 /**
      2  * @file opd_mapping.c
      3  * Management of process mappings
      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_mapping.h"
     13 #include "opd_proc.h"
     14 #include "opd_image.h"
     15 #include "opd_printf.h"
     16 
     17 #include "op_interface.h"
     18 #include "op_config_24.h"
     19 #include "op_libiberty.h"
     20 
     21 #include <sys/mman.h>
     22 #include <limits.h>
     23 #include <stdlib.h>
     24 #include <stdio.h>
     25 #include <string.h>
     26 
     27 /* hash map device mmap */
     28 static struct op_hash_index * hashmap;
     29 /* already seen mapping name */
     30 static char const * hash_name[OP_HASH_MAP_NR];
     31 
     32 
     33 void opd_cleanup_hash_name(void)
     34 {
     35 	int i;
     36 	for (i = 0; i < OP_HASH_MAP_NR; ++i)
     37 		free((char *)hash_name[i]);
     38 
     39 }
     40 
     41 
     42 void opd_init_hash_map(void)
     43 {
     44 	extern fd_t hashmapdevfd;
     45 
     46 	hashmap = mmap(0, OP_HASH_MAP_SIZE, PROT_READ, MAP_SHARED, hashmapdevfd, 0);
     47 	if ((long)hashmap == -1) {
     48 		perror("oprofiled: couldn't mmap hash map");
     49 		exit(EXIT_FAILURE);
     50 	}
     51 
     52 }
     53 
     54 
     55 void opd_kill_maps(struct opd_proc * proc)
     56 {
     57 	struct list_head * pos, * pos2;
     58 
     59 	list_for_each_safe(pos, pos2, &proc->maps) {
     60 		struct opd_map * map = list_entry(pos, struct opd_map, next);
     61 		list_del(pos);
     62 		opd_delete_image(map->image);
     63 		free(map);
     64 	}
     65 }
     66 
     67 
     68 void opd_add_mapping(struct opd_proc * proc, struct opd_image * image,
     69 		unsigned long start, unsigned long offset, unsigned long end)
     70 {
     71 	struct opd_map * map;
     72 
     73 	verbprintf(vmisc, "Adding mapping for process %d: 0x%.8lx-0x%.8lx, off 0x%.8lx, \"%s\"\n",
     74 		proc->tid, start, end, offset, image->name);
     75 
     76 	map = malloc(sizeof(struct opd_map));
     77 
     78 	/* first map is the primary image */
     79 	if (list_empty(&proc->maps)) {
     80 		if (proc->name)
     81 			free((char *)proc->name);
     82 		proc->name = xstrdup(image->name);
     83 	}
     84 
     85 	image->ref_count++;
     86 
     87 	map->image = image;
     88 	map->start = start;
     89 	map->offset = offset;
     90 	map->end = end;
     91 	list_add_tail(&map->next, &proc->maps);
     92 }
     93 
     94 
     95 /**
     96  * get_from_pool - retrieve string from hash map pool
     97  * @param ind index into pool
     98  */
     99 inline static char * get_from_pool(uint ind)
    100 {
    101 	return ((char *)(hashmap + OP_HASH_MAP_NR) + ind);
    102 }
    103 
    104 
    105 /**
    106  * opg_get_hash_name - find a mapping name from a hash
    107  * @param hash hash value for this name
    108  */
    109 static char const * opd_get_hash_name(int hash)
    110 {
    111 	char file[PATH_MAX];
    112 	char * c = &file[PATH_MAX-1];
    113 	int orighash = hash;
    114 
    115 	if (hash_name[hash])
    116 		return hash_name[hash];
    117 
    118 	*c = '\0';
    119 	while (hash) {
    120 		char * name = get_from_pool(hashmap[hash].name);
    121 
    122 		if (strlen(name) + 1 + strlen(c) >= PATH_MAX) {
    123 			fprintf(stderr, "String \"%s\" too large.\n", c);
    124 			exit(EXIT_FAILURE);
    125 		}
    126 
    127 		c -= strlen(name) + 1;
    128 		*c = '/';
    129 		strncpy(c + 1, name, strlen(name));
    130 
    131 		/* move onto parent */
    132 		hash = hashmap[hash].parent;
    133 	}
    134 
    135 	return hash_name[orighash] = xstrdup(c);
    136 }
    137 
    138 
    139 void opd_handle_mapping(struct op_note const * note)
    140 {
    141 	struct opd_proc * proc;
    142 	struct opd_image * image;
    143 	int hash;
    144 	char const * name;
    145 
    146 	proc = opd_get_proc(note->pid, note->tgid);
    147 
    148 	if (!proc) {
    149 		verbprintf(vmisc, "Told about mapping for non-existent process %u.\n", note->pid);
    150 		proc = opd_new_proc(note->pid, note->tgid);
    151 	}
    152 
    153 	hash = note->hash;
    154 
    155 	if (hash == -1) {
    156 		/* possibly deleted file */
    157 		return;
    158 	}
    159 
    160 	if (hash < 0 || hash >= OP_HASH_MAP_NR) {
    161 		fprintf(stderr, "hash value %u out of range.\n", hash);
    162 		return;
    163 	}
    164 
    165 	name = opd_get_hash_name(hash);
    166 	image = opd_get_image(name, proc->name, 0, note->pid, note->tgid);
    167 
    168 	opd_add_mapping(proc, image, note->addr, note->offset,
    169 	                note->addr + note->len);
    170 }
    171