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, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
26 #include "target/target.h"
27 #include "helper/log.h"
28 #include "helper/binarybuffer.h"
29 #include "server/gdb_server.h"
32 extern struct rtos_type FreeRTOS_rtos
;
33 extern struct rtos_type ThreadX_rtos
;
34 extern struct rtos_type eCos_rtos
;
35 extern struct rtos_type Linux_os
;
36 extern struct rtos_type ChibiOS_rtos
;
37 extern struct rtos_type embKernel_rtos
;
38 extern struct rtos_type mqx_rtos
;
40 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
)
110 if (!goi
->isconfigure
&& goi
->argc
!= 0) {
111 Jim_WrongNumArgs(goi
->interp
, goi
->argc
, goi
->argv
, "NO PARAMS");
117 Jim_GetOpt_String(goi
, &cp
, NULL
);
119 if (0 == strcmp(cp
, "auto")) {
120 /* Auto detect tries to look up all symbols for each RTOS,
121 * and runs the RTOS driver's _detect() function when GDB
122 * finds all symbols for any RTOS. See rtos_qsymbol(). */
123 target
->rtos_auto_detect
= true;
125 /* rtos_qsymbol() will iterate over all RTOSes. Allocate
126 * target->rtos here, and set it to the first RTOS type. */
127 return os_alloc(target
, rtos_types
[0]);
130 for (x
= 0; rtos_types
[x
]; x
++)
131 if (0 == strcmp(cp
, rtos_types
[x
]->name
))
132 return os_alloc_create(target
, rtos_types
[x
]);
134 Jim_SetResultFormatted(goi
->interp
, "Unknown RTOS type %s, try one of: ", cp
);
135 res
= Jim_GetResult(goi
->interp
);
136 for (x
= 0; rtos_types
[x
]; x
++)
137 Jim_AppendStrings(goi
->interp
, res
, rtos_types
[x
]->name
, ", ", NULL
);
138 Jim_AppendStrings(goi
->interp
, res
, " or auto", NULL
);
143 int gdb_thread_packet(struct connection
*connection
, char const *packet
, int packet_size
)
145 struct target
*target
= get_target_from_connection(connection
);
146 if (target
->rtos
== NULL
)
147 return rtos_thread_packet(connection
, packet
, packet_size
); /* thread not
149 return target
->rtos
->gdb_thread_packet(connection
, packet
, packet_size
);
152 static symbol_table_elem_t
*next_symbol(struct rtos
*os
, char *cur_symbol
, uint64_t cur_addr
)
154 symbol_table_elem_t
*s
;
157 os
->type
->get_symbol_list_to_lookup(&os
->symbols
);
160 return &os
->symbols
[0];
162 for (s
= os
->symbols
; s
->symbol_name
; s
++)
163 if (!strcmp(s
->symbol_name
, cur_symbol
)) {
164 s
->address
= cur_addr
;
172 /* searches for 'symbol' in the lookup table for 'os' and returns TRUE,
173 * if 'symbol' is not declared optional */
174 static bool is_symbol_mandatory(const struct rtos
*os
, const char *symbol
)
176 for (symbol_table_elem_t
*s
= os
->symbols
; s
->symbol_name
; ++s
) {
177 if (!strcmp(s
->symbol_name
, symbol
))
183 /* rtos_qsymbol() processes and replies to all qSymbol packets from GDB.
185 * GDB sends a qSymbol:: packet (empty address, empty name) to notify
186 * that it can now answer qSymbol::hexcodedname queries, to look up symbols.
188 * If the qSymbol packet has no address that means GDB did not find the
189 * symbol, in which case auto-detect will move on to try the next RTOS.
191 * rtos_qsymbol() then calls the next_symbol() helper function, which
192 * iterates over symbol names for the current RTOS until it finds the
193 * symbol in the received GDB packet, and then returns the next entry
194 * in the list of symbols.
196 * If GDB replied about the last symbol for the RTOS and the RTOS was
197 * specified explicitly, then no further symbol lookup is done. When
198 * auto-detecting, the RTOS driver _detect() function must return success.
200 * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise.
202 int rtos_qsymbol(struct connection
*connection
, char const *packet
, int packet_size
)
204 int rtos_detected
= 0;
207 char reply
[GDB_BUFFER_SIZE
], cur_sym
[GDB_BUFFER_SIZE
/ 2] = "";
208 symbol_table_elem_t
*next_sym
= NULL
;
209 struct target
*target
= get_target_from_connection(connection
);
210 struct rtos
*os
= target
->rtos
;
212 reply_len
= sprintf(reply
, "OK");
217 /* Decode any symbol name in the packet*/
218 int len
= unhexify(cur_sym
, strchr(packet
+ 8, ':') + 1, strlen(strchr(packet
+ 8, ':') + 1));
221 if ((strcmp(packet
, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */
222 (!sscanf(packet
, "qSymbol:%" SCNx64
":", &addr
)) && /* GDB did not find an address for a symbol */
223 is_symbol_mandatory(os
, cur_sym
)) { /* the symbol is mandatory for this RTOS */
225 /* GDB could not find an address for the previous symbol */
226 if (!target
->rtos_auto_detect
) {
227 LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os
->type
->name
, cur_sym
);
230 /* Autodetecting RTOS - try next RTOS */
231 if (!rtos_try_next(target
)) {
232 LOG_WARNING("No RTOS could be auto-detected!");
236 /* Next RTOS selected - invalidate current symbol */
240 next_sym
= next_symbol(os
, cur_sym
, addr
);
242 if (!next_sym
->symbol_name
) {
243 /* No more symbols need looking up */
245 if (!target
->rtos_auto_detect
) {
250 if (os
->type
->detect_rtos(target
)) {
251 LOG_INFO("Auto-detected RTOS: %s", os
->type
->name
);
255 LOG_WARNING("No RTOS could be auto-detected!");
260 if (8 + (strlen(next_sym
->symbol_name
) * 2) + 1 > sizeof(reply
)) {
261 LOG_ERROR("ERROR: RTOS symbol '%s' name is too long for GDB!", next_sym
->symbol_name
);
265 reply_len
= snprintf(reply
, sizeof(reply
), "qSymbol:");
266 reply_len
+= hexify(reply
+ reply_len
, next_sym
->symbol_name
, 0, sizeof(reply
) - reply_len
);
269 gdb_put_packet(connection
, reply
, reply_len
);
270 return rtos_detected
;
273 int rtos_thread_packet(struct connection
*connection
, char const *packet
, int packet_size
)
275 struct target
*target
= get_target_from_connection(connection
);
277 if (strncmp(packet
, "qThreadExtraInfo,", 17) == 0) {
278 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
) &&
279 (target
->rtos
->thread_count
!= 0)) {
280 threadid_t threadid
= 0;
282 sscanf(packet
, "qThreadExtraInfo,%" SCNx64
, &threadid
);
284 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
)) {
286 for (thread_num
= 0; thread_num
< target
->rtos
->thread_count
; thread_num
++) {
287 if (target
->rtos
->thread_details
[thread_num
].threadid
== threadid
) {
288 if (target
->rtos
->thread_details
[thread_num
].exists
)
294 gdb_put_packet(connection
, "E01", 3); /* thread not found */
298 struct thread_detail
*detail
= &target
->rtos
->thread_details
[found
];
301 if (detail
->display_str
!= NULL
)
302 str_size
+= strlen(detail
->display_str
);
303 if (detail
->thread_name_str
!= NULL
)
304 str_size
+= strlen(detail
->thread_name_str
);
305 if (detail
->extra_info_str
!= NULL
)
306 str_size
+= strlen(detail
->extra_info_str
);
308 char *tmp_str
= calloc(str_size
+ 7, sizeof(char));
309 char *tmp_str_ptr
= tmp_str
;
311 if (detail
->display_str
!= NULL
)
312 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%s", detail
->display_str
);
313 if (detail
->thread_name_str
!= NULL
) {
314 if (tmp_str_ptr
!= tmp_str
)
315 tmp_str_ptr
+= sprintf(tmp_str_ptr
, " : ");
316 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%s", detail
->thread_name_str
);
318 if (detail
->extra_info_str
!= NULL
) {
319 if (tmp_str_ptr
!= tmp_str
)
320 tmp_str_ptr
+= sprintf(tmp_str_ptr
, " : ");
322 sprintf(tmp_str_ptr
, " : %s", detail
->extra_info_str
);
325 assert(strlen(tmp_str
) ==
326 (size_t) (tmp_str_ptr
- tmp_str
));
328 char *hex_str
= malloc(strlen(tmp_str
) * 2 + 1);
329 int pkt_len
= hexify(hex_str
, tmp_str
, 0, strlen(tmp_str
) * 2 + 1);
331 gdb_put_packet(connection
, hex_str
, pkt_len
);
337 gdb_put_packet(connection
, "", 0);
339 } else if (strncmp(packet
, "qSymbol", 7) == 0) {
340 if (rtos_qsymbol(connection
, packet
, packet_size
) == 1) {
341 target
->rtos_auto_detect
= false;
342 target
->rtos
->type
->create(target
);
343 target
->rtos
->type
->update_threads(target
->rtos
);
346 } else if (strncmp(packet
, "qfThreadInfo", 12) == 0) {
348 if (target
->rtos
!= NULL
) {
349 if (target
->rtos
->thread_count
== 0) {
350 gdb_put_packet(connection
, "l", 1);
352 /*thread id are 16 char +1 for ',' */
353 char *out_str
= malloc(17 * target
->rtos
->thread_count
+ 1);
354 char *tmp_str
= out_str
;
355 for (i
= 0; i
< target
->rtos
->thread_count
; i
++) {
356 tmp_str
+= sprintf(tmp_str
, "%c%016" PRIx64
, i
== 0 ? 'm' : ',',
357 target
->rtos
->thread_details
[i
].threadid
);
359 gdb_put_packet(connection
, out_str
, strlen(out_str
));
363 gdb_put_packet(connection
, "l", 1);
366 } else if (strncmp(packet
, "qsThreadInfo", 12) == 0) {
367 gdb_put_packet(connection
, "l", 1);
369 } else if (strncmp(packet
, "qAttached", 9) == 0) {
370 gdb_put_packet(connection
, "1", 1);
372 } else if (strncmp(packet
, "qOffsets", 8) == 0) {
373 char offsets
[] = "Text=0;Data=0;Bss=0";
374 gdb_put_packet(connection
, offsets
, sizeof(offsets
)-1);
376 } else if (strncmp(packet
, "qCRC:", 5) == 0) {
377 /* make sure we check this before "qC" packet below
378 * otherwise it gets incorrectly handled */
379 return GDB_THREAD_PACKET_NOT_CONSUMED
;
380 } else if (strncmp(packet
, "qC", 2) == 0) {
381 if (target
->rtos
!= NULL
) {
384 size
= snprintf(buffer
, 19, "QC%016" PRIx64
, target
->rtos
->current_thread
);
385 gdb_put_packet(connection
, buffer
, size
);
387 gdb_put_packet(connection
, "QC0", 3);
389 } else if (packet
[0] == 'T') { /* Is thread alive? */
392 sscanf(packet
, "T%" SCNx64
, &threadid
);
393 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
)) {
395 for (thread_num
= 0; thread_num
< target
->rtos
->thread_count
; thread_num
++) {
396 if (target
->rtos
->thread_details
[thread_num
].threadid
== threadid
) {
397 if (target
->rtos
->thread_details
[thread_num
].exists
)
403 gdb_put_packet(connection
, "OK", 2); /* thread alive */
405 gdb_put_packet(connection
, "E01", 3); /* thread not found */
407 } else if (packet
[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for
408 * all other operations ) */
409 if ((packet
[1] == 'g') && (target
->rtos
!= NULL
))
410 sscanf(packet
, "Hg%16" SCNx64
, &target
->rtos
->current_threadid
);
411 gdb_put_packet(connection
, "OK", 2);
415 return GDB_THREAD_PACKET_NOT_CONSUMED
;
418 int rtos_get_gdb_reg_list(struct connection
*connection
)
420 struct target
*target
= get_target_from_connection(connection
);
421 int64_t current_threadid
= target
->rtos
->current_threadid
;
422 if ((target
->rtos
!= NULL
) && (current_threadid
!= -1) &&
423 (current_threadid
!= 0) &&
424 ((current_threadid
!= target
->rtos
->current_thread
) ||
425 (target
->smp
))) { /* in smp several current thread are possible */
427 target
->rtos
->type
->get_thread_reg_list(target
->rtos
,
431 if (hex_reg_list
!= NULL
) {
432 gdb_put_packet(connection
, hex_reg_list
, strlen(hex_reg_list
));
440 int rtos_generic_stack_read(struct target
*target
,
441 const struct rtos_register_stacking
*stacking
,
447 int64_t new_stack_ptr
;
451 if (stack_ptr
== 0) {
452 LOG_ERROR("Error: null stack pointer in thread");
456 uint8_t *stack_data
= malloc(stacking
->stack_registers_size
);
457 uint32_t address
= stack_ptr
;
459 if (stacking
->stack_growth_direction
== 1)
460 address
-= stacking
->stack_registers_size
;
461 retval
= target_read_buffer(target
, address
, stacking
->stack_registers_size
, stack_data
);
462 if (retval
!= ERROR_OK
) {
464 LOG_ERROR("Error reading stack frame from thread");
468 LOG_OUTPUT("Stack Data :");
469 for (i
= 0; i
< stacking
->stack_registers_size
; i
++)
470 LOG_OUTPUT("%02X", stack_data
[i
]);
473 for (i
= 0; i
< stacking
->num_output_registers
; i
++)
474 list_size
+= stacking
->register_offsets
[i
].width_bits
/8;
475 *hex_reg_list
= malloc(list_size
*2 + 1);
476 tmp_str_ptr
= *hex_reg_list
;
477 new_stack_ptr
= stack_ptr
- stacking
->stack_growth_direction
*
478 stacking
->stack_registers_size
;
479 if (stacking
->stack_alignment
!= 0) {
480 /* Align new stack pointer to x byte boundary */
482 (new_stack_ptr
& (~((int64_t) stacking
->stack_alignment
- 1))) +
483 ((stacking
->stack_growth_direction
== -1) ? stacking
->stack_alignment
: 0);
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
->display_str
);
541 free(current_thread
->thread_name_str
);
542 free(current_thread
->extra_info_str
);
544 free(rtos
->thread_details
);
545 rtos
->thread_details
= NULL
;
546 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)