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 void rtos_destroy(struct target
*target
)
167 int gdb_thread_packet(struct connection
*connection
, char const *packet
, int packet_size
)
169 struct target
*target
= get_target_from_connection(connection
);
170 if (target
->rtos
== NULL
)
171 return rtos_thread_packet(connection
, packet
, packet_size
); /* thread not
173 return target
->rtos
->gdb_thread_packet(connection
, packet
, packet_size
);
176 static symbol_table_elem_t
*next_symbol(struct rtos
*os
, char *cur_symbol
, uint64_t cur_addr
)
178 symbol_table_elem_t
*s
;
181 os
->type
->get_symbol_list_to_lookup(&os
->symbols
);
184 return &os
->symbols
[0];
186 for (s
= os
->symbols
; s
->symbol_name
; s
++)
187 if (!strcmp(s
->symbol_name
, cur_symbol
)) {
188 s
->address
= cur_addr
;
196 /* searches for 'symbol' in the lookup table for 'os' and returns TRUE,
197 * if 'symbol' is not declared optional */
198 static bool is_symbol_mandatory(const struct rtos
*os
, const char *symbol
)
200 for (symbol_table_elem_t
*s
= os
->symbols
; s
->symbol_name
; ++s
) {
201 if (!strcmp(s
->symbol_name
, symbol
))
207 /* rtos_qsymbol() processes and replies to all qSymbol packets from GDB.
209 * GDB sends a qSymbol:: packet (empty address, empty name) to notify
210 * that it can now answer qSymbol::hexcodedname queries, to look up symbols.
212 * If the qSymbol packet has no address that means GDB did not find the
213 * symbol, in which case auto-detect will move on to try the next RTOS.
215 * rtos_qsymbol() then calls the next_symbol() helper function, which
216 * iterates over symbol names for the current RTOS until it finds the
217 * symbol in the received GDB packet, and then returns the next entry
218 * in the list of symbols.
220 * If GDB replied about the last symbol for the RTOS and the RTOS was
221 * specified explicitly, then no further symbol lookup is done. When
222 * auto-detecting, the RTOS driver _detect() function must return success.
224 * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise.
226 int rtos_qsymbol(struct connection
*connection
, char const *packet
, int packet_size
)
228 int rtos_detected
= 0;
231 char reply
[GDB_BUFFER_SIZE
+ 1], cur_sym
[GDB_BUFFER_SIZE
/ 2 + 1] = ""; /* Extra byte for nul-termination */
232 symbol_table_elem_t
*next_sym
= NULL
;
233 struct target
*target
= get_target_from_connection(connection
);
234 struct rtos
*os
= target
->rtos
;
236 reply_len
= sprintf(reply
, "OK");
241 /* Decode any symbol name in the packet*/
242 size_t len
= unhexify((uint8_t *)cur_sym
, strchr(packet
+ 8, ':') + 1, strlen(strchr(packet
+ 8, ':') + 1));
245 if ((strcmp(packet
, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */
246 (!sscanf(packet
, "qSymbol:%" SCNx64
":", &addr
)) && /* GDB did not find an address for a symbol */
247 is_symbol_mandatory(os
, cur_sym
)) { /* the symbol is mandatory for this RTOS */
249 /* GDB could not find an address for the previous symbol */
250 if (!target
->rtos_auto_detect
) {
251 LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os
->type
->name
, cur_sym
);
254 /* Autodetecting RTOS - try next RTOS */
255 if (!rtos_try_next(target
)) {
256 LOG_WARNING("No RTOS could be auto-detected!");
260 /* Next RTOS selected - invalidate current symbol */
264 next_sym
= next_symbol(os
, cur_sym
, addr
);
266 if (!next_sym
->symbol_name
) {
267 /* No more symbols need looking up */
269 if (!target
->rtos_auto_detect
) {
274 if (os
->type
->detect_rtos(target
)) {
275 LOG_INFO("Auto-detected RTOS: %s", os
->type
->name
);
279 LOG_WARNING("No RTOS could be auto-detected!");
284 if (8 + (strlen(next_sym
->symbol_name
) * 2) + 1 > sizeof(reply
)) {
285 LOG_ERROR("ERROR: RTOS symbol '%s' name is too long for GDB!", next_sym
->symbol_name
);
289 reply_len
= snprintf(reply
, sizeof(reply
), "qSymbol:");
290 reply_len
+= hexify(reply
+ reply_len
,
291 (const uint8_t *)next_sym
->symbol_name
, strlen(next_sym
->symbol_name
),
292 sizeof(reply
) - reply_len
);
295 gdb_put_packet(connection
, reply
, reply_len
);
296 return rtos_detected
;
299 int rtos_thread_packet(struct connection
*connection
, char const *packet
, int packet_size
)
301 struct target
*target
= get_target_from_connection(connection
);
303 if (strncmp(packet
, "qThreadExtraInfo,", 17) == 0) {
304 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
) &&
305 (target
->rtos
->thread_count
!= 0)) {
306 threadid_t threadid
= 0;
308 sscanf(packet
, "qThreadExtraInfo,%" SCNx64
, &threadid
);
310 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
)) {
312 for (thread_num
= 0; thread_num
< target
->rtos
->thread_count
; thread_num
++) {
313 if (target
->rtos
->thread_details
[thread_num
].threadid
== threadid
) {
314 if (target
->rtos
->thread_details
[thread_num
].exists
)
320 gdb_put_packet(connection
, "E01", 3); /* thread not found */
324 struct thread_detail
*detail
= &target
->rtos
->thread_details
[found
];
327 if (detail
->thread_name_str
!= NULL
)
328 str_size
+= strlen(detail
->thread_name_str
);
329 if (detail
->extra_info_str
!= NULL
)
330 str_size
+= strlen(detail
->extra_info_str
);
332 char *tmp_str
= calloc(str_size
+ 9, sizeof(char));
333 char *tmp_str_ptr
= tmp_str
;
335 if (detail
->thread_name_str
!= NULL
)
336 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "Name: %s", detail
->thread_name_str
);
337 if (detail
->extra_info_str
!= NULL
) {
338 if (tmp_str_ptr
!= tmp_str
)
339 tmp_str_ptr
+= sprintf(tmp_str_ptr
, ", ");
340 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%s", detail
->extra_info_str
);
343 assert(strlen(tmp_str
) ==
344 (size_t) (tmp_str_ptr
- tmp_str
));
346 char *hex_str
= malloc(strlen(tmp_str
) * 2 + 1);
347 size_t pkt_len
= hexify(hex_str
, (const uint8_t *)tmp_str
,
348 strlen(tmp_str
), strlen(tmp_str
) * 2 + 1);
350 gdb_put_packet(connection
, hex_str
, pkt_len
);
356 gdb_put_packet(connection
, "", 0);
358 } else if (strncmp(packet
, "qSymbol", 7) == 0) {
359 if (rtos_qsymbol(connection
, packet
, packet_size
) == 1) {
360 if (target
->rtos_auto_detect
== true) {
361 target
->rtos_auto_detect
= false;
362 target
->rtos
->type
->create(target
);
364 target
->rtos
->type
->update_threads(target
->rtos
);
367 } else if (strncmp(packet
, "qfThreadInfo", 12) == 0) {
369 if (target
->rtos
!= NULL
) {
370 if (target
->rtos
->thread_count
== 0) {
371 gdb_put_packet(connection
, "l", 1);
373 /*thread id are 16 char +1 for ',' */
374 char *out_str
= malloc(17 * target
->rtos
->thread_count
+ 1);
375 char *tmp_str
= out_str
;
376 for (i
= 0; i
< target
->rtos
->thread_count
; i
++) {
377 tmp_str
+= sprintf(tmp_str
, "%c%016" PRIx64
, i
== 0 ? 'm' : ',',
378 target
->rtos
->thread_details
[i
].threadid
);
380 gdb_put_packet(connection
, out_str
, strlen(out_str
));
384 gdb_put_packet(connection
, "l", 1);
387 } else if (strncmp(packet
, "qsThreadInfo", 12) == 0) {
388 gdb_put_packet(connection
, "l", 1);
390 } else if (strncmp(packet
, "qAttached", 9) == 0) {
391 gdb_put_packet(connection
, "1", 1);
393 } else if (strncmp(packet
, "qOffsets", 8) == 0) {
394 char offsets
[] = "Text=0;Data=0;Bss=0";
395 gdb_put_packet(connection
, offsets
, sizeof(offsets
)-1);
397 } else if (strncmp(packet
, "qCRC:", 5) == 0) {
398 /* make sure we check this before "qC" packet below
399 * otherwise it gets incorrectly handled */
400 return GDB_THREAD_PACKET_NOT_CONSUMED
;
401 } else if (strncmp(packet
, "qC", 2) == 0) {
402 if (target
->rtos
!= NULL
) {
405 size
= snprintf(buffer
, 19, "QC%016" PRIx64
, target
->rtos
->current_thread
);
406 gdb_put_packet(connection
, buffer
, size
);
408 gdb_put_packet(connection
, "QC0", 3);
410 } else if (packet
[0] == 'T') { /* Is thread alive? */
413 sscanf(packet
, "T%" SCNx64
, &threadid
);
414 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
)) {
416 for (thread_num
= 0; thread_num
< target
->rtos
->thread_count
; thread_num
++) {
417 if (target
->rtos
->thread_details
[thread_num
].threadid
== threadid
) {
418 if (target
->rtos
->thread_details
[thread_num
].exists
)
424 gdb_put_packet(connection
, "OK", 2); /* thread alive */
426 gdb_put_packet(connection
, "E01", 3); /* thread not found */
428 } else if (packet
[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for
429 * all other operations ) */
430 if ((packet
[1] == 'g') && (target
->rtos
!= NULL
)) {
432 sscanf(packet
, "Hg%16" SCNx64
, &threadid
);
433 LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64
, threadid
);
434 /* threadid of 0 indicates target should choose */
436 target
->rtos
->current_threadid
= target
->rtos
->current_thread
;
438 target
->rtos
->current_threadid
= threadid
;
440 gdb_put_packet(connection
, "OK", 2);
444 return GDB_THREAD_PACKET_NOT_CONSUMED
;
447 static int rtos_put_gdb_reg_list(struct connection
*connection
,
448 struct rtos_reg
*reg_list
, int num_regs
)
450 size_t num_bytes
= 1; /* NUL */
451 for (int i
= 0; i
< num_regs
; ++i
)
452 num_bytes
+= DIV_ROUND_UP(reg_list
[i
].size
, 8) * 2;
454 char *hex
= malloc(num_bytes
);
457 for (int i
= 0; i
< num_regs
; ++i
) {
458 size_t count
= DIV_ROUND_UP(reg_list
[i
].size
, 8);
459 size_t n
= hexify(hex_p
, reg_list
[i
].value
, count
, num_bytes
);
464 gdb_put_packet(connection
, hex
, strlen(hex
));
470 /** Look through all registers to find this register. */
471 int rtos_get_gdb_reg(struct connection
*connection
, int reg_num
)
473 struct target
*target
= get_target_from_connection(connection
);
474 int64_t current_threadid
= target
->rtos
->current_threadid
;
475 if ((target
->rtos
!= NULL
) && (current_threadid
!= -1) &&
476 (current_threadid
!= 0) &&
477 ((current_threadid
!= target
->rtos
->current_thread
) ||
478 (target
->smp
))) { /* in smp several current thread are possible */
479 struct rtos_reg
*reg_list
;
482 LOG_DEBUG("getting register %d for thread 0x%" PRIx64
483 ", target->rtos->current_thread=0x%" PRIx64
,
486 target
->rtos
->current_thread
);
489 if (target
->rtos
->type
->get_thread_reg
) {
490 reg_list
= calloc(1, sizeof(*reg_list
));
492 retval
= target
->rtos
->type
->get_thread_reg(target
->rtos
,
493 current_threadid
, reg_num
, ®_list
[0]);
494 if (retval
!= ERROR_OK
) {
495 LOG_ERROR("RTOS: failed to get register %d", reg_num
);
499 retval
= target
->rtos
->type
->get_thread_reg_list(target
->rtos
,
503 if (retval
!= ERROR_OK
) {
504 LOG_ERROR("RTOS: failed to get register list");
509 for (int i
= 0; i
< num_regs
; ++i
) {
510 if (reg_list
[i
].number
== (uint32_t)reg_num
) {
511 rtos_put_gdb_reg_list(connection
, reg_list
+ i
, 1);
522 /** Return a list of general registers. */
523 int rtos_get_gdb_reg_list(struct connection
*connection
)
525 struct target
*target
= get_target_from_connection(connection
);
526 int64_t current_threadid
= target
->rtos
->current_threadid
;
527 if ((target
->rtos
!= NULL
) && (current_threadid
!= -1) &&
528 (current_threadid
!= 0) &&
529 ((current_threadid
!= target
->rtos
->current_thread
) ||
530 (target
->smp
))) { /* in smp several current thread are possible */
531 struct rtos_reg
*reg_list
;
534 LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64
535 ", target->rtos->current_thread=0x%" PRIx64
"\r\n",
537 target
->rtos
->current_thread
);
539 int retval
= target
->rtos
->type
->get_thread_reg_list(target
->rtos
,
543 if (retval
!= ERROR_OK
) {
544 LOG_ERROR("RTOS: failed to get register list");
548 rtos_put_gdb_reg_list(connection
, reg_list
, num_regs
);
556 int rtos_set_reg(struct connection
*connection
, int reg_num
,
559 struct target
*target
= get_target_from_connection(connection
);
560 int64_t current_threadid
= target
->rtos
->current_threadid
;
561 if ((target
->rtos
!= NULL
) &&
562 (target
->rtos
->type
->set_reg
!= NULL
) &&
563 (current_threadid
!= -1) &&
564 (current_threadid
!= 0)) {
565 return target
->rtos
->type
->set_reg(target
->rtos
, reg_num
, reg_value
);
570 int rtos_generic_stack_read(struct target
*target
,
571 const struct rtos_register_stacking
*stacking
,
573 struct rtos_reg
**reg_list
,
578 if (stack_ptr
== 0) {
579 LOG_ERROR("Error: null stack pointer in thread");
583 uint8_t *stack_data
= malloc(stacking
->stack_registers_size
);
584 uint32_t address
= stack_ptr
;
586 if (stacking
->stack_growth_direction
== 1)
587 address
-= stacking
->stack_registers_size
;
588 retval
= target_read_buffer(target
, address
, stacking
->stack_registers_size
, stack_data
);
589 if (retval
!= ERROR_OK
) {
591 LOG_ERROR("Error reading stack frame from thread");
594 LOG_DEBUG("RTOS: Read stack frame at 0x%" PRIx32
, address
);
597 LOG_OUTPUT("Stack Data :");
598 for (i
= 0; i
< stacking
->stack_registers_size
; i
++)
599 LOG_OUTPUT("%02X", stack_data
[i
]);
603 int64_t new_stack_ptr
;
604 if (stacking
->calculate_process_stack
!= NULL
) {
605 new_stack_ptr
= stacking
->calculate_process_stack(target
,
606 stack_data
, stacking
, stack_ptr
);
608 new_stack_ptr
= stack_ptr
- stacking
->stack_growth_direction
*
609 stacking
->stack_registers_size
;
612 *reg_list
= calloc(stacking
->num_output_registers
, sizeof(struct rtos_reg
));
613 *num_regs
= stacking
->num_output_registers
;
615 for (int i
= 0; i
< stacking
->num_output_registers
; ++i
) {
616 (*reg_list
)[i
].number
= stacking
->register_offsets
[i
].number
;
617 (*reg_list
)[i
].size
= stacking
->register_offsets
[i
].width_bits
;
619 int offset
= stacking
->register_offsets
[i
].offset
;
621 buf_cpy(&new_stack_ptr
, (*reg_list
)[i
].value
, (*reg_list
)[i
].size
);
622 else if (offset
!= -1)
623 buf_cpy(stack_data
+ offset
, (*reg_list
)[i
].value
, (*reg_list
)[i
].size
);
627 /* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
631 int rtos_try_next(struct target
*target
)
633 struct rtos
*os
= target
->rtos
;
634 struct rtos_type
**type
= rtos_types
;
639 while (*type
&& os
->type
!= *type
)
642 if (!*type
|| !*(++type
))
654 int rtos_update_threads(struct target
*target
)
656 if ((target
->rtos
!= NULL
) && (target
->rtos
->type
!= NULL
))
657 target
->rtos
->type
->update_threads(target
->rtos
);
661 void rtos_free_threadlist(struct rtos
*rtos
)
663 if (rtos
->thread_details
) {
666 for (j
= 0; j
< rtos
->thread_count
; j
++) {
667 struct thread_detail
*current_thread
= &rtos
->thread_details
[j
];
668 free(current_thread
->thread_name_str
);
669 free(current_thread
->extra_info_str
);
671 free(rtos
->thread_details
);
672 rtos
->thread_details
= NULL
;
673 rtos
->thread_count
= 0;
674 rtos
->current_threadid
= -1;
675 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)