static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); struct target *curr = NULL; int64_t current_threadid; if (packet[0] == 'H' && packet[1] == 'g') { sscanf(packet, "Hg%16" SCNx64, ¤t_threadid); if (current_threadid > 0) { if (hwthread_target_for_threadid(connection, current_threadid, &curr) != ERROR_OK) { LOG_ERROR("hwthread: cannot find thread id %"PRId64, current_threadid); gdb_put_packet(connection, "E01", 3); return ERROR_FAIL; } target->rtos->current_thread = current_threadid; } else if (current_threadid == 0 || current_threadid == -1) target->rtos->current_thread = threadid_from_target(target); target->rtos->current_threadid = current_threadid; gdb_put_packet(connection, "OK", 2); return ERROR_OK; } return rtos_thread_packet(connection, packet, packet_size); }
int linux_gdb_T_packet(struct connection *connection, struct target *target, char *packet, int packet_size) { int64_t threadid; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; int retval = ERROR_OK; sscanf(packet, "T%" SCNx64, &threadid); if (linux_os->threads_needs_update == 0) { struct threads *temp = linux_os->thread_list; struct threads *prev = linux_os->thread_list; while (temp != NULL) { if (temp->threadid == threadid) { if (temp->status != 0) { gdb_put_packet(connection, "OK", 2); return ERROR_OK; } else { /* delete item in the list */ linux_os->thread_list = liste_del_task(linux_os-> thread_list, &temp, prev); linux_os->thread_count--; gdb_put_packet(connection, "E01", 3); return ERROR_OK; } } /* for deletion */ prev = temp; temp = temp->next; } LOG_INFO("gdb requested status on non existing thread"); gdb_put_packet(connection, "E01", 3); return ERROR_OK; } else { retval = linux_task_update(target, 1); struct threads *temp = linux_os->thread_list; while (temp != NULL) { if (temp->threadid == threadid) { if (temp->status == 1) { gdb_put_packet(connection, "OK", 2); return ERROR_OK; } else { gdb_put_packet(connection, "E01", 3); return ERROR_OK; } } temp = temp->next; } } return retval; }
int rtos_get_gdb_reg_list(struct connection *connection) { struct target *target = get_target_from_connection(connection); int64_t current_threadid = target->rtos->current_threadid; if ((target->rtos != NULL) && (current_threadid != -1) && (current_threadid != 0) && ((current_threadid != target->rtos->current_thread) || (target->smp))) { /* in smp several current thread are possible */ char *hex_reg_list; LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64 ", target->rtos->current_thread=0x%" PRIx64 "\r\n", current_threadid, target->rtos->current_thread); target->rtos->type->get_thread_reg_list(target->rtos, current_threadid, &hex_reg_list); if (hex_reg_list != NULL) { gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list)); free(hex_reg_list); return ERROR_OK; } } return ERROR_FAIL; }
/* packet j :smp status request */ int gdb_read_smp_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); uint32_t len = sizeof(int32_t); uint8_t *buffer; char *hex_buffer; int retval = ERROR_OK; if (target->smp) { if (strstr(packet, "jc")) { hex_buffer = malloc(len * 2 + 1); buffer = (uint8_t *)&target->gdb_service->core[0]; uint32_t i; for (i = 0; i < 4; i++) { uint8_t t = buffer[i]; hex_buffer[2 * i] = DIGITS[(t >> 4) & 0xf]; hex_buffer[2 * i + 1] = DIGITS[t & 0xf]; } retval = gdb_put_packet(connection, hex_buffer, len * 2); free(hex_buffer); } }
int linux_gdb_thread_update(struct target *target, struct connection *connection, char *packet, int packet_size) { int found = 0; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct threads *temp = linux_os->thread_list; while (temp != NULL) { if (temp->threadid == linux_os->preupdtate_threadid_count + 1) { /*LOG_INFO("FOUND");*/ found = 1; break; } else temp = temp->next; } if (found == 1) { /*LOG_INFO("INTO GDB THREAD UPDATE FOUNDING START TASK");*/ char *out_strr = (char *)calloc(1, 350 * sizeof(int64_t)); char *tmp_strr = out_strr; tmp_strr += sprintf(tmp_strr, "m"); /*LOG_INFO("CHAR MALLOC & M DONE");*/ tmp_strr += sprintf(tmp_strr, "%016" PRIx64, temp->threadid); temp = temp->next; while (temp != NULL) { /*LOG_INFO("INTO GDB THREAD UPDATE WHILE");*/ tmp_strr += sprintf(tmp_strr, ","); tmp_strr += sprintf(tmp_strr, "%016" PRIx64, temp->threadid); temp = temp->next; } /*tmp_str[0] = 0;*/ gdb_put_packet(connection, out_strr, strlen(out_strr)); linux_os->preupdtate_threadid_count = linux_os->threadid_count - 1; free(out_strr); } else gdb_put_packet(connection, "l", 1); return ERROR_OK; }
/* packet j :smp status request */ int gdb_read_smp_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); int retval = ERROR_OK; if (target->smp) { if (strncmp(packet, "jc", 2) == 0) { const uint32_t len = sizeof(target->gdb_service->core[0]); char hex_buffer[len * 2 + 1]; char buffer[len]; buf_set_u32(buffer, 0, len * 8, target->gdb_service->core[0]); int pkt_len = hexify(hex_buffer, buffer, sizeof(buffer), sizeof(hex_buffer)); retval = gdb_put_packet(connection, hex_buffer, pkt_len); } } else retval = gdb_put_packet(connection, "E01", 3); return retval; }
/* J : smp set request */ int gdb_write_smp_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *separator; int coreid = 0; int retval = ERROR_OK; /* skip command character */ if (target->smp) { if (strncmp(packet, "Jc", 2) == 0) { packet += 2; coreid = strtoul(packet, &separator, 16); target->gdb_service->core[1] = coreid; retval = gdb_put_packet(connection, "OK", 2); } } else retval = gdb_put_packet(connection, "E01", 3); return retval; }
/* packet j :smp status request */ int gdb_read_smp_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); uint32_t len = sizeof(int32_t); uint8_t *buffer; char *hex_buffer; int retval = ERROR_OK; if (target->smp) { if (strncmp(packet, "jc", 2) == 0) { hex_buffer = malloc(len * 2 + 1); buffer = (uint8_t *)&target->gdb_service->core[0]; int pkt_len = hexify(hex_buffer, (char *)buffer, len, len * 2 + 1); retval = gdb_put_packet(connection, hex_buffer, pkt_len); free(hex_buffer); } } else retval = gdb_put_packet(connection, "E01", 3); return retval; }
int linux_thread_extra_info(struct target *target, struct connection *connection, char *packet, int packet_size) { int64_t threadid = 0; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid); /*LOG_INFO("lookup extra info for thread %" SCNx64, threadid);*/ struct threads *temp = linux_os->thread_list; while (temp != NULL) { if (temp->threadid == threadid) { char *pid = " PID: "; char *pid_current = "*PID: "; char *name = "NAME: "; int str_size = strlen(pid) + strlen(name); char *tmp_str = (char *)calloc(1, str_size + 50); char *tmp_str_ptr = tmp_str; /* discriminate cuurent task */ if (temp->status == 3) tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid_current); else tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid); tmp_str_ptr += sprintf(tmp_str_ptr, "%d", (int)temp->pid); tmp_str_ptr += sprintf(tmp_str_ptr, "%s", " | "); sprintf(tmp_str_ptr, "%s", name); sprintf(tmp_str_ptr, "%s", temp->name); char *hex_str = (char *)calloc(1, strlen(tmp_str) * 2 + 1); str_to_hex(hex_str, tmp_str); gdb_put_packet(connection, hex_str, strlen(hex_str)); free(hex_str); free(tmp_str); return ERROR_OK; } temp = temp->next; } LOG_INFO("thread not found"); return ERROR_OK; }
int rtos_get_gdb_reg_list(struct connection *connection, struct reg **reg_list[], int *reg_list_size) { struct target *target = get_target_from_connection(connection); if ( ( target->rtos != NULL ) && ( current_threadid != -1 ) && ( current_threadid != 0 ) && ( current_threadid != target->rtos->current_thread ) ) { char * hex_reg_list; target->rtos->type->get_thread_reg_list( target->rtos, current_threadid, &hex_reg_list ); if ( hex_reg_list != NULL ) { gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list)); free(hex_reg_list); return ERROR_OK; } } return ERROR_FAIL; }
int rtos_thread_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) { if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) && (target->rtos->thread_count != 0)) { threadid_t threadid = 0; int found = -1; sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid); if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) { int thread_num; for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) { if (target->rtos->thread_details[thread_num].threadid == threadid) { if (target->rtos->thread_details[thread_num].exists) found = thread_num; } } } if (found == -1) { gdb_put_packet(connection, "E01", 3); /* thread not found */ return ERROR_OK; } struct thread_detail *detail = &target->rtos->thread_details[found]; int str_size = 0; if (detail->display_str != NULL) str_size += strlen(detail->display_str); if (detail->thread_name_str != NULL) str_size += strlen(detail->thread_name_str); if (detail->extra_info_str != NULL) str_size += strlen(detail->extra_info_str); char *tmp_str = calloc(str_size + 7, sizeof(char)); char *tmp_str_ptr = tmp_str; if (detail->display_str != NULL) tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->display_str); if (detail->thread_name_str != NULL) { if (tmp_str_ptr != tmp_str) tmp_str_ptr += sprintf(tmp_str_ptr, " : "); tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->thread_name_str); } if (detail->extra_info_str != NULL) { if (tmp_str_ptr != tmp_str) tmp_str_ptr += sprintf(tmp_str_ptr, " : "); tmp_str_ptr += sprintf(tmp_str_ptr, " : %s", detail->extra_info_str); } assert(strlen(tmp_str) == (size_t) (tmp_str_ptr - tmp_str)); char *hex_str = malloc(strlen(tmp_str) * 2 + 1); int pkt_len = hexify(hex_str, tmp_str, 0, strlen(tmp_str) * 2 + 1); gdb_put_packet(connection, hex_str, pkt_len); free(hex_str); free(tmp_str); return ERROR_OK; } gdb_put_packet(connection, "", 0); return ERROR_OK; } else if (strncmp(packet, "qSymbol", 7) == 0) { if (rtos_qsymbol(connection, packet, packet_size) == 1) { target->rtos_auto_detect = false; target->rtos->type->create(target); target->rtos->type->update_threads(target->rtos); } return ERROR_OK; } else if (strncmp(packet, "qfThreadInfo", 12) == 0) { int i; if (target->rtos != NULL) { if (target->rtos->thread_count == 0) { gdb_put_packet(connection, "l", 1); } else { /*thread id are 16 char +1 for ',' */ char *out_str = malloc(17 * target->rtos->thread_count + 1); char *tmp_str = out_str; for (i = 0; i < target->rtos->thread_count; i++) { tmp_str += sprintf(tmp_str, "%c%016" PRIx64, i == 0 ? 'm' : ',', target->rtos->thread_details[i].threadid); } gdb_put_packet(connection, out_str, strlen(out_str)); free(out_str); } } else gdb_put_packet(connection, "l", 1); return ERROR_OK; } else if (strncmp(packet, "qsThreadInfo", 12) == 0) { gdb_put_packet(connection, "l", 1); return ERROR_OK; } else if (strncmp(packet, "qAttached", 9) == 0) { gdb_put_packet(connection, "1", 1); return ERROR_OK; } else if (strncmp(packet, "qOffsets", 8) == 0) { char offsets[] = "Text=0;Data=0;Bss=0"; gdb_put_packet(connection, offsets, sizeof(offsets)-1); return ERROR_OK; } else if (strncmp(packet, "qCRC:", 5) == 0) { /* make sure we check this before "qC" packet below * otherwise it gets incorrectly handled */ return GDB_THREAD_PACKET_NOT_CONSUMED; } else if (strncmp(packet, "qC", 2) == 0) { if (target->rtos != NULL) { char buffer[19]; int size; size = snprintf(buffer, 19, "QC%016" PRIx64, target->rtos->current_thread); gdb_put_packet(connection, buffer, size); } else gdb_put_packet(connection, "QC0", 3); return ERROR_OK; } else if (packet[0] == 'T') { /* Is thread alive? */ threadid_t threadid; int found = -1; sscanf(packet, "T%" SCNx64, &threadid); if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) { int thread_num; for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) { if (target->rtos->thread_details[thread_num].threadid == threadid) { if (target->rtos->thread_details[thread_num].exists) found = thread_num; } } } if (found != -1) gdb_put_packet(connection, "OK", 2); /* thread alive */ else gdb_put_packet(connection, "E01", 3); /* thread not found */ return ERROR_OK; } else if (packet[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for * all other operations ) */ if ((packet[1] == 'g') && (target->rtos != NULL)) { sscanf(packet, "Hg%16" SCNx64, &target->rtos->current_threadid); LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64 "\r\n", target->rtos->current_threadid); } gdb_put_packet(connection, "OK", 2); return ERROR_OK; } return GDB_THREAD_PACKET_NOT_CONSUMED; }
/* rtos_qsymbol() processes and replies to all qSymbol packets from GDB. * * GDB sends a qSymbol:: packet (empty address, empty name) to notify * that it can now answer qSymbol::hexcodedname queries, to look up symbols. * * If the qSymbol packet has no address that means GDB did not find the * symbol, in which case auto-detect will move on to try the next RTOS. * * rtos_qsymbol() then calls the next_symbol() helper function, which * iterates over symbol names for the current RTOS until it finds the * symbol in the received GDB packet, and then returns the next entry * in the list of symbols. * * If GDB replied about the last symbol for the RTOS and the RTOS was * specified explicitly, then no further symbol lookup is done. When * auto-detecting, the RTOS driver _detect() function must return success. * * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise. */ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_size) { int rtos_detected = 0; uint64_t addr = 0; size_t reply_len; char reply[GDB_BUFFER_SIZE], cur_sym[GDB_BUFFER_SIZE / 2] = ""; symbol_table_elem_t *next_sym = NULL; struct target *target = get_target_from_connection(connection); struct rtos *os = target->rtos; reply_len = sprintf(reply, "OK"); if (!os) goto done; /* Decode any symbol name in the packet*/ int len = unhexify(cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1)); cur_sym[len] = 0; if ((strcmp(packet, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */ (!sscanf(packet, "qSymbol:%" SCNx64 ":", &addr)) && /* GDB did not find an address for a symbol */ is_symbol_mandatory(os, cur_sym)) { /* the symbol is mandatory for this RTOS */ /* GDB could not find an address for the previous symbol */ if (!target->rtos_auto_detect) { LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os->type->name, cur_sym); goto done; } else { /* Autodetecting RTOS - try next RTOS */ if (!rtos_try_next(target)) { LOG_WARNING("No RTOS could be auto-detected!"); goto done; } /* Next RTOS selected - invalidate current symbol */ cur_sym[0] = '\x00'; } } next_sym = next_symbol(os, cur_sym, addr); if (!next_sym->symbol_name) { /* No more symbols need looking up */ if (!target->rtos_auto_detect) { rtos_detected = 1; goto done; } if (os->type->detect_rtos(target)) { LOG_INFO("Auto-detected RTOS: %s", os->type->name); rtos_detected = 1; goto done; } else { LOG_WARNING("No RTOS could be auto-detected!"); goto done; } } if (8 + (strlen(next_sym->symbol_name) * 2) + 1 > sizeof(reply)) { LOG_ERROR("ERROR: RTOS symbol '%s' name is too long for GDB!", next_sym->symbol_name); goto done; } reply_len = snprintf(reply, sizeof(reply), "qSymbol:"); reply_len += hexify(reply + reply_len, next_sym->symbol_name, 0, sizeof(reply) - reply_len); done: gdb_put_packet(connection, reply, reply_len); return rtos_detected; }
static int linux_task_update(struct target *target, int context) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct threads *thread_list = linux_os->thread_list; int retval; int loop = 0; linux_os->thread_count = 0; /*thread_list = thread_list->next; skip init_task*/ 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; } thread_list = thread_list->next; } int found = 0; if (linux_os->init_task_addr == 0xdeadbeef) { LOG_INFO("no init symbol\n"); return ERROR_FAIL; } int64_t start = timeval_ms(); struct threads *t = calloc(1, sizeof(struct threads)); uint32_t previous = 0xdeadbeef; t->base_addr = linux_os->init_task_addr; retval = get_current(target, 0); /*check that all current threads have been identified */ linux_identify_current_threads(target); while (((t->base_addr != linux_os->init_task_addr) && (t->base_addr != previous)) || (loop == 0)) { /* for avoiding any permanent loop for any reason possibly due to * target */ loop++; previous = t->base_addr; /* read only pid */ #ifdef PID_CHECK retval = fill_task_pid(target, t); #endif if (retval != ERROR_OK) { free(t); return ERROR_FAIL; } thread_list = linux_os->thread_list; while (thread_list != NULL) { #ifdef PID_CHECK if (t->pid == thread_list->pid) { #else if (t->base_addr == thread_list->base_addr) { #endif if (!thread_list->status) { #ifdef PID_CHECK if (t->base_addr != thread_list->base_addr) LOG_INFO("thread base_addr has changed !!"); #endif /* this is not a current thread */ thread_list->base_addr = t->base_addr; thread_list->status = 1; /* we don 't update this field any more */ /*thread_list->state = t->state; thread_list->oncpu = t->oncpu; thread_list->asid = t->asid; */ if (context) thread_list->context = cpu_context_read(target, thread_list-> base_addr, &thread_list-> thread_info_addr); } else { /* it is a current thread no need to read context */ } linux_os->thread_count++; found = 1; break; } else { found = 0; thread_list = thread_list->next; } } if (found == 0) { uint32_t base_addr; fill_task(target, t); get_name(target, t); retval = insert_into_threadlist(target, t); t->thread_info_addr = 0xdeadbeef; if (context) t->context = cpu_context_read(target, t->base_addr, &t->thread_info_addr); base_addr = next_task(target, t); t = calloc(1, sizeof(struct threads)); t->base_addr = base_addr; linux_os->thread_count++; } else t->base_addr = next_task(target, t); } LOG_INFO("update thread done %" PRId64 ", mean%" PRId64 "\n", (timeval_ms() - start), (timeval_ms() - start) / loop); free(t); linux_os->threads_needs_update = 0; return ERROR_OK; } int linux_gdb_thread_packet(struct target *target, struct connection *connection, char *packet, int packet_size) { int retval; struct linux_os *linux_os = (struct linux_os *)target->rtos->rtos_specific_params; if (linux_os->init_task_addr == 0xdeadbeef) { /* it has not been initialized */ LOG_INFO("received thread request without init task address"); gdb_put_packet(connection, "l", 1); return ERROR_OK; } retval = linux_get_tasks(target, 1); if (retval != ERROR_OK) return ERROR_TARGET_FAILURE; char *out_str = (char *)calloc(1, 350 * sizeof(int64_t)); char *tmp_str = out_str; tmp_str += sprintf(tmp_str, "m"); struct threads *temp = linux_os->thread_list; tmp_str += sprintf(tmp_str, "%016" PRIx64, temp->threadid); temp = temp->next; while (temp != NULL) { tmp_str += sprintf(tmp_str, ","); tmp_str += sprintf(tmp_str, "%016" PRIx64, temp->threadid); temp = temp->next; } gdb_put_packet(connection, out_str, strlen(out_str)); return ERROR_OK; }
static int linux_thread_packet(struct connection *connection, char *packet, int packet_size) { int retval = ERROR_OK; struct current_thread *ct; struct target *target = get_target_from_connection(connection); struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; switch (packet[0]) { case 'T': /* Is thread alive?*/ linux_gdb_T_packet(connection, target, packet, packet_size); break; case 'H': /* Set current thread */ /* ( 'c' for step and continue, 'g' for all other operations )*/ /*LOG_INFO(" H packet received '%s'", packet);*/ linux_gdb_h_packet(connection, target, packet, packet_size); break; case 'q': if (strncmp(packet, "qSymbol", 7) == 0) { if (rtos_qsymbol(connection, packet, packet_size) == 1) { linux_compute_virt2phys(target, target->rtos-> symbols[INIT_TASK]. address); } break; } else if (strncmp(packet, "qfThreadInfo", 12) == 0) { if (linux_os->thread_list == NULL) { retval = linux_gdb_thread_packet(target, connection, packet, packet_size); break; } else { retval = linux_gdb_thread_update(target, connection, packet, packet_size); break; } } else if (strncmp(packet, "qsThreadInfo", 12) == 0) { gdb_put_packet(connection, "l", 1); break; } else if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) { linux_thread_extra_info(target, connection, packet, packet_size); break; } else { retval = GDB_THREAD_PACKET_NOT_CONSUMED; break; } case 'Q': /* previously response was : thread not found * gdb_put_packet(connection, "E01", 3); */ retval = GDB_THREAD_PACKET_NOT_CONSUMED; break; case 'c': case 's': { if (linux_os->threads_lookup == 1) { ct = linux_os->current_threads; while ((ct != NULL) && (ct->core_id) != target->coreid) ct = ct->next; if ((ct != NULL) && (ct->threadid == -1)) { ct = linux_os->current_threads; while ((ct != NULL) && (ct->threadid == -1)) ct = ct->next; } if ((ct != NULL) && (ct->threadid != target->rtos-> current_threadid) && (target->rtos->current_threadid != -1)) LOG_WARNING("WARNING! current GDB thread do not match" \ "current thread running." \ "Switch thread in GDB to threadid %d", (int)ct->threadid); LOG_INFO("threads_needs_update = 1"); linux_os->threads_needs_update = 1; } } /* if a packet handler returned an error, exit input loop */ if (retval != ERROR_OK) return retval; } return retval; }
int linux_gdb_h_packet(struct connection *connection, struct target *target, char *packet, int packet_size) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct current_thread *ct = linux_os->current_threads; /* select to display the current thread of the selected target */ while ((ct != NULL) && (ct->core_id != target->coreid)) ct = ct->next; int64_t current_gdb_thread_rq; if (linux_os->threads_lookup == 1) { if ((ct != NULL) && (ct->threadid == -1)) { ct = linux_os->current_threads; while ((ct != NULL) && (ct->threadid == -1)) ct = ct->next; } if (ct == NULL) { /* no current thread can be identified * any way with smp */ LOG_INFO("no current thread identified"); /* attempt to display the name of the 2 threads identified with * get_current */ struct threads t; ct = linux_os->current_threads; while ((ct != NULL) && (ct->threadid == -1)) { t.base_addr = ct->TS; get_name(target, &t); LOG_INFO("name of unidentified thread %s", t.name); ct = ct->next; } gdb_put_packet(connection, "OK", 2); return ERROR_OK; } if (packet[1] == 'g') { sscanf(packet, "Hg%16" SCNx64, ¤t_gdb_thread_rq); if (current_gdb_thread_rq == 0) { target->rtos->current_threadid = ct->threadid; gdb_put_packet(connection, "OK", 2); } else { target->rtos->current_threadid = current_gdb_thread_rq; gdb_put_packet(connection, "OK", 2); } } else if (packet[1] == 'c') { sscanf(packet, "Hc%16" SCNx64, ¤t_gdb_thread_rq); if ((current_gdb_thread_rq == 0) || (current_gdb_thread_rq == ct->threadid)) { target->rtos->current_threadid = ct->threadid; gdb_put_packet(connection, "OK", 2); } else gdb_put_packet(connection, "E01", 3); } } else gdb_put_packet(connection, "OK", 2); return ERROR_OK; }
/* * This function does all command procesing for interfacing to gdb. */ void gdb_stub_handler(int exception_vector) { int sigval; int addr, length; char * ptr; #ifdef GDB_REMOTE_UDP gdb_udp_poll_start(); #endif /* GDB_REMOTE_UDP */ if(remote_debug) GDB_PRINTF("vector=%d, ps=0x%x, pc=0x%x\n", exception_vector, gdb_registers[PS], gdb_registers[PC]); /* reply to host that an exception has occurred */ sigval = compute_signal(exception_vector); remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hexchars[sigval >> 4]; remcomOutBuffer[2] = hexchars[sigval % 16]; remcomOutBuffer[3] = 0; if(remote_debug) GDB_PRINTF("GDB send packet: %s\n", remcomOutBuffer); gdb_put_packet(remcomOutBuffer); while (1) { remcomOutBuffer[0] = 0; gdb_get_packet(remcomInBuffer); if(remote_debug) GDB_PRINTF("GDB reveive packet: %s\n", remcomInBuffer); switch (remcomInBuffer[0]) { case '?' : remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hexchars[sigval >> 4]; remcomOutBuffer[2] = hexchars[sigval % 16]; remcomOutBuffer[3] = 0; break; case 'd' : remote_debug = !(remote_debug); /* toggle debug flag */ break; case 'g' : /* return the value of the CPU registers */ mem2hex((char*) gdb_registers, remcomOutBuffer, NUMREGBYTES, 0); break; case 'G' : /* set the value of the CPU registers - return OK */ hex2mem(&remcomInBuffer[1], (char*) gdb_registers, NUMREGBYTES, 0); gdb_strcpy(remcomOutBuffer,"OK"); break; /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ case 'm' : /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ ptr = &remcomInBuffer[1]; if (hex2int(&ptr,&addr)) if (*(ptr++) == ',') if (hex2int(&ptr,&length)) { ptr = 0; mem_err = 0; mem2hex((char*) addr, remcomOutBuffer, length, 1); if (mem_err) { gdb_strcpy (remcomOutBuffer, "E03"); if(remote_debug) GDB_PRINTF("memory fault"); } } if (ptr) { gdb_strcpy(remcomOutBuffer,"E01"); if(remote_debug) GDB_PRINTF("malformed read memory command: %s",remcomInBuffer); } break; /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ case 'M' : /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ ptr = &remcomInBuffer[1]; if (hex2int(&ptr,&addr)) if (*(ptr++) == ',') if (hex2int(&ptr,&length)) if (*(ptr++) == ':') { mem_err = 0; hex2mem(ptr, (char*) addr, length, 1); if (mem_err) { gdb_strcpy (remcomOutBuffer, "E03"); if(remote_debug) GDB_PRINTF("memory fault"); } else { gdb_strcpy(remcomOutBuffer,"OK"); } ptr = 0; } if (ptr) { gdb_strcpy(remcomOutBuffer,"E02"); if(remote_debug) GDB_PRINTF("malformed write memory command: %s",remcomInBuffer); } break; /* cAA..AA Continue at address AA..AA(optional) */ /* sAA..AA Step one instruction from AA..AA(optional) */ case 'c' : case 's' : /* try to read optional parameter, pc unchanged if no parm */ ptr = &remcomInBuffer[1]; if (hex2int(&ptr,&addr)) gdb_registers[PC] = addr; /* set the trace bit if we're stepping */ if (remcomInBuffer[0] == 's') gdb_registers[PS] |= 0x100; else gdb_registers[PS] &= 0xfffffeff; #ifdef GDB_REMOTE_UDP gdb_udp_poll_stop(); #endif /* GDB_REMOTE_UDP */ return; // break; /* kill the program */ case 'k' : /* do nothing */ break; /* Z<type-1x>,<address-x>,<length-x> Add breakpoint */ case 'Z' : if(hex(remcomInBuffer[1]) != 0) { /* We support only software break points so far */ break; } ptr = &remcomInBuffer[2]; if (*(ptr++) == ',') if (hex2int(&ptr,&addr)) { if (*(ptr++) == ',') { if (hex2int(&ptr,&length)) { if(length != 1) { gdb_strcpy(remcomOutBuffer,"E02"); if(remote_debug) GDB_PRINTF("Breakpoint address length isn't equal to 1."); break; } ptr = 0; } } } if (ptr) { gdb_strcpy(remcomOutBuffer,"E01"); if(remote_debug) GDB_PRINTF("malformed add breakpoint command: %s",remcomInBuffer); } else { struct zbreak *z; /* check whether this break point already set */ z = zbreak_list_find(addr); if(z) { /* Repeated packet */ gdb_strcpy(remcomOutBuffer,"OK"); break; } /* get an free zbreak */ mem_err = 0; z = zbreak_new(addr); if(z == NULL) { gdb_strcpy(remcomOutBuffer,"E03"); if(remote_debug) GDB_PRINTF("new zbreak failed.\n"); break; } if (mem_err) { gdb_strcpy (remcomOutBuffer, "E03"); if(remote_debug) GDB_PRINTF("memory fault"); break; } gdb_strcpy(remcomOutBuffer, "OK"); } break; /* z<type-1x>,<address-x>,<length-x> Remove breakpoint */ /* zz Remove all breakpoints */ case 'z' : if(hex(remcomInBuffer[1]) == 'z') { /* remove all breakpoints */ while(valid_zbreak_list.next != &valid_zbreak_list) { zbreak_free(valid_zbreak_list.next); } gdb_strcpy(remcomOutBuffer, "OK"); break; } if(hex(remcomInBuffer[1]) != 0) { /* We support only software break points so far */ break; } ptr = &remcomInBuffer[2]; if (*(ptr++) == ',') if (hex2int(&ptr,&addr)) { if (*(ptr++) == ',') { if (hex2int(&ptr,&length)) { if(length != 1) { gdb_strcpy(remcomOutBuffer,"E02"); if(remote_debug) GDB_PRINTF("Breakpoint address length isn't equal to 1."); break; } ptr = 0; } } } if (ptr) { gdb_strcpy(remcomOutBuffer,"E01"); if(remote_debug) GDB_PRINTF("malformed remove breakpoint command: %s",remcomInBuffer); } else { struct zbreak *z; z = zbreak_list_find(addr); if(z == NULL) { gdb_strcpy(remcomOutBuffer,"E03"); if(remote_debug) GDB_PRINTF("Breakpoint no found.\n"); break; } /* free zbreak */ zbreak_free(z); gdb_strcpy(remcomOutBuffer,"OK"); } break; } /* switch */ /* reply to the request */ if(remote_debug) GDB_PRINTF("GDB send packet: %s\n", remcomOutBuffer); gdb_put_packet(remcomOutBuffer); } }
int gdb_thread_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); if (strstr(packet, "qThreadExtraInfo,")) { if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) && (target->rtos->thread_count != 0)) { threadid_t threadid = 0; int found = -1; sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid ); if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) { int thread_num; for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) { if (target->rtos->thread_details[thread_num].threadid == threadid) { if (target->rtos->thread_details[thread_num].exists) { found = thread_num; } } } } if (found == -1) { gdb_put_packet(connection, "E01", 3); // thread not found return ERROR_OK; } struct thread_detail* detail = &target->rtos->thread_details[found]; int str_size = 0; if ( detail->display_str != NULL ) { str_size += strlen(detail->display_str); } if ( detail->thread_name_str != NULL ) { str_size += strlen(detail->thread_name_str); } if ( detail->extra_info_str != NULL ) { str_size += strlen(detail->extra_info_str); } char * tmp_str = (char*) malloc( str_size + 7 ); char* tmp_str_ptr = tmp_str; if ( detail->display_str != NULL ) { tmp_str_ptr += sprintf( tmp_str_ptr, "%s", detail->display_str ); } if ( detail->thread_name_str != NULL ) { if ( tmp_str_ptr != tmp_str ) { tmp_str_ptr += sprintf( tmp_str_ptr, " : " ); } tmp_str_ptr += sprintf( tmp_str_ptr, "%s", detail->thread_name_str ); } if ( detail->extra_info_str != NULL ) { if ( tmp_str_ptr != tmp_str ) { tmp_str_ptr += sprintf( tmp_str_ptr, " : " ); } tmp_str_ptr += sprintf( tmp_str_ptr, " : %s", detail->extra_info_str ); } assert(strlen(tmp_str) == (size_t) (tmp_str_ptr - tmp_str)); char * hex_str = (char*) malloc( strlen(tmp_str)*2 +1 ); str_to_hex( hex_str, tmp_str ); gdb_put_packet(connection, hex_str, strlen(hex_str)); free(hex_str); free(tmp_str); return ERROR_OK; } gdb_put_packet(connection, "", 0); return ERROR_OK; } else if (strstr(packet, "qSymbol")) { if ( target->rtos != NULL ) { int next_symbol_num = -1; if (target->rtos->symbols == NULL) { target->rtos->type->get_symbol_list_to_lookup( &target->rtos->symbols ); } if (0 == strcmp( "qSymbol::", packet ) ) { // first query - next_symbol_num = 0; } else { int64_t value = 0; char * hex_name_str = malloc( strlen(packet)); char * name_str; int symbol_num; char* found = strstr( packet, "qSymbol::" ); if (0 == found ) { sscanf(packet, "qSymbol:%" SCNx64 ":%s", &value, hex_name_str); } else { // No value returned by GDB - symbol was not found sscanf(packet, "qSymbol::%s", hex_name_str); } name_str = (char*) malloc( 1+ strlen(hex_name_str) / 2 ); hex_to_str( name_str, hex_name_str ); symbol_num = 0; while ( ( target->rtos->symbols[ symbol_num ].symbol_name != NULL ) && ( 0 != strcmp( target->rtos->symbols[ symbol_num ].symbol_name, name_str ) ) ) { symbol_num++; } if ( target->rtos->symbols[ symbol_num ].symbol_name == NULL ) { LOG_OUTPUT("ERROR: unknown symbol\r\n"); gdb_put_packet(connection, "OK", 2); return ERROR_OK; } target->rtos->symbols[ symbol_num ].address = value; next_symbol_num = symbol_num+1; free( hex_name_str ); free( name_str ); } int symbols_done = 0; if ( target->rtos->symbols[ next_symbol_num ].symbol_name == NULL ) { if ( ( target->rtos_auto_detect == false ) || ( 1 == target->rtos->type->detect_rtos( target ) ) ) { // Found correct RTOS or not autodetecting if ( target->rtos_auto_detect == true ) { LOG_OUTPUT( "Auto-detected RTOS: %s\r\n",target->rtos->type->name ); } symbols_done = 1; } else { // Auto detecting RTOS and currently not found if( 1 != rtos_try_next( target ) ) { // No more RTOS's to try symbols_done = 1; } else { next_symbol_num = 0; target->rtos->type->get_symbol_list_to_lookup( &target->rtos->symbols ); } } } if ( symbols_done == 1 ) { target->rtos_auto_detect = false; target->rtos->type->create( target ); target->rtos->type->update_threads(target->rtos); // No more symbols needed gdb_put_packet(connection, "OK", 2); return ERROR_OK; } else { char* symname = target->rtos->symbols[ next_symbol_num ].symbol_name; char qsymstr[] = "qSymbol:"; char * opstring = (char*)malloc(sizeof(qsymstr)+strlen(symname)*2+1); char * posptr = opstring; posptr += sprintf( posptr, "%s", qsymstr ); str_to_hex( posptr, symname ); gdb_put_packet(connection, opstring, strlen(opstring)); free(opstring); return ERROR_OK; } } gdb_put_packet(connection, "OK", 2); return ERROR_OK; } else if (strstr(packet, "qfThreadInfo")) { int i; if ( ( target->rtos != NULL ) && ( target->rtos->thread_count != 0 ) ) { char* out_str = (char*) malloc(17 * target->rtos->thread_count + 5); char* tmp_str = out_str; tmp_str += sprintf(tmp_str, "m"); for (i = 0; i < target->rtos->thread_count; i++) { if (i != 0) { tmp_str += sprintf(tmp_str, ","); } tmp_str += sprintf(tmp_str, "%016" PRIx64, target->rtos->thread_details[i].threadid); } tmp_str[0] = 0; gdb_put_packet(connection, out_str, strlen(out_str)); } else { gdb_put_packet(connection, "", 0); } return ERROR_OK; } else if (strstr(packet, "qsThreadInfo")) { gdb_put_packet(connection, "l", 1); return ERROR_OK; } else if (strstr(packet, "qAttached")) { gdb_put_packet(connection, "1", 1); return ERROR_OK; } else if (strstr(packet, "qOffsets")) { char offsets[] = "Text=0;Data=0;Bss=0"; gdb_put_packet(connection, offsets, sizeof(offsets)-1); return ERROR_OK; } else if (strstr(packet, "qC")) { if( target->rtos!=NULL ) { char buffer[15]; int size; size = snprintf(buffer, 15, "QC%08X", (int)target->rtos->current_thread); gdb_put_packet(connection, buffer, size); } else { gdb_put_packet(connection, "QC0", 3); } return ERROR_OK; } else if ( packet[0] == 'T' ) // Is thread alive? { threadid_t threadid; int found = -1; sscanf(packet, "T%" SCNx64, &threadid); if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) { int thread_num; for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) { if (target->rtos->thread_details[thread_num].threadid == threadid) { if (target->rtos->thread_details[thread_num].exists) { found = thread_num; } } } } if (found != -1) { gdb_put_packet(connection, "OK", 2); // thread alive } else { gdb_put_packet(connection, "E01", 3); // thread not found } return ERROR_OK; } else if ( packet[0] == 'H') // Set current thread ( 'c' for step and continue, 'g' for all other operations ) { if (packet[1] == 'g') { sscanf(packet, "Hg%16" SCNx64, ¤t_threadid); } gdb_put_packet(connection, "OK", 2); return ERROR_OK; } return GDB_THREAD_PACKET_NOT_CONSUMED; }