18cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/** 28cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @file opd_mapping.c 38cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Management of process mappings 48cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 58cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Copyright 2002 OProfile authors 68cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Read the file COPYING 78cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 88cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author John Levon 98cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author Philippe Elie 108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "opd_mapping.h" 138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "opd_proc.h" 148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "opd_image.h" 158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "opd_printf.h" 168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_interface.h" 188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_config_24.h" 198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_libiberty.h" 208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <sys/mman.h> 228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <limits.h> 238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <stdlib.h> 248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <stdio.h> 258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <string.h> 268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* hash map device mmap */ 288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic struct op_hash_index * hashmap; 298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* already seen mapping name */ 308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic char const * hash_name[OP_HASH_MAP_NR]; 318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid opd_cleanup_hash_name(void) 348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int i; 368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd for (i = 0; i < OP_HASH_MAP_NR; ++i) 378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd free((char *)hash_name[i]); 388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid opd_init_hash_map(void) 438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd extern fd_t hashmapdevfd; 458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd hashmap = mmap(0, OP_HASH_MAP_SIZE, PROT_READ, MAP_SHARED, hashmapdevfd, 0); 478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((long)hashmap == -1) { 488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd perror("oprofiled: couldn't mmap hash map"); 498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd exit(EXIT_FAILURE); 508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid opd_kill_maps(struct opd_proc * proc) 568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct list_head * pos, * pos2; 588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd list_for_each_safe(pos, pos2, &proc->maps) { 608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct opd_map * map = list_entry(pos, struct opd_map, next); 618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd list_del(pos); 628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd opd_delete_image(map->image); 638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd free(map); 648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid opd_add_mapping(struct opd_proc * proc, struct opd_image * image, 698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unsigned long start, unsigned long offset, unsigned long end) 708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct opd_map * map; 728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd verbprintf(vmisc, "Adding mapping for process %d: 0x%.8lx-0x%.8lx, off 0x%.8lx, \"%s\"\n", 748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd proc->tid, start, end, offset, image->name); 758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd map = malloc(sizeof(struct opd_map)); 778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* first map is the primary image */ 798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (list_empty(&proc->maps)) { 808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (proc->name) 818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd free((char *)proc->name); 828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd proc->name = xstrdup(image->name); 838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd image->ref_count++; 868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd map->image = image; 888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd map->start = start; 898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd map->offset = offset; 908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd map->end = end; 918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd list_add_tail(&map->next, &proc->maps); 928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/** 968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * get_from_pool - retrieve string from hash map pool 978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @param ind index into pool 988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddinline static char * get_from_pool(uint ind) 1008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 1018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return ((char *)(hashmap + OP_HASH_MAP_NR) + ind); 1028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/** 1068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * opg_get_hash_name - find a mapping name from a hash 1078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @param hash hash value for this name 1088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 1098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic char const * opd_get_hash_name(int hash) 1108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 1118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd char file[PATH_MAX]; 1128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd char * c = &file[PATH_MAX-1]; 1138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int orighash = hash; 1148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (hash_name[hash]) 1168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return hash_name[hash]; 1178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *c = '\0'; 1198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd while (hash) { 1208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd char * name = get_from_pool(hashmap[hash].name); 1218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (strlen(name) + 1 + strlen(c) >= PATH_MAX) { 1238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd fprintf(stderr, "String \"%s\" too large.\n", c); 1248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd exit(EXIT_FAILURE); 1258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd c -= strlen(name) + 1; 1288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *c = '/'; 1298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd strncpy(c + 1, name, strlen(name)); 1308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* move onto parent */ 1328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd hash = hashmap[hash].parent; 1338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return hash_name[orighash] = xstrdup(c); 1368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid opd_handle_mapping(struct op_note const * note) 1408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 1418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct opd_proc * proc; 1428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct opd_image * image; 1438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int hash; 1448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd char const * name; 1458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd proc = opd_get_proc(note->pid, note->tgid); 1478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!proc) { 1498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd verbprintf(vmisc, "Told about mapping for non-existent process %u.\n", note->pid); 1508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd proc = opd_new_proc(note->pid, note->tgid); 1518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd hash = note->hash; 1548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (hash == -1) { 1568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* possibly deleted file */ 1578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return; 1588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (hash < 0 || hash >= OP_HASH_MAP_NR) { 1618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd fprintf(stderr, "hash value %u out of range.\n", hash); 1628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return; 1638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd name = opd_get_hash_name(hash); 1668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd image = opd_get_image(name, proc->name, 0, note->pid, note->tgid); 1678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd opd_add_mapping(proc, image, note->addr, note->offset, 1698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd note->addr + note->len); 1708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 171