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
31 #include "real_functions.h"
57 char filename[1024]; /* TODO dynamic allocation */
60 typedef int cmp_by_hash_and_name_t(void *a, void *b);
64 static pthread_mutex_t maps_lock = PTHREAD_MUTEX_INITIALIZER;
66 char **map_inst_list = NULL;
67 char *map_inst_list_set = NULL;
68 uint32_t map_inst_count = 0;
70 static struct data_list_t sections_list = {
71 {NULL}, /* head element */
72 {NULL}, /* tail for head list el */
76 static uint32_t addr_hash_table_el_count_total = 0;
77 static uint32_t addr_hash_table_el_count_buzy = 0;
78 static struct map_t **addr_hash_table = NULL;
80 static uint32_t name_hash_table_el_count_total = 0;
81 static uint32_t name_hash_table_el_count_buzy = 0;
82 static struct map_t **name_hash_table = NULL;
84 #define MAX_READERS_COUNT 8
85 static sem_t readers_mutex;
93 static uint32_t calc_string_hash(char *str)
96 while (*str != '\0') {
104 static struct data_list_t *get_first_el(struct data_list_t *list)
106 return (struct data_list_t *)list->first;
109 static struct data_list_t *get_next_el(struct data_list_t *el)
111 return (struct data_list_t *)el->next;
114 static void print_map(struct map_t *map)
116 PRINTMSG("mapp-> %p-%p %s %llx %s %llx %s",
126 static int read_mapping_line(FILE *mapfile, struct map_t *m)
132 PRINTERR("map_t param is NULL\n");
136 ret = fscanf(mapfile, "%p-%p %s %llx %s %llx%c%c",
139 (char *)m->permissions,
145 m->is_instrument = 0;
146 if (ret > 0 && ret != EOF) {
150 ret = (fgets((char *)m->filename, sizeof(m->filename), mapfile) != NULL);
152 /* remove leading white spaces */
153 if (m->filename[0] == ' ') {
154 char *p = m->filename;
158 memmove(m->filename, p, len);
160 len = strlen(m->filename);
166 m->filename[len] = '\0';
172 return (ret != 0 && ret != EOF);
175 static void print_list()
177 struct data_list_t *p = NULL;
178 struct map_t *m = NULL;
181 PRINTMSG("=====================================");
182 for (p = get_first_el(§ions_list); p != NULL && i < sections_list.count; p = p->next) {
183 m = (struct map_t *)p->data;
184 PRINTMSG("mapp[%03d]-> %p-%p %s %llx %s %llx %s",
198 static struct data_list_t *new_data(void)
200 struct data_list_t *el = (*real_malloc)(sizeof(*el));
207 static int data_list_append(struct data_list_t *head, struct data_list_t *el)
209 if (head->first == NULL) {
214 ((struct data_list_t *)head->tail)->next = el;
221 static int add_to_map_list(struct map_t **m)
223 struct data_list_t *el = new_data();
224 el->data = (void *)(*m);
225 el->hash = (*m)->hash;
226 data_list_append(§ions_list, el);
232 static void print_list_sorted(struct map_t **list)
234 struct map_t *m = NULL;
237 PRINTMSG("=====================================");
238 for (i = 0; i < sections_list.count; i++) {
240 if (m->is_instrument)
241 PRINTMSG("mapp[%03d]-> %016X %d <%s>",
250 static int realloc_array(struct map_t ***p, uint32_t *count_total,
251 uint32_t *count_buzy, cmp_by_hash_and_name_t cmp_func)
255 struct data_list_t *el;
259 if (sections_list.count != 0) {
260 *p = (*real_malloc)(sizeof(**p) * sections_list.count);
261 *count_total = sections_list.count;
265 if (sections_list.count > *count_total) {
266 /* not enaught space in hash */
267 *p = realloc(*p, sizeof(**p) * sections_list.count);
268 *count_total = sections_list.count;
271 *count_buzy = sections_list.count;
275 el = get_first_el(§ions_list);
277 for (i = 0; i < sections_list.count; i++) {
278 list[i] = (struct map_t *)el->data;
279 el = get_next_el(el);
283 uint32_t max = *count_buzy;
286 for (i = 0; i < max; i++)
287 for (j = i + 1; j < *count_buzy; j++) {
288 if (cmp_func(list[i], list[j]) > 0) {
300 static int create_addr_hash_table()
302 realloc_array(&addr_hash_table, &addr_hash_table_el_count_total,
303 &addr_hash_table_el_count_buzy, NULL);
308 static int cmp_by_hash_and_name(void *a, void *b)
310 if (((struct map_t *)a)->hash != ((struct map_t *)b)->hash) {
311 /* hash value is major priority */
312 if (((struct map_t *)a)->hash > ((struct map_t *)b)->hash)
314 else /* if i(a->hash < b->hash) */
318 /* retun filename cmp */
319 return strcmp(((struct map_t *)a)->filename,
320 ((struct map_t *)b)->filename);
327 static int create_name_hash_table()
329 realloc_array(&name_hash_table, &name_hash_table_el_count_total,
330 &name_hash_table_el_count_buzy, cmp_by_hash_and_name);
335 static struct map_t **get_map_by_filename(char *filename, int *count)
337 uint32_t hash = calc_string_hash(filename);
338 struct map_t **res = NULL;
339 uint32_t left, right, cur;
343 if (name_hash_table_el_count_buzy == 0 ||
344 name_hash_table[0]->hash > hash ||
345 name_hash_table[name_hash_table_el_count_buzy - 1]->hash < hash) {
350 right = name_hash_table_el_count_buzy - 1;
351 cur = (left + right) >> 1;
352 while (left < right) {
353 if (hash < name_hash_table[cur]->hash) {
355 cur = (left + right) >> 1;
358 if (hash > name_hash_table[cur]->hash) {
360 cur = (left + right) >> 1;
366 /* resolve collisions */
367 if (name_hash_table[cur]->hash == hash) {
369 /* get first with same hash */
374 if (name_hash_table[cur - 1]->hash != hash)
375 /* previous element have different hash */
377 /* previous element have the same hash */
381 /* get first with same hash and filename */
383 if (cur > name_hash_table_el_count_buzy - 1)
386 if (name_hash_table[cur]->hash != hash)
387 /* previous element have different hash */
389 if (strncmp(name_hash_table[cur]->filename, filename, strlen(filename)) == 0)
391 /* previous element have the same hash */
395 /* calculate sections count */
396 while (cur <= (name_hash_table_el_count_buzy - 1) &&
397 name_hash_table[cur]->hash == hash &&
398 strncmp(name_hash_table[cur]->filename, filename, strlen(filename)) == 0) {
400 res = &name_hash_table[cur];
410 static int update_is_instrument_lib_attr_nolock()
415 /* clear is_instrument fields */
416 for (i = 0; i < name_hash_table_el_count_buzy; i++)
417 name_hash_table[i]->is_instrument = 0;
419 /* set is_instrument fields */
420 for (i = 0; i < map_inst_count; i++) {
422 map = get_map_by_filename(map_inst_list[i], &count);
423 for (;count > 0; count--) {
424 PRINTMSG("set 1!!! = %s [%p:%p]", (*map)->filename,
425 (*map)->addr, (*map)->endaddr);
426 (*map)->is_instrument = 1;
432 print_list_sorted(name_hash_table);
435 static struct map_t *get_map_by_addr(void *addr)
437 struct map_t *d = NULL;
438 struct map_t *res = NULL;
439 uint32_t left, right, cur;
441 if (addr_hash_table_el_count_buzy == 0)
444 if (addr < addr_hash_table[0]->addr)
447 if (addr > addr_hash_table[addr_hash_table_el_count_buzy - 1]->endaddr)
451 right = addr_hash_table_el_count_buzy - 1;
453 while (left < right) {
454 cur = (left + right) >> 1;
456 d = (struct map_t *)addr_hash_table[cur];
457 if (addr < d->addr) {
461 if (addr > d->endaddr) {
467 return (addr_hash_table[cur]);
471 d = (struct map_t *)addr_hash_table[left];
472 if ((d->addr <= addr) && (addr <= d->endaddr))
473 res = addr_hash_table[left];
480 static void maps_reader_lock_all()
483 for (i = 0; i < MAX_READERS_COUNT; i++)
484 sem_wait(&readers_mutex);
487 static void maps_reader_unlock_all()
490 for (i = 0; i < MAX_READERS_COUNT; i++)
491 sem_post(&readers_mutex);
494 static inline void maps_reader_lock()
496 sem_wait(&readers_mutex); /* down semaphore */
499 static inline void maps_reader_unlock()
501 sem_post(&readers_mutex); /* up semaphore */
504 static inline void maps_writer_lock()
506 pthread_mutex_lock(&maps_lock);
509 static inline void maps_writer_unlock()
511 pthread_mutex_unlock(&maps_lock);
514 /* TODO refactor this function to alloc map_inst_list_set and copy it frm src*/
515 // WARNING! this function use maps_set and set it to NULL
516 // so first param must be malloced and do not free maps_set after call
517 int set_map_inst_list(char **maps_set, uint32_t maps_count)
524 maps_reader_lock_all();
526 if (map_inst_list != NULL) {
528 map_inst_list = NULL;
531 if (map_inst_list_set != NULL) {
532 free(map_inst_list_set);
533 map_inst_list_set = NULL;
536 map_inst_list = real_malloc(sizeof(*map_inst_list) * maps_count);
537 if (maps_count != 0 && map_inst_list == NULL) {
538 PRINTERR("Cannot allocate data for map_inst_list\n");
543 if (maps_set != NULL && *maps_set != NULL && map_inst_list != NULL) {
544 map_inst_list_set = *maps_set;
545 map_inst_count = maps_count;
547 /* add library mapping names */
548 p = map_inst_list_set + sizeof(maps_count);
549 for (i = 0; i < maps_count; i++) {
550 map_inst_list[i] = p;
552 PRINTMSG("-------> %s", map_inst_list[i]);
558 res = update_is_instrument_lib_attr_nolock();
560 if (maps_set != NULL)
564 maps_reader_unlock_all();
565 maps_writer_unlock();
574 maps_reader_lock_all();
575 FILE *f = fopen("/proc/self/maps", "r");
576 struct map_t *map = NULL;
578 /* read to exists locations */
579 struct data_list_t *cur = get_first_el(§ions_list);
580 sections_list.count = 0;
581 while (cur != NULL) {
582 map = (struct map_t *)cur->data;
583 if (!read_mapping_line(f, map))
585 if (map->permissions[2] == 'x') {
586 map->hash = calc_string_hash(map->filename);
587 cur->hash = map->hash;
588 sections_list.count++;
589 cur = get_next_el(cur);
594 map = (*real_malloc)(sizeof(*map));
596 PRINTERR("Can not alloc data for map\n");
600 while (read_mapping_line(f, map)) {
601 if (map->permissions[2] == 'x') {
602 map->hash = calc_string_hash(map->filename);
603 add_to_map_list(&map);
605 map = (*real_malloc)(sizeof(*map));
612 create_addr_hash_table();
613 create_name_hash_table();
615 update_is_instrument_lib_attr_nolock();
620 maps_reader_unlock_all();
621 maps_writer_unlock();
626 int maps_print_maps_by_addr(const void *addr)
629 struct map_t *map = NULL;
632 map = get_map_by_addr((void *)addr);
635 maps_reader_unlock();
640 int maps_is_instrument_section_by_addr_no_remap(const void *addr)
646 map = get_map_by_addr((void *)addr);
648 res = map->is_instrument;
649 maps_reader_unlock();
655 /* interface function */
656 int maps_is_instrument_section_by_addr(const void *addr)
658 int ret = maps_is_instrument_section_by_addr_no_remap(addr);
661 PRINTMSG("========> hz addr %p. remap", addr);
662 if (maps_make() != 0) {
663 PRINTERR("maps make failed\n");
667 ret = maps_is_instrument_section_by_addr_no_remap(addr);
670 PRINTERR("!!!!unknown addr %p", addr);
671 get_map_by_addr((void *)addr);
682 /* must be called ones */
688 res = sem_init(&readers_mutex, 0, MAX_READERS_COUNT);
689 set_map_inst_list(NULL, 0);