static int embKernel_update_threads(struct rtos *rtos) { /* int i = 0; */ int retval; const struct embKernel_params *param; if (rtos == NULL) return -1; if (rtos->rtos_specific_params == NULL) return -3; if (rtos->symbols == NULL) { LOG_ERROR("No symbols for embKernel"); return -4; } if (rtos->symbols[SYMBOL_ID_sCurrentTask].address == 0) { LOG_ERROR("Don't have the thread list head"); return -2; } /* wipe out previous thread details if any */ rtos_free_threadlist(rtos); param = (const struct embKernel_params *) rtos->rtos_specific_params; retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTask].address, param->pointer_width, (uint8_t *) &rtos->current_thread); if (retval != ERROR_OK) { LOG_ERROR("Error reading current thread in embKernel thread list"); return retval; } int64_t max_used_priority = 0; retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sMaxPriorities].address, param->pointer_width, (uint8_t *) &max_used_priority); if (retval != ERROR_OK) return retval; int thread_list_size = 0; retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTaskCount].address, param->thread_count_width, (uint8_t *) &thread_list_size); if (retval != ERROR_OK) { LOG_ERROR("Could not read embKernel thread count from target"); return retval; } /* create space for new thread details */ rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size); if (!rtos->thread_details) { LOG_ERROR("Error allocating memory for %d threads", thread_list_size); return ERROR_FAIL; } int threadIdx = 0; /* Look for ready tasks */ for (int pri = 0; pri < max_used_priority; pri++) { /* Get first item in queue */ int64_t iterable = 0; retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListReady].address + (pri * param->rtos_list_size), param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; for (; iterable && threadIdx < thread_list_size; threadIdx++) { /* Get info from this iterable item */ retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Ready"); if (retval != ERROR_OK) return retval; /* Get next iterable item */ retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; } } /* Look for sleeping tasks */ int64_t iterable = 0; retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSleep].address, param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; for (; iterable && threadIdx < thread_list_size; threadIdx++) { /*Get info from this iterable item */ retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Sleeping"); if (retval != ERROR_OK) return retval; /*Get next iterable item */ retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; } /* Look for suspended tasks */ iterable = 0; retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSuspended].address, param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; for (; iterable && threadIdx < thread_list_size; threadIdx++) { /* Get info from this iterable item */ retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Suspended"); if (retval != ERROR_OK) return retval; /*Get next iterable item */ retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width, (uint8_t *) &iterable); if (retval != ERROR_OK) return retval; } rtos->thread_count = 0; rtos->thread_count = threadIdx; LOG_OUTPUT("Found %u tasks\n", (unsigned int)threadIdx); return 0; }
static int hwthread_update_threads(struct rtos *rtos) { int threads_found = 0; int thread_list_size = 0; struct target_list *head; struct target *target; int64_t current_thread = 0; enum target_debug_reason current_reason = DBG_REASON_UNDEFINED; if (rtos == NULL) return -1; target = rtos->target; /* wipe out previous thread details if any */ rtos_free_threadlist(rtos); /* determine the number of "threads" */ if (target->smp) { for (head = target->head; head != NULL; head = head->next) { struct target *curr = head->target; if (!target_was_examined(curr)) continue; ++thread_list_size; } } else thread_list_size = 1; /* create space for new thread details */ rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size); if (target->smp) { /* loop over all threads */ for (head = target->head; head != NULL; head = head->next) { struct target *curr = head->target; if (!target_was_examined(curr)) continue; threadid_t tid = threadid_from_target(curr); hwthread_fill_thread(rtos, curr, threads_found); /* find an interesting thread to set as current */ switch (current_reason) { case DBG_REASON_UNDEFINED: current_reason = curr->debug_reason; current_thread = tid; break; case DBG_REASON_SINGLESTEP: /* single-step can only be overridden by itself */ if (curr->debug_reason == DBG_REASON_SINGLESTEP) { if (tid == rtos->current_threadid) current_thread = tid; } break; case DBG_REASON_BREAKPOINT: /* single-step overrides breakpoint */ if (curr->debug_reason == DBG_REASON_SINGLESTEP) { current_reason = curr->debug_reason; current_thread = tid; } else /* multiple breakpoints, prefer gdbs' threadid */ if (curr->debug_reason == DBG_REASON_BREAKPOINT) { if (tid == rtos->current_threadid) current_thread = tid; } break; case DBG_REASON_WATCHPOINT: /* breakpoint and single-step override watchpoint */ if (curr->debug_reason == DBG_REASON_SINGLESTEP || curr->debug_reason == DBG_REASON_BREAKPOINT) { current_reason = curr->debug_reason; current_thread = tid; } break; case DBG_REASON_DBGRQ: /* all other reasons override debug-request */ if (curr->debug_reason == DBG_REASON_SINGLESTEP || curr->debug_reason == DBG_REASON_WATCHPOINT || curr->debug_reason == DBG_REASON_BREAKPOINT) { current_reason = curr->debug_reason; current_thread = tid; } else if (curr->debug_reason == DBG_REASON_DBGRQ) { if (tid == rtos->current_threadid) current_thread = tid; } break; default: break; } threads_found++; } } else { hwthread_fill_thread(rtos, target, threads_found); current_thread = threadid_from_target(target); threads_found++; } rtos->thread_count = threads_found; /* we found an interesting thread, set it as current */ if (current_thread != 0) rtos->current_thread = current_thread; else if (rtos->current_threadid != 0) rtos->current_thread = rtos->current_threadid; else rtos->current_thread = threadid_from_target(target); LOG_DEBUG("%s current_thread=%i", __func__, (int)rtos->current_thread); return 0; }
static int uCOS_III_update_threads(struct rtos *rtos) { struct uCOS_III_params *params = rtos->rtos_specific_params; int retval; /* free previous thread details */ rtos_free_threadlist(rtos); /* verify RTOS is running */ uint8_t rtos_running; retval = target_read_u8(rtos->target, rtos->symbols[uCOS_III_VAL_OSRunning].address, &rtos_running); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read RTOS running"); return retval; } if (rtos_running != 1 && rtos_running != 0) { LOG_ERROR("uCOS-III: invalid RTOS running value"); return ERROR_FAIL; } if (!rtos_running) { rtos->thread_details = calloc(1, sizeof(struct thread_detail)); if (rtos->thread_details == NULL) { LOG_ERROR("uCOS-III: out of memory"); return ERROR_FAIL; } rtos->thread_count = 1; rtos->thread_details->threadid = 0; rtos->thread_details->exists = true; rtos->current_thread = 0; return ERROR_OK; } /* update thread offsets */ retval = uCOS_III_update_thread_offsets(rtos); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to update thread offsets"); return retval; } /* read current thread address */ symbol_address_t current_thread_address = 0; retval = target_read_memory(rtos->target, rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address, params->pointer_width, 1, (void *)¤t_thread_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read current thread address"); return retval; } /* read number of tasks */ retval = target_read_u16(rtos->target, rtos->symbols[uCOS_III_VAL_OSTaskQty].address, (void *)&rtos->thread_count); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread count"); return retval; } rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail)); if (rtos->thread_details == NULL) { LOG_ERROR("uCOS-III: out of memory"); return ERROR_FAIL; } /* * uC/OS-III adds tasks in LIFO order; advance to the end of the * list and work backwards to preserve the intended order. */ symbol_address_t thread_address = 0; retval = uCOS_III_find_last_thread_address(rtos, &thread_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to find last thread address"); return retval; } for (int i = 0; i < rtos->thread_count; i++) { struct thread_detail *thread_detail = &rtos->thread_details[i]; char thread_str_buffer[UCOS_III_MAX_STRLEN + 1]; /* find or create new threadid */ retval = uCOS_III_find_or_create_thread(rtos, thread_address, &thread_detail->threadid); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to find or create thread"); return retval; } if (thread_address == current_thread_address) rtos->current_thread = thread_detail->threadid; thread_detail->exists = true; /* read thread name */ symbol_address_t thread_name_address = 0; retval = target_read_memory(rtos->target, thread_address + params->thread_name_offset, params->pointer_width, 1, (void *)&thread_name_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to name address"); return retval; } retval = target_read_buffer(rtos->target, thread_name_address, sizeof(thread_str_buffer), (void *)thread_str_buffer); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread name"); return retval; } thread_str_buffer[sizeof(thread_str_buffer) - 1] = '\0'; thread_detail->thread_name_str = strdup(thread_str_buffer); /* read thread extra info */ uint8_t thread_state; uint8_t thread_priority; retval = target_read_u8(rtos->target, thread_address + params->thread_state_offset, &thread_state); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread state"); return retval; } retval = target_read_u8(rtos->target, thread_address + params->thread_priority_offset, &thread_priority); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread priority"); return retval; } const char *thread_state_str; if (thread_state < ARRAY_SIZE(uCOS_III_thread_state_list)) thread_state_str = uCOS_III_thread_state_list[thread_state]; else thread_state_str = "Unknown"; snprintf(thread_str_buffer, sizeof(thread_str_buffer), "State: %s, Priority: %d", thread_state_str, thread_priority); thread_detail->extra_info_str = strdup(thread_str_buffer); /* read previous thread address */ retval = target_read_memory(rtos->target, thread_address + params->thread_prev_offset, params->pointer_width, 1, (void *)&thread_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read previous thread address"); return retval; } } return ERROR_OK; }
/* * API function, update list of threads */ static int mqx_update_threads( struct rtos *rtos ) { uint32_t task_queue_addr = 0; uint32_t kernel_data_addr = 0; uint16_t task_queue_size = 0; uint32_t active_td_addr = 0; if (!rtos->rtos_specific_params) return -3; if (!rtos->symbols) return -4; /* clear old data */ rtos_free_threadlist(rtos); /* check scheduler */ if (ERROR_OK != mqx_is_scheduler_running(rtos)) return ERROR_FAIL; /* get kernel_data symbol */ if (ERROR_OK != mqx_get_symbol( rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr )) { return ERROR_FAIL; } /* read kernel_data */ if (ERROR_OK != mqx_get_member( rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr )) { return ERROR_FAIL; } /* get task queue address */ task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST; /* get task queue size */ if (ERROR_OK != mqx_get_member( rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2, "kernel_data->TD_LIST.SIZE", &task_queue_size )) { return ERROR_FAIL; } /* get active ptr */ if (ERROR_OK != mqx_get_member( rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4, "kernel_data->ACTIVE_PTR", (void *)&active_td_addr )) { return ERROR_FAIL; } /* setup threads info */ rtos->thread_count = task_queue_size; rtos->current_thread = 0; rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail)); if (NULL == rtos->thread_details) return ERROR_FAIL; /* loop over each task and setup thread details, the current_taskpool_addr is set to queue head NOTE: debugging functions task create/destroy might cause to show invalid data. */ for ( uint32_t i = 0, taskpool_addr = task_queue_addr; i < (uint32_t)rtos->thread_count; i++ ) { uint8_t task_name[MQX_THREAD_NAME_LENGTH + 1]; uint32_t task_addr = 0, task_template = 0, task_state = 0; uint32_t task_name_addr = 0, task_id = 0, task_errno = 0; uint32_t state_index = 0, state_max = 0; uint32_t extra_info_length = 0; char *state_name = "unknown state"; /* set current taskpool address */ if (ERROR_OK != mqx_get_member( rtos, taskpool_addr, MQX_TASK_OFFSET_NEXT, 4, "td_struct_ptr->NEXT", &taskpool_addr )) { return ERROR_FAIL; } /* get task address from taskpool */ task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST; /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */ if (ERROR_OK != mqx_get_member( rtos, task_addr, MQX_TASK_OFFSET_TEMPLATE, 4, "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template )) { return ERROR_FAIL; } /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */ if (ERROR_OK != mqx_get_member( rtos, task_template, MQX_TASK_TEMPLATE_OFFSET_NAME, 4, "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr )) { return ERROR_FAIL; } /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */ if (ERROR_OK != mqx_get_member( rtos, task_name_addr, 0, MQX_THREAD_NAME_LENGTH, "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name )) { return ERROR_FAIL; } /* always terminate last character by force, otherwise openocd might fail if task_name has corrupted data */ task_name[MQX_THREAD_NAME_LENGTH] = '\0'; /* get value of 'td_struct_ptr->TASK_ID' */ if (ERROR_OK != mqx_get_member( rtos, task_addr, MQX_TASK_OFFSET_ID, 4, "td_struct_ptr->TASK_ID", &task_id )) { return ERROR_FAIL; } /* get task errno */ if (ERROR_OK != mqx_get_member( rtos, task_addr, MQX_TASK_OFFSET_ERROR_CODE, 4, "td_struct_ptr->TASK_ERROR_CODE", &task_errno )) { return ERROR_FAIL; } /* get value of 'td_struct_ptr->STATE' */ if (ERROR_OK != mqx_get_member( rtos, task_addr, MQX_TASK_OFFSET_STATE, 4, "td_struct_ptr->STATE", &task_state )) { return ERROR_FAIL; } task_state &= MQX_TASK_STATE_MASK; /* and search for defined state */ state_max = (sizeof(mqx_states)/sizeof(struct mqx_state)); for (state_index = 0; (state_index < state_max); state_index++) { if (mqx_states[state_index].state == task_state) { state_name = mqx_states[state_index].name; break; } } /* setup thread details struct */ rtos->thread_details[i].threadid = task_id; rtos->thread_details[i].exists = true; rtos->thread_details[i].display_str = NULL; /* set thread name */ rtos->thread_details[i].thread_name_str = malloc(strlen((void *)task_name) + 1); if (NULL == rtos->thread_details[i].thread_name_str) return ERROR_FAIL; strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name); /* set thread extra info * - task state * - task address * - task errno * calculate length as: * state length + address length + errno length + formatter length */ extra_info_length += strlen((void *)state_name) + 8 + 8 + 8; rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1); if (NULL == rtos->thread_details[i].extra_info_str) return ERROR_FAIL; snprintf( rtos->thread_details[i].extra_info_str, extra_info_length, "%s : 0x%"PRIx32 " : %" PRIu32, state_name, task_addr, task_errno ); /* set active thread */ if (active_td_addr == task_addr) rtos->current_thread = task_id; } return ERROR_OK; }