jimtcl: restrict memory leak workaround on Linux only
[fw/openocd] / src / rtos / linux.c
index 3b2a2b0c34b440fb72effcc1ab450213820dd434..4b96a931dafaa78c0b9133b09885b8ecf10253aa 100644 (file)
@@ -92,7 +92,7 @@ struct cpu_context {
        uint32_t PC;
        uint32_t preempt_count;
 };
-struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
+static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
                                     uint32_t *info_addr);
 static int insert_into_threadlist(struct target *target, struct threads *t);
 
@@ -144,17 +144,7 @@ static int linux_read_memory(struct target *target,
        return ERROR_OK;
 }
 
-static char *reg_converter(char *buffer, void *reg, int size)
-{
-       int i;
-
-       for (i = 0; i < size; i++)
-               buffer += sprintf(buffer, "%02x", ((uint8_t *) reg)[i]);
-
-       return buffer;
-}
-
-int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer)
+static int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer)
 {
 
        if ((addr & 0xfffffffc) != addr)
@@ -165,7 +155,7 @@ int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer)
 
 }
 
-uint32_t get_buffer(struct target *target, const uint8_t *buffer)
+static uint32_t get_buffer(struct target *target, const uint8_t *buffer)
 {
        uint32_t value = 0;
        const uint8_t *value_ptr = buffer;
@@ -174,15 +164,13 @@ uint32_t get_buffer(struct target *target, const uint8_t *buffer)
 }
 
 static int linux_os_thread_reg_list(struct rtos *rtos,
-       int64_t thread_id, char **hex_reg_list)
+       int64_t thread_id, struct rtos_reg **reg_list, int *num_regs)
 {
        struct target *target = rtos->target;
        struct linux_os *linux_os = (struct linux_os *)
                target->rtos->rtos_specific_params;
-       int i = 0;
        struct current_thread *tmp = linux_os->current_threads;
        struct current_thread *next;
-       char *hex_string;
        int found = 0;
        int retval;
        /*  check if a current thread is requested  */
@@ -195,117 +183,52 @@ static int linux_os_thread_reg_list(struct rtos *rtos,
                        next = next->next;
        } while ((found == 0) && (next != tmp) && (next != NULL));
 
-       if (found == 1) {
-               /*  search target to perfom the access  */
-               struct reg **reg_list;
-               int reg_list_size, reg_packet_size = 0;
-               struct target_list *head;
-               head = target->head;
-               found = 0;
-               do {
-                       if (head->target->coreid == next->core_id) {
-
-                               target = head->target;
-                               found = 1;
-                       } else
-                               head = head->next;
-
-               } while ((head != (struct target_list *)NULL) && (found == 0));
-
-               if (found == 0) {
-                       LOG_ERROR
-                       (
-                               "current thread %" PRIx64 ": no target to perform access of core id %" PRIx32,
-                               thread_id,
-                               next->core_id);
-                       return ERROR_FAIL;
-               }
-
-               /*LOG_INFO("thread %lx current on core %x",thread_id,
-                * target->coreid);*/
-               retval =
-                       target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
-                                       REG_CLASS_GENERAL);
-
-               if (retval != ERROR_OK)
-                       return retval;
-
-               for (i = 0; i < reg_list_size; i++)
-                       reg_packet_size += reg_list[i]->size;
-
-               assert(reg_packet_size > 0);
+       if (found == 0) {
+               LOG_ERROR("could not find thread: %" PRIx64, thread_id);
+               return ERROR_FAIL;
+       }
 
-               *hex_reg_list = malloc(DIV_ROUND_UP(reg_packet_size, 8) * 2);
+       /*  search target to perform the access  */
+       struct reg **gdb_reg_list;
+       struct target_list *head;
+       head = target->head;
+       found = 0;
+       do {
+               if (head->target->coreid == next->core_id) {
 
-               hex_string = *hex_reg_list;
+                       target = head->target;
+                       found = 1;
+               } else
+                       head = head->next;
 
-               for (i = 0; i < reg_list_size; i++) {
-                       if (!reg_list[i]->valid)
-                               reg_list[i]->type->get(reg_list[i]);
+       } while ((head != (struct target_list *)NULL) && (found == 0));
 
-                       hex_string = reg_converter(hex_string,
-                                       reg_list[i]->value,
-                                       (reg_list[i]->size) / 8);
-               }
+       if (found == 0) {
+               LOG_ERROR
+               (
+                       "current thread %" PRIx64 ": no target to perform access of core id %" PRIx32,
+                       thread_id,
+                       next->core_id);
+               return ERROR_FAIL;
+       }
 
-               free(reg_list);
+       /*LOG_INFO("thread %lx current on core %x",thread_id, target->coreid);*/
+       retval = target_get_gdb_reg_list(target, &gdb_reg_list, num_regs, REG_CLASS_GENERAL);
+       if (retval != ERROR_OK)
+               return retval;
 
-       } else {
-               struct threads *temp = linux_os->thread_list;
-               *hex_reg_list = calloc(1, 500 * sizeof(char));
-               hex_string = *hex_reg_list;
+       *reg_list = calloc(*num_regs, sizeof(struct rtos_reg));
 
-               for (i = 0; i < 16; i++)
-                       hex_string += sprintf(hex_string, "%02x", 0);
+       for (int i = 0; i < *num_regs; ++i) {
+               if (!gdb_reg_list[i]->valid)
+                       gdb_reg_list[i]->type->get(gdb_reg_list[i]);
 
-               while ((temp != NULL) &&
-                               (temp->threadid != target->rtos->current_threadid))
-                       temp = temp->next;
+               (*reg_list)[i].number = gdb_reg_list[i]->number;
+               (*reg_list)[i].size = gdb_reg_list[i]->size;
 
-               if (temp != NULL) {
-                       if (temp->context == NULL)
-                               temp->context = cpu_context_read(target,
-                                               temp->
-                                               base_addr,
-                                               &temp->
-                                               thread_info_addr);
-
-                       hex_string =
-                               reg_converter(hex_string, &temp->context->R4, 4);
-                       hex_string =
-                               reg_converter(hex_string, &temp->context->R5, 4);
-                       hex_string =
-                               reg_converter(hex_string, &temp->context->R6, 4);
-                       hex_string =
-                               reg_converter(hex_string, &temp->context->R7, 4);
-                       hex_string =
-                               reg_converter(hex_string, &temp->context->R8, 4);
-                       hex_string =
-                               reg_converter(hex_string, &temp->context->R9, 4);
-
-                       for (i = 0; i < 4; i++) /*R10 = 0x0 */
-                               hex_string += sprintf(hex_string, "%02x", 0);
-
-                       hex_string =
-                               reg_converter(hex_string, &temp->context->FP, 4);
-                       hex_string =
-                               reg_converter(hex_string, &temp->context->IP, 4);
-                       hex_string =
-                               reg_converter(hex_string, &temp->context->SP, 4);
-
-                       for (i = 0; i < 4; i++)
-                               hex_string += sprintf(hex_string, "%02x", 0);
-
-                       hex_string =
-                               reg_converter(hex_string, &temp->context->PC, 4);
-
-                       for (i = 0; i < 100; i++)       /*100 */
-                               hex_string += sprintf(hex_string, "%02x", 0);
-
-                       uint32_t cpsr = 0x00000000;
-                       reg_converter(hex_string, &cpsr, 4);
-               }
+               buf_cpy(gdb_reg_list[i]->value, (*reg_list)[i].value, (*reg_list)[i].size);
        }
+
        return ERROR_OK;
 }
 
