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 embKernel_rtos
;
36 extern struct rtos_type mqx_rtos
;
37 extern struct rtos_type uCOS_III_rtos
;
39 static struct rtos_type
*rtos_types
[] = {
51 int rtos_thread_packet(struct connection
*connection
, const char *packet
, int packet_size
);
53 int rtos_smp_init(struct target
*target
)
55 if (target
->rtos
->type
->smp_init
)
56 return target
->rtos
->type
->smp_init(target
);
57 return ERROR_TARGET_INIT_FAILED
;
60 static int os_alloc(struct target
*target
, struct rtos_type
*ostype
)
62 struct rtos
*os
= target
->rtos
= calloc(1, sizeof(struct rtos
));
68 os
->current_threadid
= -1;
69 os
->current_thread
= 0;
73 /* RTOS drivers can override the packet handler in _create(). */
74 os
->gdb_thread_packet
= rtos_thread_packet
;
79 static void os_free(struct target
*target
)
84 if (target
->rtos
->symbols
)
85 free(target
->rtos
->symbols
);
91 static int os_alloc_create(struct target
*target
, struct rtos_type
*ostype
)
93 int ret
= os_alloc(target
, ostype
);
96 ret
= target
->rtos
->type
->create(target
);
104 int rtos_create(Jim_GetOptInfo
*goi
, struct target
*target
)
111 if (!goi
->isconfigure
&& goi
->argc
!= 0) {
112 Jim_WrongNumArgs(goi
->interp
, goi
->argc
, goi
->argv
, "NO PARAMS");
118 e
= Jim_GetOpt_String(goi
, &cp
, NULL
);
122 if (0 == strcmp(cp
, "auto")) {
123 /* Auto detect tries to look up all symbols for each RTOS,
124 * and runs the RTOS driver's _detect() function when GDB
125 * finds all symbols for any RTOS. See rtos_qsymbol(). */
126 target
->rtos_auto_detect
= true;
128 /* rtos_qsymbol() will iterate over all RTOSes. Allocate
129 * target->rtos here, and set it to the first RTOS type. */
130 return os_alloc(target
, rtos_types
[0]);
133 for (x
= 0; rtos_types
[x
]; x
++)
134 if (0 == strcmp(cp
, rtos_types
[x
]->name
))
135 return os_alloc_create(target
, rtos_types
[x
]);
137 Jim_SetResultFormatted(goi
->interp
, "Unknown RTOS type %s, try one of: ", cp
);
138 res
= Jim_GetResult(goi
->interp
);
139 for (x
= 0; rtos_types
[x
]; x
++)
140 Jim_AppendStrings(goi
->interp
, res
, rtos_types
[x
]->name
, ", ", NULL
);
141 Jim_AppendStrings(goi
->interp
, res
, " or auto", NULL
);
146 int gdb_thread_packet(struct connection
*connection
, char const *packet
, int packet_size
)
148 struct target
*target
= get_target_from_connection(connection
);
149 if (target
->rtos
== NULL
)
150 return rtos_thread_packet(connection
, packet
, packet_size
); /* thread not
152 return target
->rtos
->gdb_thread_packet(connection
, packet
, packet_size
);
155 static symbol_table_elem_t
*next_symbol(struct rtos
*os
, char *cur_symbol
, uint64_t cur_addr
)
157 symbol_table_elem_t
*s
;
160 os
->type
->get_symbol_list_to_lookup(&os
->symbols
);
163 return &os
->symbols
[0];
165 for (s
= os
->symbols
; s
->symbol_name
; s
++)
166 if (!strcmp(s
->symbol_name
, cur_symbol
)) {
167 s
->address
= cur_addr
;
175 /* searches for 'symbol' in the lookup table for 'os' and returns TRUE,
176 * if 'symbol' is not declared optional */
177 static bool is_symbol_mandatory(const struct rtos
*os
, const char *symbol
)
179 for (symbol_table_elem_t
*s
= os
->symbols
; s
->symbol_name
; ++s
) {
180 if (!strcmp(s
->symbol_name
, symbol
))
186 /* rtos_qsymbol() processes and replies to all qSymbol packets from GDB.
188 * GDB sends a qSymbol:: packet (empty address, empty name) to notify
189 * that it can now answer qSymbol::hexcodedname queries, to look up symbols.
191 * If the qSymbol packet has no address that means GDB did not find the
192 * symbol, in which case auto-detect will move on to try the next RTOS.
194 * rtos_qsymbol() then calls the next_symbol() helper function, which
195 * iterates over symbol names for the current RTOS until it finds the
196 * symbol in the received GDB packet, and then returns the next entry
197 * in the list of symbols.
199 * If GDB replied about the last symbol for the RTOS and the RTOS was
200 * specified explicitly, then no further symbol lookup is done. When
201 * auto-detecting, the RTOS driver _detect() function must return success.
203 * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise.
205 int rtos_qsymbol(struct connection
*connection
, char const *packet
, int packet_size
)
207 int rtos_detected
= 0;
210 char reply
[GDB_BUFFER_SIZE
], cur_sym
[GDB_BUFFER_SIZE
/ 2] = "";
211 symbol_table_elem_t
*next_sym
= NULL
;
212 struct target
*target
= get_target_from_connection(connection
);
213 struct rtos
*os
= target
->rtos
;
215 reply_len
= sprintf(reply
, "OK");
220 /* Decode any symbol name in the packet*/
221 size_t len
= unhexify((uint8_t *)cur_sym
, strchr(packet
+ 8, ':') + 1, strlen(strchr(packet
+ 8, ':') + 1));
224 if ((strcmp(packet
, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */
225 (!sscanf(packet
, "qSymbol:%" SCNx64
":", &addr
)) && /* GDB did not find an address for a symbol */
226 is_symbol_mandatory(os
, cur_sym
)) { /* the symbol is mandatory for this RTOS */
228 /* GDB could not find an address for the previous symbol */
229 if (!target
->rtos_auto_detect
) {
230 LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os
->type
->name
, cur_sym
);
233 /* Autodetecting RTOS - try next RTOS */
234 if (!rtos_try_next(target
)) {
235 LOG_WARNING("No RTOS could be auto-detected!");
239 /* Next RTOS selected - invalidate current symbol */
243 next_sym
= next_symbol(os
, cur_sym
, addr
);
245 if (!next_sym
->symbol_name
) {
246 /* No more symbols need looking up */
248 if (!target
->rtos_auto_detect
) {
253 if (os
->type
->detect_rtos(target
)) {
254 LOG_INFO("Auto-detected RTOS: %s", os
->type
->name
);
258 LOG_WARNING("No RTOS could be auto-detected!");
263 if (8 + (strlen(next_sym
->symbol_name
) * 2) + 1 > sizeof(reply
)) {
264 LOG_ERROR("ERROR: RTOS symbol '%s' name is too long for GDB!", next_sym
->symbol_name
);
268 reply_len
= snprintf(reply
, sizeof(reply
), "qSymbol:");
269 reply_len
+= hexify(reply
+ reply_len
, next_sym
->symbol_name
, 0, sizeof(reply
) - reply_len
);
272 gdb_put_packet(connection
, reply
, reply_len
);
273 return rtos_detected
;
276 int rtos_thread_packet(struct connection
*connection
, char const *packet
, int packet_size
)
278 struct target
*target
= get_target_from_connection(connection
);
280 if (strncmp(packet
, "qThreadExtraInfo,", 17) == 0) {
281 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
) &&
282 (target
->rtos
->thread_count
!= 0)) {
283 threadid_t threadid
= 0;
285 sscanf(packet
, "qThreadExtraInfo,%" SCNx64
, &threadid
);
287 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
)) {
289 for (thread_num
= 0; thread_num
< target
->rtos
->thread_count
; thread_num
++) {
290 if (target
->rtos
->thread_details
[thread_num
].threadid
== threadid
) {
291 if (target
->rtos
->thread_details
[thread_num
].exists
)
297 gdb_put_packet(connection
, "E01", 3); /* thread not found */
301 struct thread_detail
*detail
= &target
->rtos
->thread_details
[found
];
304 if (detail
->thread_name_str
!= NULL
)
305 str_size
+= strlen(detail
->thread_name_str
);
306 if (detail
->extra_info_str
!= NULL
)
307 str_size
+= strlen(detail
->extra_info_str
);
309 char *tmp_str
= calloc(str_size
+ 9, sizeof(char));
310 char *tmp_str_ptr
= tmp_str
;
312 if (detail
->thread_name_str
!= NULL
)
313 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "Name: %s", detail
->thread_name_str
);
314 if (detail
->extra_info_str
!= NULL
) {
315 if (tmp_str_ptr
!= tmp_str
)
316 tmp_str_ptr
+= sprintf(tmp_str_ptr
, ", ");
317 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%s", detail
->extra_info_str
);
320 assert(strlen(tmp_str
) ==
321 (size_t) (tmp_str_ptr
- tmp_str
));
323 char *hex_str
= malloc(strlen(tmp_str
) * 2 + 1);
324 int pkt_len
= hexify(hex_str
, tmp_str
, 0, strlen(tmp_str
) * 2 + 1);
326 gdb_put_packet(connection
, hex_str
, pkt_len
);
332 gdb_put_packet(connection
, "", 0);
334 } else if (strncmp(packet
, "qSymbol", 7) == 0) {
335 if (rtos_qsymbol(connection
, packet
, packet_size
) == 1) {
336 target
->rtos_auto_detect
= false;
337 target
->rtos
->type
->create(target
);
338 target
->rtos
->type
->update_threads(target
->rtos
);
341 } else if (strncmp(packet
, "qfThreadInfo", 12) == 0) {
343 if (target
->rtos
!= NULL
) {
344 if (target
->rtos
->thread_count
== 0) {
345 gdb_put_packet(connection
, "l", 1);
347 /*thread id are 16 char +1 for ',' */
348 char *out_str
= malloc(17 * target
->rtos
->thread_count
+ 1);
349 char *tmp_str
= out_str
;
350 for (i
= 0; i
< target
->rtos
->thread_count
; i
++) {
351 tmp_str
+= sprintf(tmp_str
, "%c%016" PRIx64
, i
== 0 ? 'm' : ',',
352 target
->rtos
->thread_details
[i
].threadid
);
354 gdb_put_packet(connection
, out_str
, strlen(out_str
));
358 gdb_put_packet(connection
, "l", 1);
361 } else if (strncmp(packet
, "qsThreadInfo", 12) == 0) {
362 gdb_put_packet(connection
, "l", 1);
364 } else if (strncmp(packet
, "qAttached", 9) == 0) {
365 gdb_put_packet(connection
, "1", 1);
367 } else if (strncmp(packet
, "qOffsets", 8) == 0) {
368 char offsets
[] = "Text=0;Data=0;Bss=0";
369 gdb_put_packet(connection
, offsets
, sizeof(offsets
)-1);
371 } else if (strncmp(packet
, "qCRC:", 5) == 0) {
372 /* make sure we check this before "qC" packet below
373 * otherwise it gets incorrectly handled */
374 return GDB_THREAD_PACKET_NOT_CONSUMED
;
375 } else if (strncmp(packet
, "qC", 2) == 0) {
376 if (target
->rtos
!= NULL
) {
379 size
= snprintf(buffer
, 19, "QC%016" PRIx64
, target
->rtos
->current_thread
);
380 gdb_put_packet(connection
, buffer
, size
);
382 gdb_put_packet(connection
, "QC0", 3);
384 } else if (packet
[0] == 'T') { /* Is thread alive? */
387 sscanf(packet
, "T%" SCNx64
, &threadid
);
388 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
)) {
390 for (thread_num
= 0; thread_num
< target
->rtos
->thread_count
; thread_num
++) {
391 if (target
->rtos
->thread_details
[thread_num
].threadid
== threadid
) {
392 if (target
->rtos
->thread_details
[thread_num
].exists
)
398 gdb_put_packet(connection
, "OK", 2); /* thread alive */
400 gdb_put_packet(connection
, "E01", 3); /* thread not found */
402 } else if (packet
[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for
403 * all other operations ) */
404 if ((packet
[1] == 'g') && (target
->rtos
!= NULL
)) {
406 sscanf(packet
, "Hg%16" SCNx64
, &threadid
);
407 LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64
, threadid
);
408 /* threadid of 0 indicates target should choose */
410 target
->rtos
->current_threadid
= target
->rtos
->current_thread
;
412 target
->rtos
->current_threadid
= threadid
;
414 gdb_put_packet(connection
, "OK", 2);
418 return GDB_THREAD_PACKET_NOT_CONSUMED
;
421 int rtos_get_gdb_reg_list(struct connection
*connection
)
423 struct target
*target
= get_target_from_connection(connection
);
424 int64_t current_threadid
= target
->rtos
->current_threadid
;
425 if ((target
->rtos
!= NULL
) && (current_threadid
!= -1) &&
426 (current_threadid
!= 0) &&
427 ((current_threadid
!= target
->rtos
->current_thread
) ||
428 (target
->smp
))) { /* in smp several current thread are possible */
431 LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64
432 ", target->rtos->current_thread=0x%" PRIx64
"\r\n",
434 target
->rtos
->current_thread
);
436 int retval
= target
->rtos
->type
->get_thread_reg_list(target
->rtos
,
439 if (retval
!= ERROR_OK
) {
440 LOG_ERROR("RTOS: failed to get register list");
444 if (hex_reg_list
!= NULL
) {
445 gdb_put_packet(connection
, hex_reg_list
, strlen(hex_reg_list
));
453 int rtos_generic_stack_read(struct target
*target
,
454 const struct rtos_register_stacking
*stacking
,
460 int64_t new_stack_ptr
;
464 if (stack_ptr
== 0) {
465 LOG_ERROR("Error: null stack pointer in thread");
469 uint8_t *stack_data
= malloc(stacking
->stack_registers_size
);
470 uint32_t address
= stack_ptr
;
472 if (stacking
->stack_growth_direction
== 1)
473 address
-= stacking
->stack_registers_size
;
474 retval
= target_read_buffer(target
, address
, stacking
->stack_registers_size
, stack_data
);
475 if (retval
!= ERROR_OK
) {
477 LOG_ERROR("Error reading stack frame from thread");
480 LOG_DEBUG("RTOS: Read stack frame at 0x%" PRIx32
, address
);
483 LOG_OUTPUT("Stack Data :");
484 for (i
= 0; i
< stacking
->stack_registers_size
; i
++)
485 LOG_OUTPUT("%02X", stack_data
[i
]);
488 for (i
= 0; i
< stacking
->num_output_registers
; i
++)
489 list_size
+= stacking
->register_offsets
[i
].width_bits
/8;
490 *hex_reg_list
= malloc(list_size
*2 + 1);
491 tmp_str_ptr
= *hex_reg_list
;
492 if (stacking
->calculate_process_stack
!= NULL
) {
493 new_stack_ptr
= stacking
->calculate_process_stack(target
,
494 stack_data
, stacking
, stack_ptr
);
496 new_stack_ptr
= stack_ptr
- stacking
->stack_growth_direction
*
497 stacking
->stack_registers_size
;
499 for (i
= 0; i
< stacking
->num_output_registers
; i
++) {
501 for (j
= 0; j
< stacking
->register_offsets
[i
].width_bits
/8; j
++) {
502 if (stacking
->register_offsets
[i
].offset
== -1)
503 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%02x", 0);
504 else if (stacking
->register_offsets
[i
].offset
== -2)
505 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%02x",
506 ((uint8_t *)&new_stack_ptr
)[j
]);
508 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%02x",
509 stack_data
[stacking
->register_offsets
[i
].offset
+ j
]);
513 /* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
517 int rtos_try_next(struct target
*target
)
519 struct rtos
*os
= target
->rtos
;
520 struct rtos_type
**type
= rtos_types
;
525 while (*type
&& os
->type
!= *type
)
528 if (!*type
|| !*(++type
))
540 int rtos_update_threads(struct target
*target
)
542 if ((target
->rtos
!= NULL
) && (target
->rtos
->type
!= NULL
))
543 target
->rtos
->type
->update_threads(target
->rtos
);
547 void rtos_free_threadlist(struct rtos
*rtos
)
549 if (rtos
->thread_details
) {
552 for (j
= 0; j
< rtos
->thread_count
; j
++) {
553 struct thread_detail
*current_thread
= &rtos
->thread_details
[j
];
554 free(current_thread
->thread_name_str
);
555 free(current_thread
->extra_info_str
);
557 free(rtos
->thread_details
);
558 rtos
->thread_details
= NULL
;
559 rtos
->thread_count
= 0;
560 rtos
->current_threadid
= -1;
561 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)