[FEATURE] internal external call instrumentation 66/24466/5
authorVitaliy Cherepanov <v.cherepanov@samsung.com>
Tue, 15 Jul 2014 05:46:58 +0000 (09:46 +0400)
committerVitaliy Cherepanov <v.cherepanov@samsung.com>
Wed, 16 Jul 2014 12:29:30 +0000 (16:29 +0400)
if the library is instrumented all ld probes for this lib will be packed
if regular feture is enabled but always feature is not

Change-Id: I07373c0dd69c15caf5c2305b6b416295af0eefe8
Signed-off-by: Vitaliy Cherepanov <v.cherepanov@samsung.com>
Makefile
helper/damaps.c [new file with mode: 0755]
helper/libdaprobe.c
include/damaps.h [new file with mode: 0644]
include/probeinfo.h

index c4e7a0b..a8bae29 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -70,6 +70,7 @@ UTILITY_SRCS =                                \
        ./helper/dacollection.c         \
        ./helper/dacapture.c            \
        ./helper/daforkexec.c           \
+       ./helper/damaps.c                       \
        ./custom_chart/da_chart.c       \
 
 PROBE_SRCS =                                   \
diff --git a/helper/damaps.c b/helper/damaps.c
new file mode 100755 (executable)
index 0000000..5dad110
--- /dev/null
@@ -0,0 +1,623 @@
+/*
+ *  DA probe
+ *
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Cherepanov Vitaliy <v.cherepanov@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <unistd.h>
+#include "dahelper.h"
+
+struct data_list_t {
+       union {
+               void *next;
+               void *first;
+       };
+       union {
+               void *data;
+               void *tail;
+       };
+       union {
+               uint32_t hash;
+               uint32_t count;
+       };
+};
+
+struct map_t {
+       uint32_t hash;
+       int is_instrument;
+       void *addr;
+       void *endaddr;
+       char permissions[20];
+       long long offset;
+       char device[256];
+       long long inode;
+       char filename[1024]; /* TODO dynamic allocation */
+};
+
+typedef int cmp_by_hash_and_name_t(void *a, void *b);
+
+/* variables */
+
+static pthread_mutex_t maps_lock = PTHREAD_MUTEX_INITIALIZER;
+
+char **map_inst_list = NULL;
+char *map_inst_list_set = NULL;
+uint32_t map_inst_count = 0;
+
+static struct data_list_t sections_list = {
+       {NULL}, /* head element */
+       {NULL}, /* tail for head list el */
+       {0},    /* count */
+};
+
+static uint32_t addr_hash_table_el_count_total = 0;
+static uint32_t addr_hash_table_el_count_buzy = 0;
+static struct map_t **addr_hash_table = NULL;
+
+static uint32_t name_hash_table_el_count_total = 0;
+static uint32_t name_hash_table_el_count_buzy = 0;
+static struct map_t **name_hash_table = NULL;
+
+#define MAX_READERS_COUNT 8
+static sem_t readers_mutex;
+
+/*
+ *
+ * Functions
+ *
+ */
+
+static uint32_t calc_string_hash(char *str)
+{
+       uint32_t res = 0;
+       while (*str != '\0') {
+               res += *str;
+               res <<= 1;
+               str++;
+       }
+       return res;
+}
+
+static struct data_list_t *get_first_el(struct data_list_t *list)
+{
+       return (struct data_list_t *)list->first;
+}
+
+static struct data_list_t *get_next_el(struct data_list_t *el)
+{
+       return (struct data_list_t *)el->next;
+}
+
+static void print_map(struct map_t *map)
+{
+       PRINTMSG("mapp-> %p-%p %s %llx %s %llx %s",
+                 map->addr,
+                 map->endaddr,
+                 map->permissions,
+                 map->offset,
+                 map->device,
+                 map->inode,
+                 map->filename);
+}
+
+static int read_mapping_line(FILE *mapfile, struct map_t *m)
+{
+       char ch1, ch2;
+       int ret = fscanf(mapfile, "%p-%p %s %llx %s %llx%c%c",
+                        &m->addr,
+                        &m->endaddr,
+                        (char *)m->permissions,
+                        &m->offset,
+                        (char *)m->device,
+                        &m->inode,
+                        &ch1, &ch2);
+
+       m->is_instrument = 0;
+       if (ret > 0 && ret != EOF) {
+               if (ch2 != '\n') {
+                       ret = (fgets((char *)m->filename, sizeof(m->filename), mapfile) != NULL);
+                       if (ret) {
+                               int len;
+                               /* remove leading white spaces */
+                               if (m->filename[0] == ' ') {
+                                       char *p = m->filename;
+                                       while (*p == ' ')
+                                               p++;
+                                       len = strlen(p);
+                                       memcpy(m->filename, p, len);
+                               } else
+                                       len = strlen(m->filename);
+
+                               m->filename[len-1] = '\0';
+                       }
+               } else
+                       m->filename[0] = '\0';  /* no filename */
+
+               return 1;
+       } else
+               return 0;
+
+       return (ret != 0 && ret != EOF);
+}
+
+static void print_list()
+{
+       struct data_list_t *p = NULL;
+       struct map_t *m = NULL;
+       uint32_t i = 0;
+
+       PRINTMSG("=====================================");
+       for (p = get_first_el(&sections_list); p != NULL && i < sections_list.count; p = p->next) {
+               m = (struct map_t *)p->data;
+               PRINTMSG("mapp[%03d]-> %p-%p %s %llx %s %llx %s",
+                        ++i,
+                        m->addr,
+                        m->endaddr,
+                        m->permissions,
+                        m->offset,
+                        m->device,
+                        m->inode,
+                        m->filename);
+       }
+
+}
+
+static struct data_list_t *new_data(void)
+{
+       struct data_list_t *el = (*real_malloc)(sizeof(*el));
+       el->next = NULL;
+       el->hash = 0;
+       el->data = NULL;
+       return el;
+}
+
+static int data_list_append(struct data_list_t *head, struct data_list_t *el)
+{
+       if (head->first == NULL) {
+               // empty list
+               head->first = el;
+               head->tail = el;
+       } else {
+               ((struct data_list_t *)head->tail)->next = el;
+               head->tail = el;
+       }
+       head->count++;
+       return 0;
+}
+
+static int add_to_map_list(struct map_t **m)
+{
+       struct data_list_t *el = new_data();
+       el->data = (void *)(*m);
+       el->hash = (*m)->hash;
+       data_list_append(&sections_list, el);
+       *m = NULL;
+
+       return 0;
+}
+
+static void print_list_sorted(struct map_t **list)
+{
+       struct map_t *m = NULL;
+       uint32_t i = 0;
+
+       PRINTMSG("=====================================");
+       for (i = 0; i < sections_list.count; i++) {
+               m = list[i];
+               if (m->is_instrument)
+               PRINTMSG("mapp[%03d]-> %016X %d <%s>",
+                        i + 1,
+                        m->hash,
+                        m->is_instrument,
+                        m->filename);
+       }
+}
+
+static int realloc_array(struct map_t ***p, uint32_t *count_total,
+                        uint32_t *count_buzy, cmp_by_hash_and_name_t cmp_func)
+{
+       uint32_t i, j;
+       struct map_t **list;
+       struct data_list_t *el;
+
+       if (*p == NULL) {
+               /* first init */
+               if (sections_list.count != 0) {
+                       *p = (*real_malloc)(sizeof(**p) * sections_list.count);
+                       *count_total = sections_list.count;
+               }
+       } else {
+               /* not first init */
+               if (sections_list.count > *count_total) {
+                       /* not enaught space in hash */
+                       *p = realloc(*p, sizeof(**p) * sections_list.count);
+                       *count_total = sections_list.count;
+               }
+       }
+       *count_buzy = sections_list.count;
+
+       /* fill table */
+       list = *p;
+       el = get_first_el(&sections_list);
+
+       for (i = 0; i < sections_list.count; i++) {
+               list[i] = (struct map_t *)el->data;
+               el = get_next_el(el);
+       }
+
+       /* sort */
+       uint32_t max = *count_buzy;
+       struct map_t *tmp;
+       if (cmp_func) {
+               for (i = 0; i < max; i++)
+                       for (j = i + 1; j < *count_buzy; j++) {
+                               if (cmp_func(list[i], list[j]) > 0) {
+                                       tmp = list[i];
+                                       list[i] = list[j];
+                                       list[j] = tmp;
+                               }
+                       }
+               return 0;
+       }
+
+       return 0;
+}
+
+static int create_addr_hash_table()
+{
+       realloc_array(&addr_hash_table, &addr_hash_table_el_count_total,
+                     &addr_hash_table_el_count_buzy, NULL);
+
+       return 0;
+}
+
+static int cmp_by_hash_and_name(void *a, void *b)
+{
+       if (((struct map_t *)a)->hash != ((struct map_t *)b)->hash) {
+               /* hash value is major priority */
+               if (((struct map_t *)a)->hash > ((struct map_t *)b)->hash)
+                       return 1;
+               else /* if i(a->hash < b->hash) */
+                       return -1;
+       } else {
+               /* hash equel */
+               /* retun filename cmp */
+               return strcmp(((struct map_t *)a)->filename,
+                             ((struct map_t *)b)->filename);
+       }
+
+       /* never happens */
+       return 0;
+}
+
+static int create_name_hash_table()
+{
+       realloc_array(&name_hash_table, &name_hash_table_el_count_total,
+                     &name_hash_table_el_count_buzy, cmp_by_hash_and_name);
+
+       return 0;
+}
+
+static struct map_t *get_map_by_filename(char *filename)
+{
+       uint32_t hash = calc_string_hash(filename);
+       struct map_t *res = NULL;
+       uint32_t left, right, cur;
+
+       if (name_hash_table_el_count_buzy == 0 ||
+           name_hash_table[0]->hash > hash ||
+           name_hash_table[name_hash_table_el_count_buzy - 1]->hash < hash) {
+               goto find_exit;
+       }
+
+       left = 0;
+       right = name_hash_table_el_count_buzy - 1;
+       cur = (left + right) >> 1;
+       while (left < right) {
+               if (hash < name_hash_table[cur]->hash) {
+                       right = cur - 1;
+                       cur = (left + right) >> 1;
+                       continue;
+               }
+               if (hash > name_hash_table[cur]->hash) {
+                       left = cur + 1;
+                       cur = (left + right) >> 1;
+                       continue;
+               }
+               break;
+       }
+
+       /* resolve collisions */
+       if (name_hash_table[cur]->hash == hash) {
+               while (1) {
+                       if (cur == 0)
+                               /* top of list */
+                               break;
+                       if (name_hash_table[cur - 1]->hash != hash)
+                               /* previous element have different hash */
+                               break;
+                       /* previous element have the same hash */
+                       cur--;
+               }
+               res = name_hash_table[cur];
+       }
+
+find_exit:
+       return res;
+}
+
+static int update_is_instrument_lib_attr_nolock()
+{
+       uint32_t i;
+       struct map_t *map;
+
+       /* clear is_instrument fields */
+       for (i = 0; i < name_hash_table_el_count_buzy; i++)
+               name_hash_table[i]->is_instrument = 0;
+
+       /* set is_instrument fields */
+       for (i = 0; i < map_inst_count; i++) {
+               map = get_map_by_filename(map_inst_list[i]);
+               if (map) {
+                       PRINTMSG("set 1!!! = %s", map->filename);
+                       map->is_instrument = 1;
+               }
+       }
+
+       return 0;
+       print_list_sorted(name_hash_table);
+}
+
+static struct map_t *get_map_by_addr(void *addr)
+{
+       struct map_t *d = NULL;
+       struct map_t *res = NULL;
+       uint32_t left, right, cur;
+
+       if (addr_hash_table_el_count_buzy == 0)
+               goto find_exit;
+
+       if (addr < addr_hash_table[0]->addr)
+               goto find_exit;
+
+       if (addr > addr_hash_table[addr_hash_table_el_count_buzy - 1]->addr)
+               goto find_exit;
+
+       left = 0;
+       right = addr_hash_table_el_count_buzy - 1;
+       cur = 0;
+       while (left < right) {
+               cur = (left + right) >> 1;
+
+               d = (struct map_t *)addr_hash_table[cur];
+               if (addr < d->addr) {
+                       right = cur - 1;
+                       continue;
+               }
+               if (addr > d->endaddr) {
+                       left = cur + 1;
+                       continue;
+               }
+
+               /* success */
+               return (addr_hash_table[cur]);
+       }
+
+       if (left == right) {
+               d = (struct map_t *)addr_hash_table[left];
+               if ((d->addr <= addr) && (addr <= d->endaddr))
+                       res = addr_hash_table[cur];
+       }
+
+find_exit:
+       return res;
+}
+
+static void maps_reader_lock_all()
+{
+       int i;
+       for (i = 0; i < MAX_READERS_COUNT; i++)
+               sem_wait(&readers_mutex);
+}
+
+static void maps_reader_unlock_all()
+{
+       int i;
+       for (i = 0; i < MAX_READERS_COUNT; i++)
+               sem_post(&readers_mutex);
+}
+
+static inline void maps_reader_lock()
+{
+       sem_wait(&readers_mutex);       /* down semaphore */
+}
+
+static inline void maps_reader_unlock()
+{
+       sem_post(&readers_mutex);       /* up semaphore */
+}
+
+static inline void maps_writer_lock()
+{
+       pthread_mutex_lock(&maps_lock);
+}
+
+static inline void maps_writer_unlock()
+{
+       pthread_mutex_unlock(&maps_lock);
+}
+
+int set_map_inst_list(char **maps_set, uint32_t maps_count)
+{
+       int res = 0;
+       uint32_t i = 0;
+       char *p;
+
+       maps_writer_lock();
+       maps_reader_lock_all();
+
+       if (map_inst_list != NULL) {
+               free(map_inst_list);
+               map_inst_list = NULL;
+       }
+
+       if (map_inst_list_set != NULL) {
+               free(map_inst_list_set);
+               map_inst_list_set = NULL;
+       }
+
+       map_inst_list = real_malloc(sizeof(*map_inst_list) * maps_count);
+       if (maps_set != NULL && *maps_set != NULL)
+               map_inst_list_set = *maps_set + sizeof(maps_count);
+       map_inst_count = maps_count;
+
+       /* add library mapping names */
+       p = map_inst_list_set;
+       for (i = 0; i < maps_count; i++) {
+               map_inst_list[i] = p;
+               p += strlen(p) + 1;
+               PRINTMSG("-------> %s", map_inst_list[i]);
+       }
+
+       res = update_is_instrument_lib_attr_nolock();
+
+       if (maps_set != NULL)
+               *maps_set = NULL;
+
+       maps_reader_unlock_all();
+       maps_writer_unlock();
+
+       return res;
+}
+
+void maps_make()
+{
+       maps_writer_lock();
+       maps_reader_lock_all();
+       FILE *f = fopen("/proc/self/maps", "r");
+       struct map_t *map = NULL;
+
+       /* read to exists locations */
+       struct data_list_t *cur = get_first_el(&sections_list);
+       sections_list.count = 0;
+       while (cur != NULL) {
+               map = (struct map_t *)cur->data;
+               if (!read_mapping_line(f, map))
+                       break;
+               if (map->permissions[2] == 'x') {
+                       map->hash = calc_string_hash(map->filename);
+                       cur->hash = map->hash;
+                       sections_list.count++;
+                       cur = get_next_el(cur);
+               }
+       }
+
+       /* add  locations */
+       map = (*real_malloc)(sizeof(*map));
+       while (read_mapping_line(f, map)) {
+               if (map->permissions[2] == 'x') {
+                       map->hash = calc_string_hash(map->filename);
+                       add_to_map_list(&map);
+                       if (map == NULL)
+                               map = (*real_malloc)(sizeof(*map));
+               }
+       }
+
+       if (map != NULL)
+               free(map);
+
+       fclose(f);
+
+       create_addr_hash_table();
+       create_name_hash_table();
+
+       update_is_instrument_lib_attr_nolock();
+
+       maps_reader_unlock_all();
+       maps_writer_unlock();
+}
+
+int maps_print_maps_by_addr(const void *addr)
+{
+       int res = -1;
+       struct map_t *map = NULL;
+
+       maps_reader_lock();
+       map = get_map_by_addr((void *)addr);
+       if (map != NULL)
+               print_map(map);
+       maps_reader_unlock();
+
+       return res;
+}
+
+int maps_is_instrument_section_by_addr_no_remap(const void *addr)
+{
+       int res = -1;
+       struct map_t *map;
+
+       maps_reader_lock();
+       map = get_map_by_addr((void *)addr);
+       if (map != NULL)
+               res = map->is_instrument;
+       maps_reader_unlock();
+
+       return res;
+
+}
+
+/* interface function */
+int maps_is_instrument_section_by_addr(const void *addr)
+{
+       int ret = maps_is_instrument_section_by_addr_no_remap(addr);
+
+       if (ret == -1) {
+               PRINTMSG("========> hz addr %p. remap", addr);
+               maps_make();
+               if (maps_is_instrument_section_by_addr_no_remap(addr) == -1) {
+                       print_list();
+                       PRINTERR("!!!!unknown addr %p", addr);
+                       get_map_by_addr((void *)addr);
+                       sleep(2);
+                       exit(0);
+                       ret = 0;
+               }
+       }
+
+       return ret;
+}
+
+/* must be called ones */
+int maps_init()
+{
+       int res = 0;
+
+       probeBlockStart();
+       res = sem_init(&readers_mutex, 0, MAX_READERS_COUNT);
+       set_map_inst_list(NULL, 0);
+       probeBlockEnd();
+
+       return res;
+}
index 9bbc155..4090e62 100755 (executable)
@@ -58,6 +58,7 @@
 
 #include "binproto.h"
 #include "daforkexec.h"
