4 * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
8 * Cherepanov Vitaliy <v.cherepanov@samsung.com>
10 * This library is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU Lesser General Public License as published by the
12 * Free Software Foundation; either version 2.1 of the License, or (at your option)
15 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
16 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18 * License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library; if not, write to the Free Software Foundation, Inc., 51
22 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
56 char filename[1024]; /* TODO dynamic allocation */
59 typedef int cmp_by_hash_and_name_t(void *a, void *b);
63 static pthread_mutex_t maps_lock = PTHREAD_MUTEX_INITIALIZER;
65 char **map_inst_list = NULL;
66 char *map_inst_list_set = NULL;
67 uint32_t map_inst_count = 0;
69 static struct data_list_t sections_list = {
70 {NULL}, /* head element */
71 {NULL}, /* tail for head list el */
75 static uint32_t addr_hash_table_el_count_total = 0;
76 static uint32_t addr_hash_table_el_count_buzy = 0;
77 static struct map_t **addr_hash_table = NULL;
79 static uint32_t name_hash_table_el_count_total = 0;
80 static uint32_t name_hash_table_el_count_buzy = 0;
81 static struct map_t **name_hash_table = NULL;
83 #define MAX_READERS_COUNT 8
84 static sem_t readers_mutex;
92 static uint32_t calc_string_hash(char *str)
95 while (*str != '\0') {
103 static struct data_list_t *get_first_el(struct data_list_t *list)
105 return (struct data_list_t *)list->first;
108 static struct data_list_t *get_next_el(struct data_list_t *el)
110 return (struct data_list_t *)el->next;
113 static void print_map(struct map_t *map)
115 PRINTMSG("mapp-> %p-%p %s %llx %s %llx %s",
125 static int read_mapping_line(FILE *mapfile, struct map_t *m)
128 int ret = fscanf(mapfile, "%p-%p %s %llx %s %llx%c%c",
131 (char *)m->permissions,
137 m->is_instrument = 0;
138 if (ret > 0 && ret != EOF) {
140 ret = (fgets((char *)m->filename, sizeof(m->filename), mapfile) != NULL);
143 /* remove leading white spaces */
144 if (m->filename[0] == ' ') {
145 char *p = m->filename;
149 memcpy(m->filename, p, len);
151 len = strlen(m->filename);
153 m->filename[len-1] = '\0';
156 m->filename[0] = '\0'; /* no filename */
162 return (ret != 0 && ret != EOF);
165 static void print_list()
167 struct data_list_t *p = NULL;
168 struct map_t *m = NULL;
171 PRINTMSG("=====================================");
172 for (p = get_first_el(§ions_list); p != NULL && i < sections_list.count; p = p->next) {
173 m = (struct map_t *)p->data;
174 PRINTMSG("mapp[%03d]-> %p-%p %s %llx %s %llx %s",
187 static struct data_list_t *new_data(void)
189 struct data_list_t *el = (*real_malloc)(sizeof(*el));
196 static int data_list_append(struct data_list_t *head, struct data_list_t *el)
198 if (head->first == NULL) {
203 ((struct data_list_t *)head->tail)->next = el;
210 static int add_to_map_list(struct map_t **m)
212 struct data_list_t *el = new_data();
213 el->data = (void *)(*m);
214 el->hash = (*m)->hash;
215 data_list_append(§ions_list, el);
221 static void print_list_sorted(struct map_t **list)
223 struct map_t *m = NULL;
226 PRINTMSG("=====================================");
227 for (i = 0; i < sections_list.count; i++) {
229 if (m->is_instrument)
230 PRINTMSG("mapp[%03d]-> %016X %d <%s>",
238 static int realloc_array(struct map_t ***p, uint32_t *count_total,
239 uint32_t *count_buzy, cmp_by_hash_and_name_t cmp_func)
243 struct data_list_t *el;
247 if (sections_list.count != 0) {
248 *p = (*real_malloc)(sizeof(**p) * sections_list.count);
249 *count_total = sections_list.count;
253 if (sections_list.count > *count_total) {
254 /* not enaught space in hash */
255 *p = realloc(*p, sizeof(**p) * sections_list.count);
256 *count_total = sections_list.count;
259 *count_buzy = sections_list.count;
263 el = get_first_el(§ions_list);
265 for (i = 0; i < sections_list.count; i++) {
266 list[i] = (struct map_t *)el->data;
267 el = get_next_el(el);
271 uint32_t max = *count_buzy;
274 for (i = 0; i < max; i++)
275 for (j = i + 1; j < *count_buzy; j++) {
276 if (cmp_func(list[i], list[j]) > 0) {
288 static int create_addr_hash_table()
290 realloc_array(&addr_hash_table, &addr_hash_table_el_count_total,
291 &addr_hash_table_el_count_buzy, NULL);
296 static int cmp_by_hash_and_name(void *a, void *b)
298 if (((struct map_t *)a)->hash != ((struct map_t *)b)->hash) {
299 /* hash value is major priority */
300 if (((struct map_t *)a)->hash > ((struct map_t *)b)->hash)
302 else /* if i(a->hash < b->hash) */
306 /* retun filename cmp */
307 return strcmp(((struct map_t *)a)->filename,
308 ((struct map_t *)b)->filename);
315 static int create_name_hash_table()
317 realloc_array(&name_hash_table, &name_hash_table_el_count_total,
318 &name_hash_table_el_count_buzy, cmp_by_hash_and_name);
323 static struct map_t *get_map_by_filename(char *filename)
325 uint32_t hash = calc_string_hash(filename);
326 struct map_t *res = NULL;
327 uint32_t left, right, cur;
329 if (name_hash_table_el_count_buzy == 0 ||
330 name_hash_table[0]->hash > hash ||
331 name_hash_table[name_hash_table_el_count_buzy - 1]->hash < hash) {
336 right = name_hash_table_el_count_buzy - 1;
337 cur = (left + right) >> 1;
338 while (left < right) {
339 if (hash < name_hash_table[cur]->hash) {
341 cur = (left + right) >> 1;
344 if (hash > name_hash_table[cur]->hash) {
346 cur = (left + right) >> 1;
352 /* resolve collisions */
353 if (name_hash_table[cur]->hash == hash) {
358 if (name_hash_table[cur - 1]->hash != hash)
359 /* previous element have different hash */
361 /* previous element have the same hash */
364 res = name_hash_table[cur];
371 static int update_is_instrument_lib_attr_nolock()
376 /* clear is_instrument fields */
377 for (i = 0; i < name_hash_table_el_count_buzy; i++)
378 name_hash_table[i]->is_instrument = 0;
380 /* set is_instrument fields */
381 for (i = 0; i < map_inst_count; i++) {
382 map = get_map_by_filename(map_inst_list[i]);
384 PRINTMSG("set 1!!! = %s [%p:%p]", map->filename,
385 map->addr, map->endaddr);
386 map->is_instrument = 1;
391 print_list_sorted(name_hash_table);
394 static struct map_t *get_map_by_addr(void *addr)
396 struct map_t *d = NULL;
397 struct map_t *res = NULL;
398 uint32_t left, right, cur;
400 if (addr_hash_table_el_count_buzy == 0)
403 if (addr < addr_hash_table[0]->addr)
406 if (addr > addr_hash_table[addr_hash_table_el_count_buzy - 1]->addr)
410 right = addr_hash_table_el_count_buzy - 1;
412 while (left < right) {
413 cur = (left + right) >> 1;
415 d = (struct map_t *)addr_hash_table[cur];
416 if (addr < d->addr) {
420 if (addr > d->endaddr) {
426 return (addr_hash_table[cur]);
430 d = (struct map_t *)addr_hash_table[left];
431 if ((d->addr <= addr) && (addr <= d->endaddr))
432 res = addr_hash_table[left];
439 static void maps_reader_lock_all()
442 for (i = 0; i < MAX_READERS_COUNT; i++)
443 sem_wait(&readers_mutex);
446 static void maps_reader_unlock_all()
449 for (i = 0; i < MAX_READERS_COUNT; i++)
450 sem_post(&readers_mutex);
453 static inline void maps_reader_lock()
455 sem_wait(&readers_mutex); /* down semaphore */
458 static inline void maps_reader_unlock()
460 sem_post(&readers_mutex); /* up semaphore */
463 static inline void maps_writer_lock()
465 pthread_mutex_lock(&maps_lock);
468 static inline void maps_writer_unlock()
470 pthread_mutex_unlock(&maps_lock);
473 // WARNING! this function use maps_set and set it to NULL
474 // so first param must be malloced and do not free maps_set after call
475 int set_map_inst_list(char **maps_set, uint32_t maps_count)
482 maps_reader_lock_all();
484 if (map_inst_list != NULL) {
486 map_inst_list = NULL;
489 if (map_inst_list_set != NULL) {
490 free(map_inst_list_set);
491 map_inst_list_set = NULL;
494 map_inst_list = real_malloc(sizeof(*map_inst_list) * maps_count);
495 if (maps_set != NULL && *maps_set != NULL)
496 map_inst_list_set = *maps_set;
497 map_inst_count = maps_count;
499 /* add library mapping names */
500 p = map_inst_list_set + sizeof(maps_count);
501 for (i = 0; i < maps_count; i++) {
502 map_inst_list[i] = p;
504 PRINTMSG("-------> %s", map_inst_list[i]);
507 res = update_is_instrument_lib_attr_nolock();
509 if (maps_set != NULL)
512 maps_reader_unlock_all();
513 maps_writer_unlock();
521 maps_reader_lock_all();
522 FILE *f = fopen("/proc/self/maps", "r");
523 struct map_t *map = NULL;
525 /* read to exists locations */
526 struct data_list_t *cur = get_first_el(§ions_list);
527 sections_list.count = 0;
528 while (cur != NULL) {
529 map = (struct map_t *)cur->data;
530 if (!read_mapping_line(f, map))
532 if (map->permissions[2] == 'x') {
533 map->hash = calc_string_hash(map->filename);
534 cur->hash = map->hash;
535 sections_list.count++;
536 cur = get_next_el(cur);
541 map = (*real_malloc)(sizeof(*map));
542 while (read_mapping_line(f, map)) {
543 if (map->permissions[2] == 'x') {
544 map->hash = calc_string_hash(map->filename);
545 add_to_map_list(&map);
547 map = (*real_malloc)(sizeof(*map));
556 create_addr_hash_table();
557 create_name_hash_table();
559 update_is_instrument_lib_attr_nolock();
561 maps_reader_unlock_all();
562 maps_writer_unlock();
565 int maps_print_maps_by_addr(const void *addr)
568 struct map_t *map = NULL;
571 map = get_map_by_addr((void *)addr);
574 maps_reader_unlock();
579 int maps_is_instrument_section_by_addr_no_remap(const void *addr)
585 map = get_map_by_addr((void *)addr);
587 res = map->is_instrument;
588 maps_reader_unlock();
594 /* interface function */
595 int maps_is_instrument_section_by_addr(const void *addr)
597 int ret = maps_is_instrument_section_by_addr_no_remap(addr);
600 PRINTMSG("========> hz addr %p. remap", addr);
602 ret = maps_is_instrument_section_by_addr_no_remap(addr);
605 PRINTERR("!!!!unknown addr %p", addr);
606 get_map_by_addr((void *)addr);
616 /* must be called ones */
622 res = sem_init(&readers_mutex, 0, MAX_READERS_COUNT);
623 set_map_inst_list(NULL, 0);