@@ -323,11 +246,11 @@ static const char * const linux_symbol_list[] = {
        NULL
 };
 
-static int linux_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int linux_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
 {
        unsigned int i;
-       *symbol_list = (symbol_table_elem_t *)
-               calloc(ARRAY_SIZE(linux_symbol_list), sizeof(symbol_table_elem_t));
+       *symbol_list = (struct symbol_table_elem *)
+               calloc(ARRAY_SIZE(linux_symbol_list), sizeof(struct symbol_table_elem));
 
        for (i = 0; i < ARRAY_SIZE(linux_symbol_list); i++)
                (*symbol_list)[i].symbol_name = linux_symbol_list[i];
@@ -370,7 +293,7 @@ int fill_task_pid(struct target *target, struct threads *t)
 }
 #endif
 
-int fill_task(struct target *target, struct threads *t)
+static int fill_task(struct target *target, struct threads *t)
 {
        int retval;
        uint32_t pid_addr = t->base_addr + PID;
@@ -426,7 +349,7 @@ int fill_task(struct target *target, struct threads *t)
        return retval;
 }
 
-int get_name(struct target *target, struct threads *t)
+static int get_name(struct target *target, struct threads *t)
 {
        int retval;
        uint32_t full_name[4];
@@ -472,7 +395,7 @@ int get_name(struct target *target, struct threads *t)
 
 }
 
