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