+#include "damaps.h"
 
 #define APP_INSTALL_PATH               "/opt/apps"
 #define TISEN_APP_POSTFIX                      ".exe"
@@ -224,8 +225,10 @@ static void *recvThread(void __unused * data)
        fd_set readfds, workfds;
        int maxfd = 0, rc;
        uint64_t xtime;
+       uint32_t tmp;
        ssize_t recvlen;
        log_t log;
+       char *data_buf = NULL;
        sigset_t profsigmask;
 
        if(gTraceInfo.socket.daemonSock == -1)
@@ -277,19 +280,36 @@ static void *recvThread(void __unused * data)
 
                        if(recvlen > 0) // recv succeed
                        {
-                               if(log.length > 0)
-                               {
-                                       if(log.length >= DA_LOG_MAX)
-                                               log.length = DA_LOG_MAX - 1;
-                                       recvlen = recv(gTraceInfo.socket.daemonSock, log.data,
+
+                               if (log.type == MSG_MAPS_INST_LIST) {
+                                       if (data_buf)
+                                               free(data_buf);
+
+                                       data_buf = malloc(log.length);
+                                       if (data_buf == NULL) {
+                                               PRINTERR("cannot allocate buf to recv msg");
+                                               break;
+                                       }
+                                       recvlen = recv(gTraceInfo.socket.daemonSock, data_buf,
                                                log.length, MSG_WAITALL);
-                               }
-                               else
-                               {
-                                       log.length = 0;
-                               }
 
-                               log.data[log.length] = '\0';
+                               } else {
+
+                                       if(log.length > 0)
+                                       {
+                                               if(log.length >= DA_LOG_MAX)
+                                                       log.length = DA_LOG_MAX-1;
+
+                                               recvlen = recv(gTraceInfo.socket.daemonSock, log.data,
+                                                       log.length, MSG_WAITALL);
+                                       }
+                                       else
+                                       {
+                                               log.length = 0;
+                                       }
+
+                                       log.data[log.length] = '\0';
+                               }
 
                                if (log.type == MSG_CAPTURE_SCREEN) {
                                        captureScreen();
@@ -302,6 +322,13 @@ static void *recvThread(void __unused * data)
                                        application_exit();
                                        break;
                                }
+                               else if(log.type == MSG_MAPS_INST_LIST)
+                               {
+                                       tmp = *((uint32_t *)data_buf);
+                                       PRINTMSG("MSG_MAPS_INST_LIST <%u>", tmp);
+                                       set_map_inst_list(&data_buf, tmp);
+                                       continue;
+                               }
                                else
                                {
                                        PRINTERR("recv unknown message(%d)", log.type);
@@ -326,6 +353,10 @@ static void *recvThread(void __unused * data)
                }
        }
 
+       /* release buffer */
+       if (data_buf)
+               free(data_buf);
+
        probeBlockEnd();
        return NULL;
 }
