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 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
26 #include "target/target.h"
27 #include "helper/log.h"
28 #include "server/gdb_server.h"
30 static void hex_to_str(char *dst
, char *hex_src
);
33 extern struct rtos_type FreeRTOS_rtos
;
34 extern struct rtos_type ThreadX_rtos
;
35 extern struct rtos_type eCos_rtos
;
36 extern struct rtos_type Linux_os
;
37 extern struct rtos_type ChibiOS_rtos
;
39 static struct rtos_type
*rtos_types
[] = {
48 int rtos_thread_packet(struct connection
*connection
, char *packet
, int packet_size
);
50 int rtos_smp_init(struct target
*target
)
52 if (target
->rtos
->type
->smp_init
)
53 return target
->rtos
->type
->smp_init(target
);
54 return ERROR_TARGET_INIT_FAILED
;
57 static int os_alloc(struct target
*target
, struct rtos_type
*ostype
)
59 struct rtos
*os
= target
->rtos
= calloc(1, sizeof(struct rtos
));
65 os
->current_threadid
= -1;
66 os
->current_thread
= 0;
70 /* RTOS drivers can override the packet handler in _create(). */
71 os
->gdb_thread_packet
= rtos_thread_packet
;
76 static void os_free(struct target
*target
)
81 if (target
->rtos
->symbols
)
82 free(target
->rtos
->symbols
);
88 static int os_alloc_create(struct target
*target
, struct rtos_type
*ostype
)
90 int ret
= os_alloc(target
, ostype
);
93 ret
= target
->rtos
->type
->create(target
);
101 int rtos_create(Jim_GetOptInfo
*goi
, struct target
*target
)
107 if (!goi
->isconfigure
&& goi
->argc
!= 0) {
108 Jim_WrongNumArgs(goi
->interp
, goi
->argc
, goi
->argv
, "NO PARAMS");
114 Jim_GetOpt_String(goi
, &cp
, NULL
);
116 if (0 == strcmp(cp
, "auto")) {
117 /* Auto detect tries to look up all symbols for each RTOS,
118 * and runs the RTOS driver's _detect() function when GDB
119 * finds all symbols for any RTOS. See rtos_qsymbol(). */
120 target
->rtos_auto_detect
= true;
122 /* rtos_qsymbol() will iterate over all RTOSes. Allocate
123 * target->rtos here, and set it to the first RTOS type. */
124 return os_alloc(target
, rtos_types
[0]);
127 for (x
= 0; rtos_types
[x
]; x
++)
128 if (0 == strcmp(cp
, rtos_types
[x
]->name
))
129 return os_alloc_create(target
, rtos_types
[x
]);
131 Jim_SetResultFormatted(goi
->interp
, "Unknown RTOS type %s, try one of: ", cp
);
132 res
= Jim_GetResult(goi
->interp
);
133 for (x
= 0; rtos_types
[x
]; x
++)
134 Jim_AppendStrings(goi
->interp
, res
, rtos_types
[x
]->name
, ", ", NULL
);
135 Jim_AppendStrings(goi
->interp
, res
, " or auto", NULL
);
140 int gdb_thread_packet(struct connection
*connection
, char *packet
, int packet_size
)
142 struct target
*target
= get_target_from_connection(connection
);
143 if (target
->rtos
== NULL
)
144 return rtos_thread_packet(connection
, packet
, packet_size
); /* thread not
146 return target
->rtos
->gdb_thread_packet(connection
, packet
, packet_size
);
149 static char *next_symbol(struct rtos
*os
, char *cur_symbol
, uint64_t cur_addr
)
151 symbol_table_elem_t
*s
;
154 os
->type
->get_symbol_list_to_lookup(&os
->symbols
);
157 return os
->symbols
[0].symbol_name
;
159 for (s
= os
->symbols
; s
->symbol_name
; s
++)
160 if (!strcmp(s
->symbol_name
, cur_symbol
)) {
161 s
->address
= cur_addr
;
163 return s
->symbol_name
;
169 /* rtos_qsymbol() processes and replies to all qSymbol packets from GDB.
171 * GDB sends a qSymbol:: packet (empty address, empty name) to notify
172 * that it can now answer qSymbol::hexcodedname queries, to look up symbols.
174 * If the qSymbol packet has no address that means GDB did not find the
175 * symbol, in which case auto-detect will move on to try the next RTOS.
177 * rtos_qsymbol() then calls the next_symbol() helper function, which
178 * iterates over symbol names for the current RTOS until it finds the
179 * symbol in the received GDB packet, and then returns the next entry
180 * in the list of symbols.
182 * If GDB replied about the last symbol for the RTOS and the RTOS was
183 * specified explicitly, then no further symbol lookup is done. When
184 * auto-detecting, the RTOS driver _detect() function must return success.
186 * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise.
188 int rtos_qsymbol(struct connection
*connection
, char *packet
, int packet_size
)
190 int rtos_detected
= 0;
193 char reply
[GDB_BUFFER_SIZE
], cur_sym
[GDB_BUFFER_SIZE
/ 2] = "", *next_sym
;
194 struct target
*target
= get_target_from_connection(connection
);
195 struct rtos
*os
= target
->rtos
;
197 reply_len
= sprintf(reply
, "OK");
202 if (sscanf(packet
, "qSymbol:%" SCNx64
":", &addr
))
203 hex_to_str(cur_sym
, strchr(packet
+ 8, ':') + 1);
204 else if (target
->rtos_auto_detect
&& !rtos_try_next(target
))
207 next_sym
= next_symbol(os
, cur_sym
, addr
);
209 if (!target
->rtos_auto_detect
) {
214 if (os
->type
->detect_rtos(target
)) {
215 LOG_OUTPUT("Auto-detected RTOS: %s\r\n", os
->type
->name
);
220 if (!rtos_try_next(target
))
223 os
->type
->get_symbol_list_to_lookup(&os
->symbols
);
225 next_sym
= os
->symbols
[0].symbol_name
;
230 if (8 + (strlen(next_sym
) * 2) + 1 > sizeof(reply
)) {
231 LOG_OUTPUT("ERROR: RTOS symbol '%s' name is too long for GDB!", next_sym
);
235 reply_len
= sprintf(reply
, "qSymbol:");
236 reply_len
+= str_to_hex(reply
+ reply_len
, next_sym
);
239 gdb_put_packet(connection
, reply
, reply_len
);
240 return rtos_detected
;
243 int rtos_thread_packet(struct connection
*connection
, char *packet
, int packet_size
)
245 struct target
*target
= get_target_from_connection(connection
);
247 if (strncmp(packet
, "qThreadExtraInfo,", 17) == 0) {
248 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
) &&
249 (target
->rtos
->thread_count
!= 0)) {
250 threadid_t threadid
= 0;
252 sscanf(packet
, "qThreadExtraInfo,%" SCNx64
, &threadid
);
254 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
)) {
256 for (thread_num
= 0; thread_num
< target
->rtos
->thread_count
; thread_num
++) {
257 if (target
->rtos
->thread_details
[thread_num
].threadid
== threadid
) {
258 if (target
->rtos
->thread_details
[thread_num
].exists
)
264 gdb_put_packet(connection
, "E01", 3); /* thread not found */
268 struct thread_detail
*detail
= &target
->rtos
->thread_details
[found
];
271 if (detail
->display_str
!= NULL
)
272 str_size
+= strlen(detail
->display_str
);
273 if (detail
->thread_name_str
!= NULL
)
274 str_size
+= strlen(detail
->thread_name_str
);
275 if (detail
->extra_info_str
!= NULL
)
276 str_size
+= strlen(detail
->extra_info_str
);
278 char *tmp_str
= (char *) malloc(str_size
+ 7);
279 char *tmp_str_ptr
= tmp_str
;
281 if (detail
->display_str
!= NULL
)
282 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%s", detail
->display_str
);
283 if (detail
->thread_name_str
!= NULL
) {
284 if (tmp_str_ptr
!= tmp_str
)
285 tmp_str_ptr
+= sprintf(tmp_str_ptr
, " : ");
286 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%s", detail
->thread_name_str
);
288 if (detail
->extra_info_str
!= NULL
) {
289 if (tmp_str_ptr
!= tmp_str
)
290 tmp_str_ptr
+= sprintf(tmp_str_ptr
, " : ");
292 sprintf(tmp_str_ptr
, " : %s", detail
->extra_info_str
);
295 assert(strlen(tmp_str
) ==
296 (size_t) (tmp_str_ptr
- tmp_str
));
298 char *hex_str
= (char *) malloc(strlen(tmp_str
)*2 + 1);
299 str_to_hex(hex_str
, tmp_str
);
301 gdb_put_packet(connection
, hex_str
, strlen(hex_str
));
307 gdb_put_packet(connection
, "", 0);
309 } else if (strncmp(packet
, "qSymbol", 7) == 0) {
310 if (rtos_qsymbol(connection
, packet
, packet_size
) == 1) {
311 target
->rtos_auto_detect
= false;
312 target
->rtos
->type
->create(target
);
313 target
->rtos
->type
->update_threads(target
->rtos
);
316 } else if (strncmp(packet
, "qfThreadInfo", 12) == 0) {
318 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_count
!= 0)) {
320 char *out_str
= (char *) malloc(17 * target
->rtos
->thread_count
+ 5);
321 char *tmp_str
= out_str
;
322 tmp_str
+= sprintf(tmp_str
, "m");
323 for (i
= 0; i
< target
->rtos
->thread_count
; i
++) {
325 tmp_str
+= sprintf(tmp_str
, ",");
326 tmp_str
+= sprintf(tmp_str
, "%016" PRIx64
,
327 target
->rtos
->thread_details
[i
].threadid
);
330 gdb_put_packet(connection
, out_str
, strlen(out_str
));
332 gdb_put_packet(connection
, "", 0);
335 } else if (strncmp(packet
, "qsThreadInfo", 12) == 0) {
336 gdb_put_packet(connection
, "l", 1);
338 } else if (strncmp(packet
, "qAttached", 9) == 0) {
339 gdb_put_packet(connection
, "1", 1);
341 } else if (strncmp(packet
, "qOffsets", 8) == 0) {
342 char offsets
[] = "Text=0;Data=0;Bss=0";
343 gdb_put_packet(connection
, offsets
, sizeof(offsets
)-1);
345 } else if (strncmp(packet
, "qCRC:", 5) == 0) {
346 /* make sure we check this before "qC" packet below
347 * otherwise it gets incorrectly handled */
348 return GDB_THREAD_PACKET_NOT_CONSUMED
;
349 } else if (strncmp(packet
, "qC", 2) == 0) {
350 if (target
->rtos
!= NULL
) {
353 size
= snprintf(buffer
, 19, "QC%016" PRIx64
, target
->rtos
->current_thread
);
354 gdb_put_packet(connection
, buffer
, size
);
356 gdb_put_packet(connection
, "QC0", 3);
358 } else if (packet
[0] == 'T') { /* Is thread alive? */
361 sscanf(packet
, "T%" SCNx64
, &threadid
);
362 if ((target
->rtos
!= NULL
) && (target
->rtos
->thread_details
!= NULL
)) {
364 for (thread_num
= 0; thread_num
< target
->rtos
->thread_count
; thread_num
++) {
365 if (target
->rtos
->thread_details
[thread_num
].threadid
== threadid
) {
366 if (target
->rtos
->thread_details
[thread_num
].exists
)
372 gdb_put_packet(connection
, "OK", 2); /* thread alive */
374 gdb_put_packet(connection
, "E01", 3); /* thread not found */
376 } else if (packet
[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for
377 * all other operations ) */
378 if ((packet
[1] == 'g') && (target
->rtos
!= NULL
))
379 sscanf(packet
, "Hg%16" SCNx64
, &target
->rtos
->current_threadid
);
380 gdb_put_packet(connection
, "OK", 2);
384 return GDB_THREAD_PACKET_NOT_CONSUMED
;
387 int rtos_get_gdb_reg_list(struct connection
*connection
)
389 struct target
*target
= get_target_from_connection(connection
);
390 int64_t current_threadid
= target
->rtos
->current_threadid
;
391 if ((target
->rtos
!= NULL
) && (current_threadid
!= -1) &&
392 (current_threadid
!= 0) &&
393 ((current_threadid
!= target
->rtos
->current_thread
) ||
394 (target
->smp
))) { /* in smp several current thread are possible */
396 target
->rtos
->type
->get_thread_reg_list(target
->rtos
,
400 if (hex_reg_list
!= NULL
) {
401 gdb_put_packet(connection
, hex_reg_list
, strlen(hex_reg_list
));
409 int rtos_generic_stack_read(struct target
*target
,
410 const struct rtos_register_stacking
*stacking
,
416 int64_t new_stack_ptr
;
420 if (stack_ptr
== 0) {
421 LOG_OUTPUT("Error: null stack pointer in thread\r\n");
425 uint8_t *stack_data
= (uint8_t *) malloc(stacking
->stack_registers_size
);
426 uint32_t address
= stack_ptr
;
428 if (stacking
->stack_growth_direction
== 1)
429 address
-= stacking
->stack_registers_size
;
430 retval
= target_read_buffer(target
, address
, stacking
->stack_registers_size
, stack_data
);
431 if (retval
!= ERROR_OK
) {
432 LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n");
436 LOG_OUTPUT("Stack Data :");
437 for (i
= 0; i
< stacking
->stack_registers_size
; i
++)
438 LOG_OUTPUT("%02X", stack_data
[i
]);
441 for (i
= 0; i
< stacking
->num_output_registers
; i
++)
442 list_size
+= stacking
->register_offsets
[i
].width_bits
/8;
443 *hex_reg_list
= (char *)malloc(list_size
*2 + 1);
444 tmp_str_ptr
= *hex_reg_list
;
445 new_stack_ptr
= stack_ptr
- stacking
->stack_growth_direction
*
446 stacking
->stack_registers_size
;
447 if (stacking
->stack_alignment
!= 0) {
448 /* Align new stack pointer to x byte boundary */
450 (new_stack_ptr
& (~((int64_t) stacking
->stack_alignment
- 1))) +
451 ((stacking
->stack_growth_direction
== -1) ? stacking
->stack_alignment
: 0);
453 for (i
= 0; i
< stacking
->num_output_registers
; i
++) {
455 for (j
= 0; j
< stacking
->register_offsets
[i
].width_bits
/8; j
++) {
456 if (stacking
->register_offsets
[i
].offset
== -1)
457 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%02x", 0);
458 else if (stacking
->register_offsets
[i
].offset
== -2)
459 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%02x",
460 ((uint8_t *)&new_stack_ptr
)[j
]);
462 tmp_str_ptr
+= sprintf(tmp_str_ptr
, "%02x",
463 stack_data
[stacking
->register_offsets
[i
].offset
+ j
]);
466 /* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
470 int rtos_try_next(struct target
*target
)
472 struct rtos
*os
= target
->rtos
;
473 struct rtos_type
**type
= rtos_types
;
478 while (*type
&& os
->type
!= *type
)
481 if (!*type
|| !*(++type
))
493 static void hex_to_str(char *dst
, char *hex_src
)
498 while (hex_src
[src_pos
] != '\x00') {
499 char hex_char
= hex_src
[src_pos
];
503 10 : (hex_char
>= 'A') ? hex_char
-'A'+10 : hex_char
-'0';
504 if (0 == (src_pos
& 0x01)) {
505 dst
[dst_pos
] = hex_digit_val
;
508 ((unsigned char *)dst
)[dst_pos
] <<= 4;
509 ((unsigned char *)dst
)[dst_pos
] += hex_digit_val
;
517 int str_to_hex(char *hex_dst
, char *src
)
519 char *posptr
= hex_dst
;
521 for (i
= 0; i
< strlen(src
); i
++)
522 posptr
+= sprintf(posptr
, "%02x", (unsigned char)src
[i
]);
523 return posptr
- hex_dst
;
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
);
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)