1/**
2 * @file opd_cookie.c
3 * cookie -> name cache
4 *
5 * @remark Copyright 2002, 2005 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author John Levon
9 */
10
11#include "opd_cookie.h"
12#include "oprofiled.h"
13#include "op_list.h"
14#include "op_libiberty.h"
15
16#include <sys/syscall.h>
17#include <unistd.h>
18#include <limits.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <errno.h>
22
23#ifndef __NR_lookup_dcookie
24#if defined(__i386__)
25#define __NR_lookup_dcookie 253
26#elif defined(__x86_64__)
27#define __NR_lookup_dcookie 212
28#elif defined(__powerpc__)
29#define __NR_lookup_dcookie 235
30#elif defined(__alpha__)
31#define __NR_lookup_dcookie 406
32#elif defined(__hppa__)
33#define __NR_lookup_dcookie 223
34#elif defined(__ia64__)
35#define __NR_lookup_dcookie 1237
36#elif defined(__sparc__)
37/* untested */
38#define __NR_lookup_dcookie 208
39#elif defined(__s390__) || defined (__s390x__)
40#define __NR_lookup_dcookie 110
41#elif defined(__arm__)
42#define __NR_lookup_dcookie (__NR_SYSCALL_BASE+249)
43#elif defined(__mips__)
44#include <sgidefs.h>
45/* O32 */
46#if _MIPS_SIM == _MIPS_SIM_ABI32
47#define __NR_lookup_dcookie 4247
48/* N64 */
49#elif _MIPS_SIM == _MIPS_SIM_ABI64
50#define __NR_lookup_dcookie 5206
51/* N32 */
52#elif _MIPS_SIM == _MIPS_SIM_NABI32
53#define __NR_lookup_dcookie 6206
54#else
55#error Unknown MIPS ABI: Dunno __NR_lookup_dcookie
56#endif
57#else
58#error Please define __NR_lookup_dcookie for your architecture
59#endif
60#endif /* __NR_lookup_dcookie */
61
62#if (defined(__powerpc__) && !defined(__powerpc64__)) || defined(__hppa__)\
63	|| (defined(__s390__) && !defined(__s390x__)) \
64	|| (defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32) \
65	    && defined(__MIPSEB__)) \
66        || (defined(__arm__) && defined(__ARM_EABI__) \
67            && defined(__ARMEB__))
68static inline int lookup_dcookie(cookie_t cookie, char * buf, size_t size)
69{
70	return syscall(__NR_lookup_dcookie, (unsigned long)(cookie >> 32),
71		       (unsigned long)(cookie & 0xffffffff), buf, size);
72}
73#elif (defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)) \
74	|| (defined(__arm__) && defined(__ARM_EABI__))
75static inline int lookup_dcookie(cookie_t cookie, char * buf, size_t size)
76{
77	return syscall(__NR_lookup_dcookie,
78		       (unsigned long)(cookie & 0xffffffff),
79		       (unsigned long)(cookie >> 32), buf, size);
80}
81#else
82static inline int lookup_dcookie(cookie_t cookie, char * buf, size_t size)
83{
84	return syscall(__NR_lookup_dcookie, cookie, buf, size);
85}
86#endif
87
88
89struct cookie_entry {
90	cookie_t value;
91	char * name;
92	int ignored;
93	struct list_head list;
94};
95
96
97#define HASH_SIZE 512
98#define HASH_BITS (HASH_SIZE - 1)
99
100static struct list_head hashes[HASH_SIZE];
101
102static struct cookie_entry * create_cookie(cookie_t cookie)
103{
104	int err;
105	struct cookie_entry * entry = xmalloc(sizeof(struct cookie_entry));
106
107	entry->value = cookie;
108	entry->name = xmalloc(PATH_MAX + 1);
109
110	err = lookup_dcookie(cookie, entry->name, PATH_MAX);
111
112	if (err < 0) {
113		fprintf(stderr, "Lookup of cookie %llx failed, errno=%d\n",
114		       cookie, errno);
115		free(entry->name);
116		entry->name = NULL;
117		entry->ignored = 0;
118	} else {
119		entry->ignored = is_image_ignored(entry->name);
120	}
121
122	return entry;
123}
124
125
126/* Cookie monster want cookie! */
127static unsigned long hash_cookie(cookie_t cookie)
128{
129	return (cookie >> DCOOKIE_SHIFT) & (HASH_SIZE - 1);
130}
131
132
133char const * find_cookie(cookie_t cookie)
134{
135	unsigned long hash = hash_cookie(cookie);
136	struct list_head * pos;
137	struct cookie_entry * entry;
138
139	if (cookie == INVALID_COOKIE || cookie == NO_COOKIE)
140		return NULL;
141
142	list_for_each(pos, &hashes[hash]) {
143		entry = list_entry(pos, struct cookie_entry, list);
144		if (entry->value == cookie)
145			goto out;
146	}
147
148	/* not sure this can ever happen due to is_cookie_ignored */
149	entry = create_cookie(cookie);
150	list_add(&entry->list, &hashes[hash]);
151out:
152	return entry->name;
153}
154
155
156int is_cookie_ignored(cookie_t cookie)
157{
158	unsigned long hash = hash_cookie(cookie);
159	struct list_head * pos;
160	struct cookie_entry * entry;
161
162	if (cookie == INVALID_COOKIE || cookie == NO_COOKIE)
163		return 1;
164
165	list_for_each(pos, &hashes[hash]) {
166		entry = list_entry(pos, struct cookie_entry, list);
167		if (entry->value == cookie)
168			goto out;
169	}
170
171	entry = create_cookie(cookie);
172	list_add(&entry->list, &hashes[hash]);
173out:
174	return entry->ignored;
175}
176
177
178char const * verbose_cookie(cookie_t cookie)
179{
180	unsigned long hash = hash_cookie(cookie);
181	struct list_head * pos;
182	struct cookie_entry * entry;
183
184	if (cookie == INVALID_COOKIE)
185		return "invalid";
186
187	if (cookie == NO_COOKIE)
188		return "anonymous";
189
190	list_for_each(pos, &hashes[hash]) {
191		entry = list_entry(pos, struct cookie_entry, list);
192		if (entry->value == cookie) {
193			if (!entry->name)
194				return "failed lookup";
195			return entry->name;
196		}
197	}
198
199	return "not hashed";
200}
201
202
203void cookie_init(void)
204{
205	size_t i;
206
207	for (i = 0; i < HASH_SIZE; ++i)
208		list_init(&hashes[i]);
209}
210