1 /***************************************************************************
2 * Copyright (C) 2011 by Broadcom Corporation *
3 * Evan Hunter - ehunter@broadcom.com *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
24 #include "target/target.h"
25 #include "helper/log.h"
26 #include "helper/binarybuffer.h"
27 #include "server/gdb_server.h"
30 extern struct rtos_type FreeRTOS_rtos
;
31 extern struct rtos_type ThreadX_rtos
;
32 extern struct rtos_type eCos_rtos
;
33 extern struct rtos_type Linux_os
;
34 extern struct rtos_type ChibiOS_rtos
;
35 extern struct rtos_type chromium_ec_rtos
;
36 extern struct rtos_type embKernel_rtos
;
37 extern struct rtos_type mqx_rtos
;
38 extern struct rtos_type uCOS_III_rtos
;
39 extern struct rtos_type nuttx_rtos
;
40 extern struct rtos_type hwthread_rtos
;
42 static struct rtos_type
*rtos_types
[] = {
57 int rtos_thread_packet(struct connection
*connection
, const char *packet
, int packet_size
);
59 int rtos_smp_init(struct target
*target
)
61 if (target
->rtos
->type
->smp_init
)
62 return target
->rtos
->type
->smp_init(target
);
63 return ERROR_TARGET_INIT_FAILED
;
66 static int rtos_target_for_threadid(struct connection
*connection
, int64_t threadid
, struct target
**t
)
68 struct target
*curr
= get_target_from_connection(connection
);
75 static int os_alloc(struct target
*target
, struct rtos_type
*ostype
)
77 struct rtos
*os
= target
->rtos
= calloc(1, sizeof(struct rtos
));
83 os
->current_threadid
= -1;
84 os
->current_thread
= 0;
88 /* RTOS drivers can override the packet handler in _create(). */
89 os
->gdb_thread_packet
= rtos_thread_packet
;
90 os
->gdb_target_for_threadid
= rtos_target_for_threadid
;
95 static void os_free(struct target
*target
)
100 if (target
->rtos
->symbols
)
101 free(target
->rtos
->symbols
);
107 static int os_alloc_create(struct target
*target
, struct rtos_type
*ostype
)
109 int ret
= os_alloc(target
, ostype
);
112 ret
= target
->rtos
->type
->create(target
);
120 int rtos_create(Jim_GetOptInfo
*goi
, struct target
*target
)
127 if (!goi
->isconfigure
&& goi
->argc
!= 0) {
128 Jim_WrongNumArgs(goi
->interp
, goi
->argc
, goi
->argv
, "NO PARAMS");
134 e
= Jim_GetOpt_String(goi
, &cp
, NULL
);
138 if (0 == strcmp(cp
, "auto")) {
139 /* Auto detect tries to look up all symbols for each RTOS,
140 * and runs the RTOS driver's _detect() function when GDB
141 * finds all symbols for any RTOS. See rtos_qsymbol(). */
142 target
->rtos_auto_detect
= true;
144 /* rtos_qsymbol() will iterate over all RTOSes. Allocate
145 * target->rtos here, and set it to the first RTOS type. */
146 return os_alloc(target
, rtos_types
[0]);
149 for (x
= 0; rtos_types
[x
]; x
++)
150 if (0 == strcmp(cp
, rtos_types
[x
]->name
))
151 return os_alloc_create(target
, rtos_types
[x
]);
153 Jim_SetResultFormatted(goi
->interp
, "Unknown RTOS type %s, try one of: ", cp
);
154 res
= Jim_GetResult(goi
->interp
);
155 for (x
= 0; rtos_types
[x
]; x
++)
156 Jim_AppendStrings(goi
->interp
, res
, rtos_types
[x
]->name
, ", ", NULL
);
157 Jim_AppendStrings(goi
->interp
, res
, " or auto", NULL
);
162 int gdb_thread_packet(struct connection
*connection
, char const *packet
, int packet_size
)
164 struct target
*target
= get_target_from_connection(connection
);
165 if (target
->rtos
== NULL
)
166 return rtos_thread_packet(connection
, packet
, packet_size
); /* thread not
168 return target
->rtos
->gdb_thread_packet(connection
, packet
, packet_size
);
171 static symbol_table_elem_t
*next_symbol(struct rtos
*os
, char *cur_symbol
, uint64_t cur_addr
)
173 symbol_table_elem_t
*s
;
176 os
->type
->get_symbol_list_to_lookup(&os
->symbols
);
179 return &os
->symbols
[0];
181 for (s
= os
->symbols
; s
->symbol_name
; s
++)
182 if (!strcmp(s
->symbol_name
, cur_symbol
)) {
183 s
->address
= cur_addr
;
191 /* searches for 'symbol' in the lookup table for 'os' and returns TRUE,
192 * if 'symbol' is not declared optional */
193 static bool is_symbol_mandatory(const struct rtos
*os
, const char *symbol
)
195 for (symbol_table_elem_t
*s
= os
->symbols
; s
->symbol_name
; ++s
) {
196 if (!strcmp(s
->symbol_name
, symbol
))
202 /* rtos_qsymbol() processes and replies to all qSymbol packets from GDB.
204 * GDB sends a qSymbol:: packet (empty address, empty name) to notify
205 * that it can now answer qSymbol::hexcodedname queries, to look up symbols.
207 * If the qSymbol packet has no address that means GDB did not find the
208 * symbol, in which case auto-detect will move on to try the next RTOS.
210 * rtos_qsymbol() then calls the next_symbol() helper function, which
211 * iterates over symbol names for the current RTOS until it finds the
212 * symbol in the received GDB packet, and then returns the next entry
213 * in the list of symbols.
215 * If GDB replied about the last symbol for the RTOS and the RTOS was
216 * specified explicitly, then no further symbol lookup is done. When
217 * auto-detecting, the RTOS driver _detect() function must return success.
219 * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise.
221 int rtos_qsymbol(struct connection
*connection
, char const *packet
, int packet_size
)
223 int rtos_detected
= 0;
226 char reply
[GDB_BUFFER_SIZE
+ 1], cur_sym
[GDB_BUFFER_SIZE
/ 2 + 1] = ""; /* Extra byte for nul-termination */
227 symbol_table_elem_t
*next_sym
= NULL
;
228 struct target
*target
= get_target_from_connection(connection
);
229 struct rtos
*os
= target
->rtos
;
231 reply_len
= sprintf(reply
, "OK");
236 /* Decode any symbol name in the packet*/
237 size_t len
= unhexify((uint8_t *)cur_sym
, strchr(packet
+ 8, ':') + 1, strlen(strchr(packet
+ 8, ':') + 1));
240 if ((strcmp(packet
, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */
241 (!sscanf(packet
, "qSymbol:%" SCNx64
":", &addr
)) && /* GDB did not find an address for a symbol */
242 is_symbol_mandatory(os
, cur_sym
)) { /* the symbol is mandatory for this RTOS */
244 /* GDB could not find an address for the previous symbol */
245 if (!target
->rtos_auto_detect
) {
246 LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os
->type
->name
, cur_sym
);
249 /* Autodetecting RTOS - try next RTOS */
250 if (!rtos_try_next(target
)) {
251 LOG_WARNING("No RTOS could be auto-detected!");
255 /* Next RTOS selected - invalidate current symbol */
259 next_sym
= next_symbol(os
, cur_sym
, addr
);
261 if (!next_sym
->symbol_name
) {
262 /* No more symbols need looking up */
264 if (!target
->rtos_auto_detect
) {
269 if (os
->type
->detect_rtos(target
)) {
270 LOG_INFO("Auto-detected RTOS: %s", os
->type
->name
);
274 LOG_WARNING("No RTOS could be auto-detected!");
279 if (8 + (strlen(next_sym
->symbol_name
) * 2) + 1 > sizeof(reply
)) {
280 LOG_ERROR("ERROR: RTOS symbol '%s' name is too long for GDB!", next_sym
->symbol_name
);
284 reply_len
= snprintf(reply
, sizeof(reply
), "qSymbol:");
285 reply_len
+= hexify(reply
+ reply_len
,
286 (const uint8_t *)next_sym
->symbol_name
, strlen(next_sym
->symbol_name
),
287 sizeof(reply
) - reply_len
);
290 gdb_put_packet(connection
, reply
, reply_len
);
291 return rtos_detected
;
294 int rtos_thread_packet(struct connection
*connection
, char const *packet
, int packet_size
)
296 struct target
*target
= get_target_from_connection(connection
);
298 if (strncmp(packet
, "qThreadExtraInfo,", 17) == 0) {
299 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
) &&
300 (target
->rtos
->thread_count
!= 0)) {
301 threadid_t threadid
= 0;
303 sscanf(packet
, "qThreadExtraInfo,%" SCNx64
, &threadid
);
305 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
)) {
307 for (thread_num
= 0; thread_num
< target
->rtos
->thread_count
; thread_num
++) {
308 if (target
->rtos
->thread_details
[thread_num
].threadid
== threadid
) {
309 if (target
->rtos
->thread_details
[thread_num
].exists
)
315 gdb_put_packet(connection
, "E01", 3); /* thread not found */
319 struct thread_detail
*detail
= &target
->rtos
->thread_details
[found
];
322 if (detail
->thread_name_str
!= NULL
)
323 str_size
+= strlen(detail
->thread_name_str
);
324 if (detail
->extra_info_str
!= NULL
)
325 str_size
+= strlen(detail
->extra_info_str
);
327 char *tmp_str
= calloc(str_size
+ 9, sizeof(char));
328 char *tmp_str_ptr
= tmp_str
;
330 if (detail
->thread_name_str
!= NULL
)
331 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "Name: %s", detail
->thread_name_str
);
332 if (detail
->extra_info_str
!= NULL
) {
333 if (tmp_str_ptr
!= tmp_str
)
334 tmp_str_ptr
+= sprintf(tmp_str_ptr
, ", ");
335 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%s", detail
->extra_info_str
);
338 assert(strlen(tmp_str
) ==
339 (size_t) (tmp_str_ptr
- tmp_str
));
341 char *hex_str
= malloc(strlen(tmp_str
) * 2 + 1);
342 size_t pkt_len
= hexify(hex_str
, (const uint8_t *)tmp_str
,
343 strlen(tmp_str
), strlen(tmp_str
) * 2 + 1);
345 gdb_put_packet(connection
, hex_str
, pkt_len
);
351 gdb_put_packet(connection
, "", 0);
353 } else if (strncmp(packet
, "qSymbol", 7) == 0) {
354 if (rtos_qsymbol(connection
, packet
, packet_size
) == 1) {
355 if (target
->rtos_auto_detect
== true) {
356 target
->rtos_auto_detect
= false;
357 target
->rtos
->type
->create(target
);
359 target
->rtos
->type
->update_threads(target
->rtos
);
362 } else if (strncmp(packet
, "qfThreadInfo", 12) == 0) {
364 if (target
->rtos
!= NULL
) {
365 if (target
->rtos
->thread_count
== 0) {
366 gdb_put_packet(connection
, "l", 1);
368 /*thread id are 16 char +1 for ',' */
369 char *out_str
= malloc(17 * target
->rtos
->thread_count
+ 1);
370 char *tmp_str
= out_str
;
371 for (i
= 0; i
< target
->rtos
->thread_count
; i
++) {
372 tmp_str
+= sprintf(tmp_str
, "%c%016" PRIx64
, i
== 0 ? 'm' : ',',
373 target
->rtos
->thread_details
[i
].threadid
);
375 gdb_put_packet(connection
, out_str
, strlen(out_str
));
379 gdb_put_packet(connection
, "l", 1);
382 } else if (strncmp(packet
, "qsThreadInfo", 12) == 0) {
383 gdb_put_packet(connection
, "l", 1);
385 } else if (strncmp(packet
, "qAttached", 9) == 0) {
386 gdb_put_packet(connection
, "1", 1);
388 } else if (strncmp(packet
, "qOffsets", 8) == 0) {
389 char offsets
[] = "Text=0;Data=0;Bss=0";
390 gdb_put_packet(connection
, offsets
, sizeof(offsets
)-1);
392 } else if (strncmp(packet
, "qCRC:", 5) == 0) {
393 /* make sure we check this before "qC" packet below
394 * otherwise it gets incorrectly handled */
395 return GDB_THREAD_PACKET_NOT_CONSUMED
;
396 } else if (strncmp(packet
, "qC", 2) == 0) {
397 if (target
->rtos
!= NULL
) {
400 size
= snprintf(buffer
, 19, "QC%016" PRIx64
, target
->rtos
->current_thread
);
401 gdb_put_packet(connection
, buffer
, size
);
403 gdb_put_packet(connection
, "QC0", 3);
405 } else if (packet
[0] == 'T') { /* Is thread alive? */
408 sscanf(packet
, "T%" SCNx64
, &threadid
);
409 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
)) {
411 for (thread_num
= 0; thread_num
< target
->rtos
->thread_count
; thread_num
++) {
412 if (target
->rtos
->thread_details
[thread_num
].threadid
== threadid
) {
413 if (target
->rtos
->thread_details
[thread_num
].exists
)
419 gdb_put_packet(connection
, "OK", 2); /* thread alive */
421 gdb_put_packet(connection
, "E01", 3); /* thread not found */
423 } else if (packet
[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for
424 * all other operations ) */
425 if ((packet
[1] == 'g') && (target
->rtos
!= NULL
)) {
427 sscanf(packet
, "Hg%16" SCNx64
, &threadid
);
428 LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64
, threadid
);
429 /* threadid of 0 indicates target should choose */
431 target
->rtos
->current_threadid
= target
->rtos
->current_thread
;
433 target
->rtos
->current_threadid
= threadid
;
435 gdb_put_packet(connection
, "OK", 2);
439 return GDB_THREAD_PACKET_NOT_CONSUMED
;
442 static int rtos_put_gdb_reg_list(struct connection
*connection
,
443 struct rtos_reg
*reg_list
, int num_regs
)
445 size_t num_bytes
= 1; /* NUL */
446 for (int i
= 0; i
< num_regs
; ++i
)
447 num_bytes
+= DIV_ROUND_UP(reg_list
[i
].size
, 8) * 2;
449 char *hex
= malloc(num_bytes
);
452 for (int i
= 0; i
< num_regs
; ++i
) {
453 size_t count
= DIV_ROUND_UP(reg_list
[i
].size
, 8);
454 size_t n
= hexify(hex_p
, reg_list
[i
].value
, count
, num_bytes
);
459 gdb_put_packet(connection
, hex
, strlen(hex
));
465 int rtos_get_gdb_reg(struct connection
*connection
, int reg_num
)
467 struct target
*target
= get_target_from_connection(connection
);
468 int64_t current_threadid
= target
->rtos
->current_threadid
;
469 if ((target
->rtos
!= NULL
) && (current_threadid
!= -1) &&
470 (current_threadid
!= 0) &&
471 ((current_threadid
!= target
->rtos
->current_thread
) ||
472 (target
->smp
))) { /* in smp several current thread are possible */
473 struct rtos_reg
*reg_list
;
476 LOG_DEBUG("RTOS: getting register %d for thread 0x%" PRIx64
477 ", target->rtos->current_thread=0x%" PRIx64
"\r\n",
480 target
->rtos
->current_thread
);
482 int retval
= target
->rtos
->type
->get_thread_reg_list(target
->rtos
,
486 if (retval
!= ERROR_OK
) {
487 LOG_ERROR("RTOS: failed to get register list");
491 for (int i
= 0; i
< num_regs
; ++i
) {
492 if (reg_list
[i
].number
== (uint32_t)reg_num
) {
493 rtos_put_gdb_reg_list(connection
, reg_list
+ i
, 1);
504 int rtos_get_gdb_reg_list(struct connection
*connection
)
506 struct target
*target
= get_target_from_connection(connection
);
507 int64_t current_threadid
= target
->rtos
->current_threadid
;
508 if ((target
->rtos
!= NULL
) && (current_threadid
!= -1) &&
509 (current_threadid
!= 0) &&
510 ((current_threadid
!= target
->rtos
->current_thread
) ||
511 (target
->smp
))) { /* in smp several current thread are possible */
512 struct rtos_reg
*reg_list
;
515 LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64
516 ", target->rtos->current_thread=0x%" PRIx64
"\r\n",
518 target
->rtos
->current_thread
);
520 int retval
= target
->rtos
->type
->get_thread_reg_list(target
->rtos
,
524 if (retval
!= ERROR_OK
) {
525 LOG_ERROR("RTOS: failed to get register list");
529 rtos_put_gdb_reg_list(connection
, reg_list
, num_regs
);
537 int rtos_generic_stack_read(struct target
*target
,
538 const struct rtos_register_stacking
*stacking
,
540 struct rtos_reg
**reg_list
,
545 if (stack_ptr
== 0) {
546 LOG_ERROR("Error: null stack pointer in thread");
550 uint8_t *stack_data
= malloc(stacking
->stack_registers_size
);
551 uint32_t address
= stack_ptr
;
553 if (stacking
->stack_growth_direction
== 1)
554 address
-= stacking
->stack_registers_size
;
555 retval
= target_read_buffer(target
, address
, stacking
->stack_registers_size
, stack_data
);
556 if (retval
!= ERROR_OK
) {
558 LOG_ERROR("Error reading stack frame from thread");
561 LOG_DEBUG("RTOS: Read stack frame at 0x%" PRIx32
, address
);
564 LOG_OUTPUT("Stack Data :");
565 for (i
= 0; i
< stacking
->stack_registers_size
; i
++)
566 LOG_OUTPUT("%02X", stack_data
[i
]);
570 int64_t new_stack_ptr
;
571 if (stacking
->calculate_process_stack
!= NULL
) {
572 new_stack_ptr
= stacking
->calculate_process_stack(target
,
573 stack_data
, stacking
, stack_ptr
);
575 new_stack_ptr
= stack_ptr
- stacking
->stack_growth_direction
*
576 stacking
->stack_registers_size
;
579 *reg_list
= calloc(stacking
->num_output_registers
, sizeof(struct rtos_reg
));
580 *num_regs
= stacking
->num_output_registers
;
582 for (int i
= 0; i
< stacking
->num_output_registers
; ++i
) {
583 (*reg_list
)[i
].number
= stacking
->register_offsets
[i
].number
;
584 (*reg_list
)[i
].size
= stacking
->register_offsets
[i
].width_bits
;
586 int offset
= stacking
->register_offsets
[i
].offset
;
588 buf_cpy(&new_stack_ptr
, (*reg_list
)[i
].value
, (*reg_list
)[i
].size
);
589 else if (offset
!= -1)
590 buf_cpy(stack_data
+ offset
, (*reg_list
)[i
].value
, (*reg_list
)[i
].size
);
594 /* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
598 int rtos_try_next(struct target
*target
)
600 struct rtos
*os
= target
->rtos
;
601 struct rtos_type
**type
= rtos_types
;
606 while (*type
&& os
->type
!= *type
)
609 if (!*type
|| !*(++type
))
621 int rtos_update_threads(struct target
*target
)
623 if ((target
->rtos
!= NULL
) && (target
->rtos
->type
!= NULL
))
624 target
->rtos
->type
->update_threads(target
->rtos
);
628 void rtos_free_threadlist(struct rtos
*rtos
)
630 if (rtos
->thread_details
) {
633 for (j
= 0; j
< rtos
->thread_count
; j
++) {
634 struct thread_detail
*current_thread
= &rtos
->thread_details
[j
];
635 free(current_thread
->thread_name_str
);
636 free(current_thread
->extra_info_str
);
638 free(rtos
->thread_details
);
639 rtos
->thread_details
= NULL
;
640 rtos
->thread_count
= 0;
641 rtos
->current_threadid
= -1;
642 rtos
->current_thread
= 0;
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)