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
;
38 static struct rtos_type
*rtos_types
[] = {
49 int rtos_thread_packet(struct connection
*connection
, const char *packet
, int packet_size
);
51 int rtos_smp_init(struct target
*target
)
53 if (target
->rtos
->type
->smp_init
)
54 return target
->rtos
->type
->smp_init(target
);
55 return ERROR_TARGET_INIT_FAILED
;
58 static int os_alloc(struct target
*target
, struct rtos_type
*ostype
)
60 struct rtos
*os
= target
->rtos
= calloc(1, sizeof(struct rtos
));
66 os
->current_threadid
= -1;
67 os
->current_thread
= 0;
71 /* RTOS drivers can override the packet handler in _create(). */
72 os
->gdb_thread_packet
= rtos_thread_packet
;
77 static void os_free(struct target
*target
)
82 if (target
->rtos
->symbols
)
83 free(target
->rtos
->symbols
);
89 static int os_alloc_create(struct target
*target
, struct rtos_type
*ostype
)
91 int ret
= os_alloc(target
, ostype
);
94 ret
= target
->rtos
->type
->create(target
);
102 int rtos_create(Jim_GetOptInfo
*goi
, struct target
*target
)
108 if (!goi
->isconfigure
&& goi
->argc
!= 0) {
109 Jim_WrongNumArgs(goi
->interp
, goi
->argc
, goi
->argv
, "NO PARAMS");
115 Jim_GetOpt_String(goi
, &cp
, NULL
);
117 if (0 == strcmp(cp
, "auto")) {
118 /* Auto detect tries to look up all symbols for each RTOS,
119 * and runs the RTOS driver's _detect() function when GDB
120 * finds all symbols for any RTOS. See rtos_qsymbol(). */
121 target
->rtos_auto_detect
= true;
123 /* rtos_qsymbol() will iterate over all RTOSes. Allocate
124 * target->rtos here, and set it to the first RTOS type. */
125 return os_alloc(target
, rtos_types
[0]);
128 for (x
= 0; rtos_types
[x
]; x
++)
129 if (0 == strcmp(cp
, rtos_types
[x
]->name
))
130 return os_alloc_create(target
, rtos_types
[x
]);
132 Jim_SetResultFormatted(goi
->interp
, "Unknown RTOS type %s, try one of: ", cp
);
133 res
= Jim_GetResult(goi
->interp
);
134 for (x
= 0; rtos_types
[x
]; x
++)
135 Jim_AppendStrings(goi
->interp
, res
, rtos_types
[x
]->name
, ", ", NULL
);
136 Jim_AppendStrings(goi
->interp
, res
, " or auto", NULL
);
141 int gdb_thread_packet(struct connection
*connection
, char const *packet
, int packet_size
)
143 struct target
*target
= get_target_from_connection(connection
);
144 if (target
->rtos
== NULL
)
145 return rtos_thread_packet(connection
, packet
, packet_size
); /* thread not
147 return target
->rtos
->gdb_thread_packet(connection
, packet
, packet_size
);
150 static symbol_table_elem_t
*next_symbol(struct rtos
*os
, char *cur_symbol
, uint64_t cur_addr
)
152 symbol_table_elem_t
*s
;
155 os
->type
->get_symbol_list_to_lookup(&os
->symbols
);
158 return &os
->symbols
[0];
160 for (s
= os
->symbols
; s
->symbol_name
; s
++)
161 if (!strcmp(s
->symbol_name
, cur_symbol
)) {
162 s
->address
= cur_addr
;
170 /* searches for 'symbol' in the lookup table for 'os' and returns TRUE,
171 * if 'symbol' is not declared optional */
172 static bool is_symbol_mandatory(const struct rtos
*os
, const char *symbol
)
174 for (symbol_table_elem_t
*s
= os
->symbols
; s
->symbol_name
; ++s
) {
175 if (!strcmp(s
->symbol_name
, symbol
))
181 /* rtos_qsymbol() processes and replies to all qSymbol packets from GDB.
183 * GDB sends a qSymbol:: packet (empty address, empty name) to notify
184 * that it can now answer qSymbol::hexcodedname queries, to look up symbols.
186 * If the qSymbol packet has no address that means GDB did not find the
187 * symbol, in which case auto-detect will move on to try the next RTOS.
189 * rtos_qsymbol() then calls the next_symbol() helper function, which
190 * iterates over symbol names for the current RTOS until it finds the
191 * symbol in the received GDB packet, and then returns the next entry
192 * in the list of symbols.
194 * If GDB replied about the last symbol for the RTOS and the RTOS was
195 * specified explicitly, then no further symbol lookup is done. When
196 * auto-detecting, the RTOS driver _detect() function must return success.
198 * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise.
200 int rtos_qsymbol(struct connection
*connection
, char const *packet
, int packet_size
)
202 int rtos_detected
= 0;
205 char reply
[GDB_BUFFER_SIZE
], cur_sym
[GDB_BUFFER_SIZE
/ 2] = "";
206 symbol_table_elem_t
*next_sym
= NULL
;
207 struct target
*target
= get_target_from_connection(connection
);
208 struct rtos
*os
= target
->rtos
;
210 reply_len
= sprintf(reply
, "OK");
215 /* Decode any symbol name in the packet*/
216 size_t len
= unhexify((uint8_t *)cur_sym
, strchr(packet
+ 8, ':') + 1, strlen(strchr(packet
+ 8, ':') + 1));
219 if ((strcmp(packet
, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */
220 (!sscanf(packet
, "qSymbol:%" SCNx64
":", &addr
)) && /* GDB did not find an address for a symbol */
221 is_symbol_mandatory(os
, cur_sym
)) { /* the symbol is mandatory for this RTOS */
223 /* GDB could not find an address for the previous symbol */
224 if (!target
->rtos_auto_detect
) {
225 LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os
->type
->name
, cur_sym
);
228 /* Autodetecting RTOS - try next RTOS */
229 if (!rtos_try_next(target
)) {
230 LOG_WARNING("No RTOS could be auto-detected!");
234 /* Next RTOS selected - invalidate current symbol */
238 next_sym
= next_symbol(os
, cur_sym
, addr
);
240 if (!next_sym
->symbol_name
) {
241 /* No more symbols need looking up */
243 if (!target
->rtos_auto_detect
) {
248 if (os
->type
->detect_rtos(target
)) {
249 LOG_INFO("Auto-detected RTOS: %s", os
->type
->name
);
253 LOG_WARNING("No RTOS could be auto-detected!");
258 if (8 + (strlen(next_sym
->symbol_name
) * 2) + 1 > sizeof(reply
)) {
259 LOG_ERROR("ERROR: RTOS symbol '%s' name is too long for GDB!", next_sym
->symbol_name
);
263 reply_len
= snprintf(reply
, sizeof(reply
), "qSymbol:");
264 reply_len
+= hexify(reply
+ reply_len
, next_sym
->symbol_name
, 0, sizeof(reply
) - reply_len
);
267 gdb_put_packet(connection
, reply
, reply_len
);
268 return rtos_detected
;
271 int rtos_thread_packet(struct connection
*connection
, char const *packet
, int packet_size
)
273 struct target
*target
= get_target_from_connection(connection
);
275 if (strncmp(packet
, "qThreadExtraInfo,", 17) == 0) {
276 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
) &&
277 (target
->rtos
->thread_count
!= 0)) {
278 threadid_t threadid
= 0;
280 sscanf(packet
, "qThreadExtraInfo,%" SCNx64
, &threadid
);
282 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
)) {
284 for (thread_num
= 0; thread_num
< target
->rtos
->thread_count
; thread_num
++) {
285 if (target
->rtos
->thread_details
[thread_num
].threadid
== threadid
) {
286 if (target
->rtos
->thread_details
[thread_num
].exists
)
292 gdb_put_packet(connection
, "E01", 3); /* thread not found */
296 struct thread_detail
*detail
= &target
->rtos
->thread_details
[found
];
299 if (detail
->thread_name_str
!= NULL
)
300 str_size
+= strlen(detail
->thread_name_str
);
301 if (detail
->extra_info_str
!= NULL
)
302 str_size
+= strlen(detail
->extra_info_str
);
304 char *tmp_str
= calloc(str_size
+ 4, sizeof(char));
305 char *tmp_str_ptr
= tmp_str
;
307 if (detail
->thread_name_str
!= NULL
)
308 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%s", detail
->thread_name_str
);
309 if (detail
->extra_info_str
!= NULL
) {
310 if (tmp_str_ptr
!= tmp_str
)
311 tmp_str_ptr
+= sprintf(tmp_str_ptr
, " : ");
312 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%s", detail
->extra_info_str
);
315 assert(strlen(tmp_str
) ==
316 (size_t) (tmp_str_ptr
- tmp_str
));
318 char *hex_str
= malloc(strlen(tmp_str
) * 2 + 1);
319 int pkt_len
= hexify(hex_str
, tmp_str
, 0, strlen(tmp_str
) * 2 + 1);
321 gdb_put_packet(connection
, hex_str
, pkt_len
);
327 gdb_put_packet(connection
, "", 0);
329 } else if (strncmp(packet
, "qSymbol", 7) == 0) {
330 if (rtos_qsymbol(connection
, packet
, packet_size
) == 1) {
331 target
->rtos_auto_detect
= false;
332 target
->rtos
->type
->create(target
);
333 target
->rtos
->type
->update_threads(target
->rtos
);
336 } else if (strncmp(packet
, "qfThreadInfo", 12) == 0) {
338 if (target
->rtos
!= NULL
) {
339 if (target
->rtos
->thread_count
== 0) {
340 gdb_put_packet(connection
, "l", 1);
342 /*thread id are 16 char +1 for ',' */
343 char *out_str
= malloc(17 * target
->rtos
->thread_count
+ 1);
344 char *tmp_str
= out_str
;
345 for (i
= 0; i
< target
->rtos
->thread_count
; i
++) {
346 tmp_str
+= sprintf(tmp_str
, "%c%016" PRIx64
, i
== 0 ? 'm' : ',',
347 target
->rtos
->thread_details
[i
].threadid
);
349 gdb_put_packet(connection
, out_str
, strlen(out_str
));
353 gdb_put_packet(connection
, "l", 1);
356 } else if (strncmp(packet
, "qsThreadInfo", 12) == 0) {
357 gdb_put_packet(connection
, "l", 1);
359 } else if (strncmp(packet
, "qAttached", 9) == 0) {
360 gdb_put_packet(connection
, "1", 1);
362 } else if (strncmp(packet
, "qOffsets", 8) == 0) {
363 char offsets
[] = "Text=0;Data=0;Bss=0";
364 gdb_put_packet(connection
, offsets
, sizeof(offsets
)-1);
366 } else if (strncmp(packet
, "qCRC:", 5) == 0) {
367 /* make sure we check this before "qC" packet below
368 * otherwise it gets incorrectly handled */
369 return GDB_THREAD_PACKET_NOT_CONSUMED
;
370 } else if (strncmp(packet
, "qC", 2) == 0) {
371 if (target
->rtos
!= NULL
) {
374 size
= snprintf(buffer
, 19, "QC%016" PRIx64
, target
->rtos
->current_thread
);
375 gdb_put_packet(connection
, buffer
, size
);
377 gdb_put_packet(connection
, "QC0", 3);
379 } else if (packet
[0] == 'T') { /* Is thread alive? */
382 sscanf(packet
, "T%" SCNx64
, &threadid
);
383 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
)) {
385 for (thread_num
= 0; thread_num
< target
->rtos
->thread_count
; thread_num
++) {
386 if (target
->rtos
->thread_details
[thread_num
].threadid
== threadid
) {
387 if (target
->rtos
->thread_details
[thread_num
].exists
)
393 gdb_put_packet(connection
, "OK", 2); /* thread alive */
395 gdb_put_packet(connection
, "E01", 3); /* thread not found */
397 } else if (packet
[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for
398 * all other operations ) */
399 if ((packet
[1] == 'g') && (target
->rtos
!= NULL
)) {
400 sscanf(packet
, "Hg%16" SCNx64
, &target
->rtos
->current_threadid
);
401 LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64
"\r\n",
402 target
->rtos
->current_threadid
);
404 gdb_put_packet(connection
, "OK", 2);
408 return GDB_THREAD_PACKET_NOT_CONSUMED
;
411 int rtos_get_gdb_reg_list(struct connection
*connection
)
413 struct target
*target
= get_target_from_connection(connection
);
414 int64_t current_threadid
= target
->rtos
->current_threadid
;
415 if ((target
->rtos
!= NULL
) && (current_threadid
!= -1) &&
416 (current_threadid
!= 0) &&
417 ((current_threadid
!= target
->rtos
->current_thread
) ||
418 (target
->smp
))) { /* in smp several current thread are possible */
421 LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64
422 ", target->rtos->current_thread=0x%" PRIx64
"\r\n",
424 target
->rtos
->current_thread
);
426 target
->rtos
->type
->get_thread_reg_list(target
->rtos
,
430 if (hex_reg_list
!= NULL
) {
431 gdb_put_packet(connection
, hex_reg_list
, strlen(hex_reg_list
));
439 int rtos_generic_stack_read(struct target
*target
,
440 const struct rtos_register_stacking
*stacking
,
446 int64_t new_stack_ptr
;
450 if (stack_ptr
== 0) {
451 LOG_ERROR("Error: null stack pointer in thread");
455 uint8_t *stack_data
= malloc(stacking
->stack_registers_size
);
456 uint32_t address
= stack_ptr
;
458 if (stacking
->stack_growth_direction
== 1)
459 address
-= stacking
->stack_registers_size
;
460 retval
= target_read_buffer(target
, address
, stacking
->stack_registers_size
, stack_data
);
461 if (retval
!= ERROR_OK
) {
463 LOG_ERROR("Error reading stack frame from thread");
466 LOG_DEBUG("RTOS: Read stack frame at 0x%" PRIx32
, address
);
469 LOG_OUTPUT("Stack Data :");
470 for (i
= 0; i
< stacking
->stack_registers_size
; i
++)
471 LOG_OUTPUT("%02X", stack_data
[i
]);
474 for (i
= 0; i
< stacking
->num_output_registers
; i
++)
475 list_size
+= stacking
->register_offsets
[i
].width_bits
/8;
476 *hex_reg_list
= malloc(list_size
*2 + 1);
477 tmp_str_ptr
= *hex_reg_list
;
478 if (stacking
->calculate_process_stack
!= NULL
) {
479 new_stack_ptr
= stacking
->calculate_process_stack(target
,
480 stack_data
, stacking
, stack_ptr
);
482 new_stack_ptr
= stack_ptr
- stacking
->stack_growth_direction
*
483 stacking
->stack_registers_size
;
485 for (i
= 0; i
< stacking
->num_output_registers
; i
++) {
487 for (j
= 0; j
< stacking
->register_offsets
[i
].width_bits
/8; j
++) {
488 if (stacking
->register_offsets
[i
].offset
== -1)
489 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%02x", 0);
490 else if (stacking
->register_offsets
[i
].offset
== -2)
491 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%02x",
492 ((uint8_t *)&new_stack_ptr
)[j
]);
494 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%02x",
495 stack_data
[stacking
->register_offsets
[i
].offset
+ j
]);
499 /* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
503 int rtos_try_next(struct target
*target
)
505 struct rtos
*os
= target
->rtos
;
506 struct rtos_type
**type
= rtos_types
;
511 while (*type
&& os
->type
!= *type
)
514 if (!*type
|| !*(++type
))
526 int rtos_update_threads(struct target
*target
)
528 if ((target
->rtos
!= NULL
) && (target
->rtos
->type
!= NULL
))
529 target
->rtos
->type
->update_threads(target
->rtos
);
533 void rtos_free_threadlist(struct rtos
*rtos
)
535 if (rtos
->thread_details
) {
538 for (j
= 0; j
< rtos
->thread_count
; j
++) {
539 struct thread_detail
*current_thread
= &rtos
->thread_details
[j
];
540 free(current_thread
->thread_name_str
);
541 free(current_thread
->extra_info_str
);
543 free(rtos
->thread_details
);
544 rtos
->thread_details
= NULL
;
545 rtos
->thread_count
= 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)