@@ -383,8 +414,6 @@ void _init_(void)
 {
        char msg[DA_LOG_MAX];
 
-       rtdl_next_set_once(real_malloc, "malloc");
-
        probeBlockStart();
 
        init_exec_fork();
@@ -411,13 +440,25 @@ void _init_(void)
        PRINTMSG(msg);
 
        gTraceInfo.init_complete = 1;
+       maps_make();
        probeBlockEnd();
 
 }
 
 void __attribute__((constructor)) _init_probe()
 {
+
+       rtdl_next_set_once(real_malloc, "malloc");
+
+        /* init maps */
+       if (maps_init()!=0){
+               perror("cannot init readers semaphores\n");
+               exit(0);
+       };
+
+       /* init library */
        _init_();
+
        char msg[DA_LOG_MAX];
        sprintf(msg, "<-lib construnctor");
        PRINTMSG(msg);
@@ -728,7 +769,7 @@ int preBlockBegin(const void *caller, bool bFiltering, enum DaOptions option)
 
        probeBlockStart();
 
-       if (is_user_call(caller)) {
+       if (maps_is_instrument_section_by_addr(caller)) {
                probingStart();
                return 2; /* user call */
        } else {
diff --git a/include/damaps.h b/include/damaps.h
new file mode 100644 (file)
index 0000000..c6258fd
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  DA probe
+ *
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Cherepanov Vitaliy <v.cherepanov@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+extern int maps_init();
+extern void maps_make();
+extern int maps_is_instrument_section_by_addr(const void *addr);
+extern int set_map_inst_list(char **maps_set, uint32_t maps_count);
index 98d7111..258a8fa 100755 (executable)
@@ -181,7 +181,8 @@ enum MessageType
        MSG_WARNING = 12,
        MSG_STOP = 101,
        MSG_CONFIG = 103,
-       MSG_CAPTURE_SCREEN= 108
+       MSG_CAPTURE_SCREEN= 108,
+       MSG_MAPS_INST_LIST= 109
 };
 
 enum DaOptions