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