-int get_current(struct target *target, int create)
+static int get_current(struct target *target, int create)
 {
        struct target_list *head;
        head = target->head;
@@ -560,7 +483,7 @@ int get_current(struct target *target, int create)
        return ERROR_OK;
 }
 
-struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
+static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
        uint32_t *thread_info_addr_old)
 {
        struct cpu_context *context = calloc(1, sizeof(struct cpu_context));
@@ -656,7 +579,7 @@ retry:
        return context;
 }
 
-uint32_t next_task(struct target *target, struct threads *t)
+static uint32_t next_task(struct target *target, struct threads *t)
 {
        uint8_t *buffer = calloc(1, 4);
        uint32_t next_addr = t->base_addr + NEXT;
@@ -675,7 +598,7 @@ uint32_t next_task(struct target *target, struct threads *t)
        return 0;
 }
 
-struct current_thread *add_current_thread(struct current_thread *currents,
+static struct current_thread *add_current_thread(struct current_thread *currents,
        struct current_thread *ct)
 {
        ct->next = NULL;
@@ -694,25 +617,24 @@ struct current_thread *add_current_thread(struct current_thread *currents,
        }
 }
 
-struct threads *liste_del_task(struct threads *task_list, struct threads **t,
+static struct threads *liste_del_task(struct threads *task_list, struct threads **t,
        struct threads *prev)
 {
        LOG_INFO("del task %" PRId64, (*t)->threadid);
-       prev->next = (*t)->next;
-
-       if (prev == task_list)
-               task_list = prev;
+       if (prev)
+               prev->next = (*t)->next;
+       else
+               task_list = (*t)->next;
 
        /*  free content of threads */
-       if ((*t)->context)
-               free((*t)->context);
+       free((*t)->context);
 
        free(*t);
-       *t = prev;
+       *t = prev ? prev : task_list;
        return task_list;
 }
 
-struct threads *liste_add_task(struct threads *task_list, struct threads *t,
+static struct threads *liste_add_task(struct threads *task_list, struct threads *t,
        struct threads **last)
 {
        t->next = NULL;
@@ -761,7 +683,7 @@ static int current_base_addr(struct linux_os *linux_os, uint32_t base_addr)
        return 0;
 }
 
-int linux_get_tasks(struct target *target, int context)
+static int linux_get_tasks(struct target *target, int context)
 {
        int loop = 0;
        int retval = 0;
@@ -802,6 +724,7 @@ int linux_get_tasks(struct target *target, int context)
 
                /*  check that this thread is not one the current threads already
                 *  created */
+               uint32_t base_addr;
 #ifdef PID_CHECK
 
                if (!current_pid(linux_os, t->pid)) {
@@ -822,12 +745,13 @@ int linux_get_tasks(struct target *target, int context)
                                t->context =
                                        cpu_context_read(target, t->base_addr,
                                                &t->thread_info_addr);
+                       base_addr = next_task(target, t);
                } else {
                        /*LOG_INFO("thread %s is a current thread already created",t->name); */
+                       base_addr = next_task(target, t);
                        free(t);
                }
 
-               uint32_t base_addr = next_task(target, t);
                t = calloc(1, sizeof(struct threads));
                t->base_addr = base_addr;
        }
@@ -856,8 +780,7 @@ static int clean_threadlist(struct target *target)
        while (temp != NULL) {
                old = temp;
 
-               if (temp->context)
-                       free(temp->context);
+               free(temp->context);
 
                temp = temp->next;
                free(old);
@@ -1006,10 +929,8 @@ static int linux_task_update(struct target *target, int context)
        while (thread_list != NULL) {
                thread_list->status = 0;        /*setting all tasks to dead state*/
 
-               if (thread_list->context) {
-                       free(thread_list->context);
-                       thread_list->context = NULL;
-               }
+               free(thread_list->context);
+               thread_list->context = NULL;
 
                thread_list = thread_list->next;
        }
@@ -1070,10 +991,8 @@ static int linux_task_update(struct target *target, int context)
                                        if (context)
                                                thread_list->context =
                                                        cpu_context_read(target,
-                                                               thread_list->
-                                                               base_addr,
-                                                               &thread_list->
-                                                               thread_info_addr);
+                                                               thread_list->base_addr,
+                                                               &thread_list->thread_info_addr);
                                } else {
                                        /*  it is a current thread no need to read context */
                                }
@@ -1114,7 +1033,7 @@ static int linux_task_update(struct target *target, int context)
        return ERROR_OK;
 }
 
-int linux_gdb_thread_packet(struct target *target,
+static int linux_gdb_thread_packet(struct target *target,
        struct connection *connection, char const *packet,
        int packet_size)
 {
@@ -1134,7 +1053,7 @@ int linux_gdb_thread_packet(struct target *target,
        if (retval != ERROR_OK)
                return ERROR_TARGET_FAILURE;
 
-       char *out_str = calloc(1, 350 * sizeof(int64_t));
+       char *out_str = calloc(MAX_THREADS * 17 + 10, 1);
        char *tmp_str = out_str;
        tmp_str += sprintf(tmp_str, "m");
        struct threads *temp = linux_os->thread_list;
@@ -1151,7 +1070,7 @@ int linux_gdb_thread_packet(struct target *target,
        return ERROR_OK;
 }
 
-int linux_gdb_thread_update(struct target *target,
+static int linux_gdb_thread_update(struct target *target,
        struct connection *connection, char const *packet,
        int packet_size)
 {
@@ -1171,7 +1090,7 @@ int linux_gdb_thread_update(struct target *target,
 
        if (found == 1) {
                /*LOG_INFO("INTO GDB THREAD UPDATE FOUNDING START TASK");*/
-               char *out_strr = calloc(1, 350 * sizeof(int64_t));
+               char *out_strr = calloc(MAX_THREADS * 17 + 10, 1);
                char *tmp_strr = out_strr;
                tmp_strr += sprintf(tmp_strr, "m");
                /*LOG_INFO("CHAR MALLOC & M DONE");*/
@@ -1198,7 +1117,7 @@ int linux_gdb_thread_update(struct target *target,
        return ERROR_OK;
 }
 
-int linux_thread_extra_info(struct target *target,
+static int linux_thread_extra_info(struct target *target,
        struct connection *connection, char const *packet,
        int packet_size)
 {
@@ -1244,7 +1163,7 @@ int linux_thread_extra_info(struct target *target,
        return ERROR_OK;
 }
 
-int linux_gdb_T_packet(struct connection *connection,
+static int linux_gdb_T_packet(struct connection *connection,
        struct target *target, char const *packet, int packet_size)
 {
        int64_t threadid;
@@ -1255,7 +1174,7 @@ int linux_gdb_T_packet(struct connection *connection,
 
        if (linux_os->threads_needs_update == 0) {
                struct threads *temp = linux_os->thread_list;
-               struct threads *prev = linux_os->thread_list;
+               struct threads *prev = NULL;
 
                while (temp != NULL) {
                        if (temp->threadid == threadid) {
@@ -1265,9 +1184,8 @@ int linux_gdb_T_packet(struct connection *connection,
                                } else {
                                        /* delete item in the list   */
                                        linux_os->thread_list =
-                                               liste_del_task(linux_os->
-                                                       thread_list, &temp,
-                                                       prev);
+                                               liste_del_task(linux_os->thread_list,
+                                                       &temp, prev);
                                        linux_os->thread_count--;
                                        gdb_put_packet(connection, "E01", 3);
                                        return ERROR_OK;
@@ -1305,7 +1223,7 @@ int linux_gdb_T_packet(struct connection *connection,
        return retval;
 }
 
-int linux_gdb_h_packet(struct connection *connection,
+static int linux_gdb_h_packet(struct connection *connection,
        struct target *target, char const *packet, int packet_size)
 {
        struct linux_os *linux_os = (struct linux_os *)
@@ -1398,9 +1316,7 @@ static int linux_thread_packet(struct connection *connection, char const *packet
                        if (strncmp(packet, "qSymbol", 7) == 0) {
                                if (rtos_qsymbol(connection, packet, packet_size) == 1) {
                                        linux_compute_virt2phys(target,
-                                                       target->rtos->
-                                                       symbols[INIT_TASK].
-                                                       address);
+                                                       target->rtos->symbols[INIT_TASK].address);
                                }
 
                                break;
@@ -1451,11 +1367,10 @@ static int linux_thread_packet(struct connection *connection, char const *packet
                                }
 
                                if ((ct != NULL) && (ct->threadid !=
-                                                target->rtos->
-                                                current_threadid)
+                                                target->rtos->current_threadid)
                                && (target->rtos->current_threadid != -1))
-                                       LOG_WARNING("WARNING! current GDB thread do not match" \
-                                                       "current thread running." \
+                                       LOG_WARNING("WARNING! current GDB thread do not match "
+                                                       "current thread running. "
                                                        "Switch thread in GDB to threadid %d",
                                                        (int)ct->threadid);
 
@@ -1485,8 +1400,7 @@ static int linux_os_smp_init(struct target *target)
        while (head != (struct target_list *)NULL) {
                if (head->target->rtos != rtos) {
                        struct linux_os *smp_os_linux =
-                               (struct linux_os *)head->target->rtos->
-                               rtos_specific_params;
+                               (struct linux_os *)head->target->rtos->rtos_specific_params;
                        /*  remap smp target on rtos  */
                        free(head->target->rtos);
                        head->target->rtos = rtos;
@@ -1569,13 +1483,13 @@ static char *linux_ps_command(struct target *target)
                                if (temp->context)
                                        tmp +=
                                                sprintf(tmp,
-                                                       "%" PRId32 "\t\t%" PRId32 "\t\t%" PRIx32 "\t\t%s\n",
+                                                       "%" PRIu32 "\t\t%" PRIu32 "\t\t%" PRIx32 "\t\t%s\n",
                                                        temp->pid, temp->oncpu,
                                                        temp->asid, temp->name);
                                else
                                        tmp +=
                                                sprintf(tmp,
-                                                       "%" PRId32 "\t\t%" PRId32 "\t\t%" PRIx32 "\t\t%s\n",
+                                                       "%" PRIu32 "\t\t%" PRIu32 "\t\t%" PRIx32 "\t\t%s\n",
                                                        temp->pid, temp->oncpu,
                                                        temp->asid, temp->name);
                        }