- works on Cortex-M3 with ThreadX and FreeRTOS Compared to original patch a few nits were fixed: - remove stricmp usage - unsigned compare fix - printf formatting fixes - fixed a bug with overrunning a memory buffer allocated with malloc.tags/v0.5.0-rc1
@@ -1170,6 +1170,7 @@ AC_OUTPUT(dnl | |||||
src/xsvf/Makefile dnl | src/xsvf/Makefile dnl | ||||
src/svf/Makefile dnl | src/svf/Makefile dnl | ||||
src/target/Makefile dnl | src/target/Makefile dnl | ||||
src/rtos/Makefile dnl | |||||
src/server/Makefile dnl | src/server/Makefile dnl | ||||
src/flash/Makefile dnl | src/flash/Makefile dnl | ||||
src/flash/nor/Makefile dnl | src/flash/nor/Makefile dnl | ||||
@@ -8,7 +8,8 @@ SUBDIRS = \ | |||||
svf \ | svf \ | ||||
xsvf \ | xsvf \ | ||||
pld \ | pld \ | ||||
server | |||||
server \ | |||||
rtos | |||||
lib_LTLIBRARIES = libopenocd.la | lib_LTLIBRARIES = libopenocd.la | ||||
bin_PROGRAMS = openocd | bin_PROGRAMS = openocd | ||||
@@ -100,6 +101,7 @@ libopenocd_la_LIBADD = \ | |||||
$(top_builddir)/src/flash/libflash.la \ | $(top_builddir)/src/flash/libflash.la \ | ||||
$(top_builddir)/src/target/libtarget.la \ | $(top_builddir)/src/target/libtarget.la \ | ||||
$(top_builddir)/src/server/libserver.la \ | $(top_builddir)/src/server/libserver.la \ | ||||
$(top_builddir)/src/rtos/librtos.la \ | |||||
$(top_builddir)/src/helper/libhelper.la \ | $(top_builddir)/src/helper/libhelper.la \ | ||||
$(FTDI2232LIB) $(MINGWLDADD) $(LIBUSB) | $(FTDI2232LIB) $(MINGWLDADD) $(LIBUSB) | ||||
@@ -0,0 +1,481 @@ | |||||
/*************************************************************************** | |||||
* Copyright (C) 2011 by Broadcom Corporation * | |||||
* Evan Hunter - ehunter@broadcom.com * | |||||
* * | |||||
* This program is free software; you can redistribute it and/or modify * | |||||
* it under the terms of the GNU General Public License as published by * | |||||
* the Free Software Foundation; either version 2 of the License, or * | |||||
* (at your option) any later version. * | |||||
* * | |||||
* This program is distributed in the hope that it will be useful, * | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |||||
* GNU General Public License for more details. * | |||||
* * | |||||
* You should have received a copy of the GNU General Public License * | |||||
* along with this program; if not, write to the * | |||||
* Free Software Foundation, Inc., * | |||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||||
***************************************************************************/ | |||||
#ifdef HAVE_CONFIG_H | |||||
#include "config.h" | |||||
#endif | |||||
#include <helper/time_support.h> | |||||
#include <jtag/jtag.h> | |||||
#include "target/target.h" | |||||
#include "target/target_type.h" | |||||
#include "rtos.h" | |||||
#include "helper/log.h" | |||||
#include "rtos_standard_stackings.h" | |||||
#define FreeRTOS_STRUCT( int_type, ptr_type, list_prev_offset ) | |||||
struct FreeRTOS_params | |||||
{ | |||||
const char * target_name; | |||||
const unsigned char thread_count_width; | |||||
const unsigned char pointer_width; | |||||
const unsigned char list_next_offset; | |||||
const unsigned char list_width; | |||||
const unsigned char list_elem_next_offset; | |||||
const unsigned char list_elem_content_offset; | |||||
const unsigned char thread_stack_offset; | |||||
const unsigned char thread_name_offset; | |||||
const struct rtos_register_stacking* stacking_info; | |||||
}; | |||||
const struct FreeRTOS_params FreeRTOS_params_list[] = | |||||
{ | |||||
{ "cortex_m3", // target_name | |||||
4, // thread_count_width; | |||||
4, // pointer_width; | |||||
16, // list_next_offset; | |||||
20, // list_width; | |||||
8, // list_elem_next_offset; | |||||
12, // list_elem_content_offset | |||||
0, // thread_stack_offset; | |||||
52, // thread_name_offset; | |||||
&rtos_standard_Cortex_M3_stacking, // stacking_info | |||||
} | |||||
}; | |||||
#define FREERTOS_NUM_PARAMS ((int)(sizeof(FreeRTOS_params_list)/sizeof(struct FreeRTOS_params))) | |||||
static int FreeRTOS_detect_rtos( struct target* target ); | |||||
static int FreeRTOS_create( struct target* target ); | |||||
static int FreeRTOS_update_threads( struct rtos *rtos ); | |||||
static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, long long thread_id, char ** hex_reg_list ); | |||||
static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t * symbol_list[]); | |||||
struct rtos_type FreeRTOS_rtos = | |||||
{ | |||||
.name = "FreeRTOS", | |||||
.detect_rtos = FreeRTOS_detect_rtos, | |||||
.create = FreeRTOS_create, | |||||
.update_threads = FreeRTOS_update_threads, | |||||
.get_thread_reg_list = FreeRTOS_get_thread_reg_list, | |||||
.get_symbol_list_to_lookup = FreeRTOS_get_symbol_list_to_lookup, | |||||
}; | |||||
enum FreeRTOS_symbol_values | |||||
{ | |||||
FreeRTOS_VAL_pxCurrentTCB = 0, | |||||
FreeRTOS_VAL_pxReadyTasksLists = 1, | |||||
FreeRTOS_VAL_xDelayedTaskList1 = 2, | |||||
FreeRTOS_VAL_xDelayedTaskList2 = 3, | |||||
FreeRTOS_VAL_pxDelayedTaskList = 4, | |||||
FreeRTOS_VAL_pxOverflowDelayedTaskList = 5, | |||||
FreeRTOS_VAL_xPendingReadyList = 6, | |||||
FreeRTOS_VAL_xTasksWaitingTermination = 7, | |||||
FreeRTOS_VAL_xSuspendedTaskList = 8, | |||||
FreeRTOS_VAL_uxCurrentNumberOfTasks = 9, | |||||
}; | |||||
static char* FreeRTOS_symbol_list[] = | |||||
{ | |||||
"pxCurrentTCB", | |||||
"pxReadyTasksLists", | |||||
"xDelayedTaskList1", | |||||
"xDelayedTaskList2", | |||||
"pxDelayedTaskList", | |||||
"pxOverflowDelayedTaskList", | |||||
"xPendingReadyList", | |||||
"xTasksWaitingTermination", | |||||
"xSuspendedTaskList", | |||||
"uxCurrentNumberOfTasks", | |||||
NULL | |||||
}; | |||||
#define FREERTOS_NUM_SYMBOLS (sizeof(FreeRTOS_symbol_list)/sizeof(char*)) | |||||
// TODO: | |||||
// this is not safe for little endian yet | |||||
// may be problems reading if sizes are not 32 bit long integers. | |||||
// test mallocs for failure | |||||
static int FreeRTOS_update_threads( struct rtos *rtos ) | |||||
{ | |||||
int i = 0; | |||||
int retval; | |||||
int tasks_found = 0; | |||||
const struct FreeRTOS_params* param; | |||||
if (rtos->rtos_specific_params == NULL ) | |||||
{ | |||||
return -1; | |||||
} | |||||
param = (const struct FreeRTOS_params*) rtos->rtos_specific_params; | |||||
if ( rtos->symbols == NULL ) | |||||
{ | |||||
LOG_OUTPUT("No symbols for FreeRTOS\r\n"); | |||||
return -3; | |||||
} | |||||
if ( rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address == 0 ) | |||||
{ | |||||
LOG_OUTPUT("Don't have the number of threads in FreeRTOS \r\n"); | |||||
return -2; | |||||
} | |||||
int thread_list_size = 0; | |||||
retval = target_read_buffer( rtos->target, rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address, param->thread_count_width, (uint8_t *)&thread_list_size); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Could not read FreeRTOS thread count from target\r\n"); | |||||
return retval; | |||||
} | |||||
// wipe out previous thread details if any | |||||
if ( rtos->thread_details != NULL ) | |||||
{ | |||||
int j; | |||||
for( j = 0; j < rtos->thread_count; j++ ) | |||||
{ | |||||
if ( rtos->thread_details[j].display_str != NULL ) | |||||
{ | |||||
free( rtos->thread_details[j].display_str ); | |||||
rtos->thread_details[j].display_str = NULL; | |||||
} | |||||
if ( rtos->thread_details[j].thread_name_str != NULL ) | |||||
{ | |||||
free( rtos->thread_details[j].thread_name_str ); | |||||
rtos->thread_details[j].thread_name_str = NULL; | |||||
} | |||||
if ( rtos->thread_details[j].extra_info_str != NULL ) | |||||
{ | |||||
free( rtos->thread_details[j].extra_info_str ); | |||||
rtos->thread_details[j].extra_info_str = NULL; | |||||
} | |||||
} | |||||
free( rtos->thread_details ); | |||||
rtos->thread_details = NULL; | |||||
} | |||||
// read the current thread | |||||
retval = target_read_buffer( rtos->target, rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address, param->pointer_width, (uint8_t *)&rtos->current_thread ); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading current thread in FreeRTOS thread list\r\n"); | |||||
return retval; | |||||
} | |||||
if ( ( thread_list_size == 0 ) || ( rtos->current_thread == 0 ) ) | |||||
{ | |||||
// Either : No RTOS threads - there is always at least the current execution though | |||||
// OR : No current thread - all threads suspended - show the current execution of idling | |||||
char tmp_str[] = "Current Execution"; | |||||
thread_list_size++; | |||||
tasks_found++; | |||||
rtos->thread_details = (struct thread_detail*) malloc( sizeof( struct thread_detail ) * thread_list_size ); | |||||
rtos->thread_details->threadid = 1; | |||||
rtos->thread_details->exists = true; | |||||
rtos->thread_details->display_str = NULL; | |||||
rtos->thread_details->extra_info_str = NULL; | |||||
rtos->thread_details->thread_name_str = (char*) malloc( sizeof(tmp_str) ); | |||||
strcpy( rtos->thread_details->thread_name_str, tmp_str ); | |||||
if ( thread_list_size == 1 ) | |||||
{ | |||||
rtos->thread_count = 1; | |||||
return ERROR_OK; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
// create space for new thread details | |||||
rtos->thread_details = (struct thread_detail*) malloc( sizeof( struct thread_detail ) * thread_list_size ); | |||||
} | |||||
// Unfortunately, we can't know how many lists there are for pxReadyTasksLists, | |||||
// So figure it out via other variables | |||||
int num_ready_task_lists = (rtos->symbols[FreeRTOS_VAL_xDelayedTaskList1].address - rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address) / param->list_width; | |||||
symbol_address_t* list_of_lists = (symbol_address_t *)malloc( sizeof( symbol_address_t ) * ( num_ready_task_lists + 5 ) ); | |||||
int num_lists; | |||||
for( num_lists = 0; num_lists < num_ready_task_lists; num_lists++ ) | |||||
{ | |||||
list_of_lists[num_lists] = rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address + num_lists * param->list_width; | |||||
} | |||||
list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList1].address; | |||||
list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList2].address; | |||||
list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xPendingReadyList].address; | |||||
list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xTasksWaitingTermination].address; | |||||
for( i = 0; i < num_lists; i++ ) | |||||
{ | |||||
if ( list_of_lists[i] == 0 ) | |||||
{ | |||||
continue; | |||||
} | |||||
// Read the number of threads in this list | |||||
long long list_thread_count = 0; | |||||
retval = target_read_buffer( rtos->target, list_of_lists[i], param->thread_count_width, (uint8_t *)&list_thread_count); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading number of threads in FreeRTOS thread list\r\n"); | |||||
return retval; | |||||
} | |||||
if ( list_thread_count == 0 ) | |||||
{ | |||||
continue; | |||||
} | |||||
// Read the location of first list item | |||||
unsigned long long prev_list_elem_ptr = -1; | |||||
unsigned long long list_elem_ptr = 0; | |||||
retval = target_read_buffer( rtos->target, list_of_lists[i] + param->list_next_offset, param->pointer_width, (uint8_t *)&list_elem_ptr); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading first thread item location in FreeRTOS thread list\r\n"); | |||||
return retval; | |||||
} | |||||
while ( (list_thread_count > 0) && ( list_elem_ptr != 0) && ( list_elem_ptr != prev_list_elem_ptr ) && ( tasks_found < thread_list_size ) ) | |||||
{ | |||||
// Get the location of the thread structure. | |||||
rtos->thread_details[tasks_found].threadid = 0; | |||||
retval = target_read_buffer( rtos->target, list_elem_ptr + param->list_elem_content_offset, param->pointer_width, (uint8_t *)&(rtos->thread_details[tasks_found].threadid)); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading thread list item object in FreeRTOS thread list\r\n"); | |||||
return retval; | |||||
} | |||||
// get thread name | |||||
#define FREERTOS_THREAD_NAME_STR_SIZE (200) | |||||
char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE]; | |||||
// Read the thread name | |||||
retval = target_read_buffer( rtos->target, rtos->thread_details[tasks_found].threadid + param->thread_name_offset, FREERTOS_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading first thread item location in FreeRTOS thread list\r\n"); | |||||
return retval; | |||||
} | |||||
tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00'; | |||||
if ( tmp_str[0] == '\x00' ) | |||||
{ | |||||
strcpy(tmp_str,"No Name"); | |||||
} | |||||
rtos->thread_details[tasks_found].thread_name_str = (char*)malloc( strlen(tmp_str)+1 ); | |||||
strcpy( rtos->thread_details[tasks_found].thread_name_str, tmp_str ); | |||||
rtos->thread_details[tasks_found].display_str = NULL; | |||||
rtos->thread_details[tasks_found].exists = true; | |||||
if ( rtos->thread_details[tasks_found].threadid == rtos->current_thread ) | |||||
{ | |||||
char running_str[] = "Running"; | |||||
rtos->thread_details[tasks_found].extra_info_str = (char*) malloc( sizeof(running_str) ); | |||||
strcpy( rtos->thread_details[tasks_found].extra_info_str, running_str ); | |||||
} | |||||
else | |||||
{ | |||||
rtos->thread_details[tasks_found].extra_info_str = NULL; | |||||
} | |||||
tasks_found++; | |||||
list_thread_count--; | |||||
prev_list_elem_ptr = list_elem_ptr; | |||||
list_elem_ptr = 0; | |||||
retval = target_read_buffer( rtos->target, prev_list_elem_ptr + param->list_elem_next_offset, param->pointer_width, (uint8_t *)&list_elem_ptr); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading next thread item location in FreeRTOS thread list\r\n"); | |||||
return retval; | |||||
} | |||||
} | |||||
} | |||||
free( list_of_lists ); | |||||
rtos->thread_count = tasks_found; | |||||
return 0; | |||||
} | |||||
static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, long long thread_id, char ** hex_reg_list ) | |||||
{ | |||||
int retval; | |||||
const struct FreeRTOS_params* param; | |||||
long long stack_ptr = 0; | |||||
*hex_reg_list = NULL; | |||||
if ( rtos == NULL ) | |||||
{ | |||||
return -1; | |||||
} | |||||
if ( thread_id == 0 ) | |||||
{ | |||||
return -2; | |||||
} | |||||
if (rtos->rtos_specific_params == NULL ) | |||||
{ | |||||
return -1; | |||||
} | |||||
param = (const struct FreeRTOS_params*) rtos->rtos_specific_params; | |||||
// Read the stack pointer | |||||
retval = target_read_buffer( rtos->target, thread_id + param->thread_stack_offset, param->pointer_width, (uint8_t*)&stack_ptr); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n"); | |||||
return retval; | |||||
} | |||||
return rtos_generic_stack_read( rtos->target, param->stacking_info, stack_ptr, hex_reg_list ); | |||||
} | |||||
static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t * symbol_list[]) | |||||
{ | |||||
unsigned int i; | |||||
*symbol_list = (symbol_table_elem_t *) malloc( sizeof( symbol_table_elem_t ) * FREERTOS_NUM_SYMBOLS ); | |||||
for( i = 0; i < FREERTOS_NUM_SYMBOLS; i++ ) | |||||
{ | |||||
(*symbol_list)[i].symbol_name = FreeRTOS_symbol_list[i]; | |||||
} | |||||
return 0; | |||||
} | |||||
#if 0 | |||||
static int FreeRTOS_set_current_thread(struct rtos *rtos, threadid_t thread_id) | |||||
{ | |||||
return 0; | |||||
} | |||||
static int FreeRTOS_get_thread_ascii_info( struct rtos* rtos, threadid_t thread_id, char ** info ) | |||||
{ | |||||
int retval; | |||||
const struct FreeRTOS_params* param; | |||||
if ( rtos == NULL ) | |||||
{ | |||||
return -1; | |||||
} | |||||
if ( thread_id == 0 ) | |||||
{ | |||||
return -2; | |||||
} | |||||
if (rtos->rtos_specific_params == NULL ) | |||||
{ | |||||
return -3; | |||||
} | |||||
param = (const struct FreeRTOS_params*) rtos->rtos_specific_params; | |||||
#define FREERTOS_THREAD_NAME_STR_SIZE (200) | |||||
char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE]; | |||||
// Read the thread name | |||||
retval = target_read_buffer( rtos->target, thread_id + param->thread_name_offset, FREERTOS_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading first thread item location in FreeRTOS thread list\r\n"); | |||||
return retval; | |||||
} | |||||
tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00'; | |||||
if ( tmp_str[0] == '\x00' ) | |||||
{ | |||||
strcpy(tmp_str,"No Name"); | |||||
} | |||||
*info = (char*)malloc( strlen(tmp_str)+1 ); | |||||
strcpy( *info, tmp_str ); | |||||
return 0; | |||||
} | |||||
#endif | |||||
static int FreeRTOS_detect_rtos( struct target* target ) | |||||
{ | |||||
if ( ( target->rtos->symbols != NULL ) && | |||||
( target->rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address != 0 ) ) | |||||
{ | |||||
// looks like FreeRTOS | |||||
return 1; | |||||
} | |||||
return 0; | |||||
return 0; | |||||
} | |||||
static int FreeRTOS_create( struct target* target ) | |||||
{ | |||||
int i = 0; | |||||
while ( ( i < FREERTOS_NUM_PARAMS ) && ( 0 != strcmp( FreeRTOS_params_list[i].target_name, target->type->name ) ) ) | |||||
{ | |||||
i++; | |||||
} | |||||
if ( i >= FREERTOS_NUM_PARAMS ) | |||||
{ | |||||
LOG_OUTPUT("Could not find target in FreeRTOS compatability list\r\n"); | |||||
return -1; | |||||
} | |||||
target->rtos->rtos_specific_params = (void*) &FreeRTOS_params_list[i]; | |||||
return 0; | |||||
} |
@@ -0,0 +1,35 @@ | |||||
# *************************************************************************** | |||||
# * Copyright (C) 2011 by Broadcom Corporation * | |||||
# * Evan Hunter - ehunter@broadcom.com * | |||||
# * * | |||||
# * This program is free software; you can redistribute it and/or modify * | |||||
# * it under the terms of the GNU General Public License as published by * | |||||
# * the Free Software Foundation; either version 2 of the License, or * | |||||
# * (at your option) any later version. * | |||||
# * * | |||||
# * This program is distributed in the hope that it will be useful, * | |||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |||||
# * GNU General Public License for more details. * | |||||
# * * | |||||
# * You should have received a copy of the GNU General Public License * | |||||
# * along with this program; if not, write to the * | |||||
# * Free Software Foundation, Inc., * | |||||
# * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||||
# *************************************************************************** | |||||
include $(top_srcdir)/common.mk | |||||
METASOURCES = AUTO | |||||
noinst_LTLIBRARIES = librtos.la | |||||
noinst_HEADERS = rtos.h | |||||
librtos_la_SOURCES = rtos.c rtos_standard_stackings.c FreeRTOS.c ThreadX.c | |||||
librtos_la_CFLAGS = | |||||
if IS_MINGW | |||||
# FD_* macros are sloppy with their signs on MinGW32 platform | |||||
librtos_la_CFLAGS += -Wno-sign-compare | |||||
endif | |||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in |
@@ -0,0 +1,536 @@ | |||||
/*************************************************************************** | |||||
* Copyright (C) 2011 by Broadcom Corporation * | |||||
* Evan Hunter - ehunter@broadcom.com * | |||||
* * | |||||
* This program is free software; you can redistribute it and/or modify * | |||||
* it under the terms of the GNU General Public License as published by * | |||||
* the Free Software Foundation; either version 2 of the License, or * | |||||
* (at your option) any later version. * | |||||
* * | |||||
* This program is distributed in the hope that it will be useful, * | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |||||
* GNU General Public License for more details. * | |||||
* * | |||||
* You should have received a copy of the GNU General Public License * | |||||
* along with this program; if not, write to the * | |||||
* Free Software Foundation, Inc., * | |||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||||
***************************************************************************/ | |||||
#ifdef HAVE_CONFIG_H | |||||
#include "config.h" | |||||
#endif | |||||
#include <helper/time_support.h> | |||||
#include <jtag/jtag.h> | |||||
#include "target/target.h" | |||||
#include "target/target_type.h" | |||||
#include "rtos.h" | |||||
#include "helper/log.h" | |||||
#include "rtos_standard_stackings.h" | |||||
static int ThreadX_detect_rtos( struct target* target ); | |||||
static int ThreadX_create( struct target* target ); | |||||
static int ThreadX_update_threads( struct rtos* rtos); | |||||
static int ThreadX_get_thread_reg_list(struct rtos *rtos, long long thread_id, char ** hex_reg_list ); | |||||
static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t * symbol_list[]); | |||||
struct ThreadX_thread_state | |||||
{ | |||||
int value; | |||||
char * desc; | |||||
}; | |||||
struct ThreadX_thread_state ThreadX_thread_states[] = | |||||
{ | |||||
{ 0, "Ready" }, | |||||
{ 1, "Completed" }, | |||||
{ 2, "Terminated" }, | |||||
{ 3, "Suspended" }, | |||||
{ 4, "Sleeping" }, | |||||
{ 5, "Waiting - Queue" }, | |||||
{ 6, "Waiting - Semaphore" }, | |||||
{ 7, "Waiting - Event flag" }, | |||||
{ 8, "Waiting - Memory" }, | |||||
{ 9, "Waiting - Memory" }, | |||||
{ 10, "Waiting - I/O" }, | |||||
{ 11, "Waiting - Filesystem" }, | |||||
{ 12, "Waiting - Network" }, | |||||
{ 13, "Waiting - Mutex" }, | |||||
}; | |||||
#define THREADX_NUM_STATES (sizeof(ThreadX_thread_states)/sizeof(struct ThreadX_thread_state)) | |||||
struct ThreadX_params | |||||
{ | |||||
char * target_name; | |||||
unsigned char pointer_width; | |||||
unsigned char thread_stack_offset; | |||||
unsigned char thread_name_offset; | |||||
unsigned char thread_state_offset; | |||||
unsigned char thread_next_offset; | |||||
const struct rtos_register_stacking* stacking_info; | |||||
}; | |||||
const struct ThreadX_params ThreadX_params_list[] = | |||||
{ | |||||
{ "cortex_m3", // target_name | |||||
4, // pointer_width; | |||||
8, // thread_stack_offset; | |||||
40, // thread_name_offset; | |||||
48, // thread_state_offset; | |||||
136, // thread_next_offset | |||||
&rtos_standard_Cortex_M3_stacking, // stacking_info | |||||
} | |||||
}; | |||||
#define THREADX_NUM_PARAMS ((int)(sizeof(ThreadX_params_list)/sizeof(struct ThreadX_params))) | |||||
enum ThreadX_symbol_values | |||||
{ | |||||
ThreadX_VAL_tx_thread_current_ptr = 0, | |||||
ThreadX_VAL_tx_thread_created_ptr = 1, | |||||
ThreadX_VAL_tx_thread_created_count = 2, | |||||
}; | |||||
static char* ThreadX_symbol_list[] = | |||||
{ | |||||
"_tx_thread_current_ptr", | |||||
"_tx_thread_created_ptr", | |||||
"_tx_thread_created_count", | |||||
NULL | |||||
}; | |||||
#define THREADX_NUM_SYMBOLS (sizeof(ThreadX_symbol_list)/sizeof(char*)) | |||||
const struct rtos_type ThreadX_rtos = | |||||
{ | |||||
.name = "ThreadX", | |||||
.detect_rtos = ThreadX_detect_rtos, | |||||
.create = ThreadX_create, | |||||
.update_threads = ThreadX_update_threads, | |||||
.get_thread_reg_list = ThreadX_get_thread_reg_list, | |||||
.get_symbol_list_to_lookup = ThreadX_get_symbol_list_to_lookup, | |||||
}; | |||||
static int ThreadX_update_threads( struct rtos* rtos) | |||||
{ | |||||
int retval; | |||||
int tasks_found = 0; | |||||
int thread_list_size = 0; | |||||
const struct ThreadX_params* param; | |||||
if ( rtos == NULL ) | |||||
{ | |||||
return -1; | |||||
} | |||||
if (rtos->rtos_specific_params == NULL ) | |||||
{ | |||||
return -3; | |||||
} | |||||
param = (const struct ThreadX_params*) rtos->rtos_specific_params; | |||||
if ( rtos->symbols == NULL ) | |||||
{ | |||||
LOG_OUTPUT("No symbols for ThreadX\r\n"); | |||||
return -4; | |||||
} | |||||
if ( rtos->symbols[ThreadX_VAL_tx_thread_created_count].address == 0 ) | |||||
{ | |||||
LOG_OUTPUT("Don't have the number of threads in ThreadX \r\n"); | |||||
return -2; | |||||
} | |||||
// read the number of threads | |||||
retval = target_read_buffer( rtos->target, rtos->symbols[ThreadX_VAL_tx_thread_created_count].address, 4, (uint8_t *)&thread_list_size); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Could not read ThreadX thread count from target\r\n"); | |||||
return retval; | |||||
} | |||||
// wipe out previous thread details if any | |||||
if ( rtos->thread_details != NULL ) | |||||
{ | |||||
int j; | |||||
for( j = 0; j < rtos->thread_count; j++ ) | |||||
{ | |||||
if ( rtos->thread_details[j].display_str != NULL ) | |||||
{ | |||||
free( rtos->thread_details[j].display_str ); | |||||
rtos->thread_details[j].display_str = NULL; | |||||
} | |||||
if ( rtos->thread_details[j].thread_name_str != NULL ) | |||||
{ | |||||
free( rtos->thread_details[j].thread_name_str ); | |||||
rtos->thread_details[j].thread_name_str = NULL; | |||||
} | |||||
if ( rtos->thread_details[j].extra_info_str != NULL ) | |||||
{ | |||||
free( rtos->thread_details[j].extra_info_str ); | |||||
rtos->thread_details[j].extra_info_str = NULL; | |||||
} | |||||
} | |||||
free( rtos->thread_details ); | |||||
rtos->thread_details = NULL; | |||||
} | |||||
// read the current thread id | |||||
retval = target_read_buffer( rtos->target, rtos->symbols[ThreadX_VAL_tx_thread_current_ptr].address, 4, (uint8_t *)&rtos->current_thread); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Could not read ThreadX current thread from target\r\n"); | |||||
return retval; | |||||
} | |||||
if ( ( thread_list_size == 0 ) || ( rtos->current_thread == 0 ) ) | |||||
{ | |||||
// Either : No RTOS threads - there is always at least the current execution though | |||||
// OR : No current thread - all threads suspended - show the current execution of idling | |||||
char tmp_str[] = "Current Execution"; | |||||
thread_list_size++; | |||||
tasks_found++; | |||||
rtos->thread_details = (struct thread_detail*) malloc( sizeof( struct thread_detail ) * thread_list_size ); | |||||
rtos->thread_details->threadid = 1; | |||||
rtos->thread_details->exists = true; | |||||
rtos->thread_details->display_str = NULL; | |||||
rtos->thread_details->extra_info_str = NULL; | |||||
rtos->thread_details->thread_name_str = (char*) malloc( sizeof(tmp_str) ); | |||||
strcpy( rtos->thread_details->thread_name_str, tmp_str ); | |||||
if ( thread_list_size == 0 ) | |||||
{ | |||||
rtos->thread_count = 1; | |||||
return ERROR_OK; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
// create space for new thread details | |||||
rtos->thread_details = (struct thread_detail*) malloc( sizeof( struct thread_detail ) * thread_list_size ); | |||||
} | |||||
// Read the pointer to the first thread | |||||
long long thread_ptr = 0; | |||||
retval = target_read_buffer( rtos->target, rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address, param->pointer_width, (uint8_t *)&thread_ptr); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Could not read ThreadX thread location from target\r\n"); | |||||
return retval; | |||||
} | |||||
// loop over all threads | |||||
long long prev_thread_ptr = 0; | |||||
while ( ( thread_ptr != prev_thread_ptr ) && ( tasks_found < thread_list_size ) ) | |||||
{ | |||||
#define THREADX_THREAD_NAME_STR_SIZE (200) | |||||
char tmp_str[THREADX_THREAD_NAME_STR_SIZE]; | |||||
unsigned int i = 0; | |||||
long long name_ptr = 0; | |||||
// Save the thread pointer | |||||
rtos->thread_details[tasks_found].threadid = thread_ptr; | |||||
// read the name pointer | |||||
retval = target_read_buffer( rtos->target, thread_ptr + param->thread_name_offset, param->pointer_width, (uint8_t *)&name_ptr); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Could not read ThreadX thread name pointer from target\r\n"); | |||||
return retval; | |||||
} | |||||
// Read the thread name | |||||
retval = target_read_buffer( rtos->target, name_ptr, THREADX_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading thread name from ThreadX target\r\n"); | |||||
return retval; | |||||
} | |||||
tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00'; | |||||
if ( tmp_str[0] == '\x00' ) | |||||
{ | |||||
strcpy(tmp_str,"No Name"); | |||||
} | |||||
rtos->thread_details[tasks_found].thread_name_str = (char*)malloc( strlen(tmp_str)+1 ); | |||||
strcpy( rtos->thread_details[tasks_found].thread_name_str, tmp_str ); | |||||
// Read the thread status | |||||
long long thread_status = 0; | |||||
retval = target_read_buffer( rtos->target, thread_ptr + param->thread_state_offset, 4, (uint8_t *)&thread_status); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading thread state from ThreadX target\r\n"); | |||||
return retval; | |||||
} | |||||
for( i = 0; (i < THREADX_NUM_STATES) && (ThreadX_thread_states[i].value!=thread_status); i++ ) | |||||
{ | |||||
} | |||||
char * state_desc; | |||||
if (i < THREADX_NUM_STATES) | |||||
{ | |||||
state_desc = ThreadX_thread_states[i].desc; | |||||
} | |||||
else | |||||
{ | |||||
state_desc = "Unknown state"; | |||||
} | |||||
rtos->thread_details[tasks_found].extra_info_str = (char*)malloc( strlen(state_desc)+1 ); | |||||
strcpy( rtos->thread_details[tasks_found].extra_info_str, state_desc ); | |||||
rtos->thread_details[tasks_found].exists = true; | |||||
rtos->thread_details[tasks_found].display_str = NULL; | |||||
tasks_found++; | |||||
prev_thread_ptr = thread_ptr; | |||||
// Get the location of the next thread structure. | |||||
thread_ptr = 0; | |||||
retval = target_read_buffer( rtos->target, prev_thread_ptr + param->thread_next_offset, param->pointer_width, (uint8_t *) &thread_ptr ); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading next thread pointer in ThreadX thread list\r\n"); | |||||
return retval; | |||||
} | |||||
} | |||||
rtos->thread_count = tasks_found; | |||||
return 0; | |||||
} | |||||
static int ThreadX_get_thread_reg_list(struct rtos *rtos, long long thread_id, char ** hex_reg_list ) | |||||
{ | |||||
int retval; | |||||
const struct ThreadX_params* param; | |||||
*hex_reg_list = NULL; | |||||
if ( rtos == NULL ) | |||||
{ | |||||
return -1; | |||||
} | |||||
if ( thread_id == 0 ) | |||||
{ | |||||
return -2; | |||||
} | |||||
if (rtos->rtos_specific_params == NULL ) | |||||
{ | |||||
return -3; | |||||
} | |||||
param = (const struct ThreadX_params*) rtos->rtos_specific_params; | |||||
// Read the stack pointer | |||||
long long stack_ptr = 0; | |||||
retval = target_read_buffer( rtos->target, thread_id + param->thread_stack_offset, param->pointer_width, (uint8_t*)&stack_ptr); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading stack frame from ThreadX thread\r\n"); | |||||
return retval; | |||||
} | |||||
return rtos_generic_stack_read( rtos->target, param->stacking_info, stack_ptr, hex_reg_list ); | |||||
} | |||||
static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t * symbol_list[]) | |||||
{ | |||||
unsigned int i; | |||||
*symbol_list = (symbol_table_elem_t *) malloc( sizeof( symbol_table_elem_t ) * THREADX_NUM_SYMBOLS ); | |||||
for( i = 0; i < THREADX_NUM_SYMBOLS; i++ ) | |||||
{ | |||||
(*symbol_list)[i].symbol_name = ThreadX_symbol_list[i]; | |||||
} | |||||
return 0; | |||||
} | |||||
static int ThreadX_detect_rtos( struct target* target ) | |||||
{ | |||||
if ( ( target->rtos->symbols != NULL ) && | |||||
( target->rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address != 0 ) ) | |||||
{ | |||||
// looks like ThreadX | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} | |||||
#if 0 | |||||
static int ThreadX_set_current_thread(struct rtos *rtos, threadid_t thread_id) | |||||
{ | |||||
return 0; | |||||
} | |||||
static int ThreadX_get_thread_detail( struct rtos* rtos, threadid_t thread_id, struct thread_detail* detail ) | |||||
{ | |||||
unsigned int i = 0; | |||||
int retval; | |||||
#define THREADX_THREAD_NAME_STR_SIZE (200) | |||||
char tmp_str[THREADX_THREAD_NAME_STR_SIZE]; | |||||
const struct ThreadX_params* param; | |||||
if ( rtos == NULL ) | |||||
{ | |||||
return -1; | |||||
} | |||||
if ( thread_id == 0 ) | |||||
{ | |||||
return -2; | |||||
} | |||||
if (rtos->rtos_specific_params == NULL ) | |||||
{ | |||||
return -3; | |||||
} | |||||
param = (const struct ThreadX_params*) rtos->rtos_specific_params; | |||||
if ( rtos->symbols == NULL ) | |||||
{ | |||||
LOG_OUTPUT("No symbols for ThreadX\r\n"); | |||||
return -3; | |||||
} | |||||
detail->threadid = thread_id; | |||||
long long name_ptr = 0; | |||||
// read the name pointer | |||||
retval = target_read_buffer( rtos->target, thread_id + param->thread_name_offset, param->pointer_width, (uint8_t *)&name_ptr); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Could not read ThreadX thread name pointer from target\r\n"); | |||||
return retval; | |||||
} | |||||
// Read the thread name | |||||
retval = target_read_buffer( rtos->target, name_ptr, THREADX_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading thread name from ThreadX target\r\n"); | |||||
return retval; | |||||
} | |||||
tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00'; | |||||
if ( tmp_str[0] == '\x00' ) | |||||
{ | |||||
strcpy(tmp_str,"No Name"); | |||||
} | |||||
detail->thread_name_str = (char*)malloc( strlen(tmp_str)+1 ); | |||||
// Read the thread status | |||||
long long thread_status = 0; | |||||
retval = target_read_buffer( rtos->target, thread_id + param->thread_state_offset, 4, (uint8_t *)&thread_status); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading thread state from ThreadX target\r\n"); | |||||
return retval; | |||||
} | |||||
for( i = 0; (i < THREADX_NUM_STATES) && (ThreadX_thread_states[i].value!=thread_status); i++ ) | |||||
{ | |||||
} | |||||
char * state_desc; | |||||
if (i < THREADX_NUM_STATES) | |||||
{ | |||||
state_desc = ThreadX_thread_states[i].desc; | |||||
} | |||||
else | |||||
{ | |||||
state_desc = "Unknown state"; | |||||
} | |||||
detail->extra_info_str = (char*)malloc( strlen(state_desc)+1 ); | |||||
detail->exists = true; | |||||
detail->display_str = NULL; | |||||
return 0; | |||||
} | |||||
#endif | |||||
static int ThreadX_create( struct target* target ) | |||||
{ | |||||
int i = 0; | |||||
while ( ( i < THREADX_NUM_PARAMS ) && ( 0 != strcmp( ThreadX_params_list[i].target_name, target->type->name ) ) ) | |||||
{ | |||||
i++; | |||||
} | |||||
if ( i >= THREADX_NUM_PARAMS ) | |||||
{ | |||||
LOG_OUTPUT("Could not find target in ThreadX compatability list\r\n"); | |||||
return -1; | |||||
} | |||||
target->rtos->rtos_specific_params = (void*) &ThreadX_params_list[i]; | |||||
target->rtos->current_thread = 0; | |||||
target->rtos->thread_details = NULL; | |||||
return 0; | |||||
} |
@@ -0,0 +1,657 @@ | |||||
/*************************************************************************** | |||||
* Copyright (C) 2011 by Broadcom Corporation * | |||||
* Evan Hunter - ehunter@broadcom.com * | |||||
* * | |||||
* This program is free software; you can redistribute it and/or modify * | |||||
* it under the terms of the GNU General Public License as published by * | |||||
* the Free Software Foundation; either version 2 of the License, or * | |||||
* (at your option) any later version. * | |||||
* * | |||||
* This program is distributed in the hope that it will be useful, * | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |||||
* GNU General Public License for more details. * | |||||
* * | |||||
* You should have received a copy of the GNU General Public License * | |||||
* along with this program; if not, write to the * | |||||
* Free Software Foundation, Inc., * | |||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||||
***************************************************************************/ | |||||
#ifdef HAVE_CONFIG_H | |||||
#include "config.h" | |||||
#endif | |||||
#include "rtos.h" | |||||
#include "target/target.h" | |||||
#include "helper/log.h" | |||||
#include "server/gdb_server.h" | |||||
static long long current_threadid = -1; | |||||
static void hex_to_str( char* dst, char * hex_src ); | |||||
static int str_to_hex( char* hex_dst, char* src ); | |||||
/* RTOSs */ | |||||
extern struct rtos_type FreeRTOS_rtos; | |||||
extern struct rtos_type ThreadX_rtos; | |||||
static struct rtos_type *rtos_types[] = | |||||
{ | |||||
&ThreadX_rtos, | |||||
&FreeRTOS_rtos, | |||||
NULL | |||||
}; | |||||
int rtos_create(Jim_GetOptInfo *goi, struct target * target) | |||||
{ | |||||
int x; | |||||
char *cp; | |||||
if (! goi->isconfigure) { | |||||
if (goi->argc != 0) { | |||||
if (goi->argc != 0) { | |||||
Jim_WrongNumArgs(goi->interp, | |||||
goi->argc, goi->argv, | |||||
"NO PARAMS"); | |||||
return JIM_ERR; | |||||
} | |||||
Jim_SetResultString(goi->interp, | |||||
target_type_name(target), -1); | |||||
} | |||||
} | |||||
if (target->rtos) { | |||||
free((void *)(target->rtos)); | |||||
} | |||||
// e = Jim_GetOpt_String(goi, &cp, NULL); | |||||
// target->rtos = strdup(cp); | |||||
Jim_GetOpt_String(goi, &cp, NULL); | |||||
/* now does target type exist */ | |||||
if ( 0 == strcmp( cp, "auto") ) | |||||
{ | |||||
// auto detection of RTOS | |||||
target->rtos_auto_detect = true; | |||||
x = 0; | |||||
} | |||||
else | |||||
{ | |||||
for (x = 0 ; rtos_types[x] ; x++) { | |||||
if (0 == strcmp(cp, rtos_types[x]->name)) { | |||||
/* found */ | |||||
break; | |||||
} | |||||
} | |||||
if (rtos_types[x] == NULL) { | |||||
Jim_SetResultFormatted(goi->interp, "Unknown rtos type %s, try one of ", cp); | |||||
for (x = 0 ; rtos_types[x] ; x++) { | |||||
if (rtos_types[x + 1]) { | |||||
Jim_AppendStrings(goi->interp, | |||||
Jim_GetResult(goi->interp), | |||||
rtos_types[x]->name, | |||||
", ", NULL); | |||||
} else { | |||||
Jim_AppendStrings(goi->interp, | |||||
Jim_GetResult(goi->interp), | |||||
" or ", | |||||
rtos_types[x]->name,NULL); | |||||
} | |||||
} | |||||
return JIM_ERR; | |||||
} | |||||
} | |||||
/* Create it */ | |||||
target->rtos = calloc(1,sizeof(struct rtos)); | |||||
target->rtos->type = rtos_types[x]; | |||||
target->rtos->current_thread = 0; | |||||
target->rtos->symbols = NULL; | |||||
target->rtos->target = target; | |||||
if ( 0 != strcmp( cp, "auto") ) | |||||
{ | |||||
target->rtos->type->create( target ); | |||||
} | |||||
return JIM_OK; | |||||
} | |||||
int gdb_thread_packet(struct connection *connection, struct target *target, char *packet, int packet_size) | |||||
{ | |||||
if (strstr(packet, "qP")) | |||||
{ | |||||
#define TAG_THREADID 1 /* Echo the thread identifier */ | |||||
#define TAG_EXISTS 2 /* Is this process defined enough to | |||||
fetch registers and its stack */ | |||||
#define TAG_DISPLAY 4 /* A short thing maybe to put on a window */ | |||||
#define TAG_THREADNAME 8 /* string, maps 1-to-1 with a thread is */ | |||||
#define TAG_MOREDISPLAY 16 /* Whatever the kernel wants to say about */ | |||||
// TODO: need to scanf the mode variable (or it with the tags), and the threadid | |||||
unsigned long mode; | |||||
threadid_t threadid = 0; | |||||
struct thread_detail* detail; | |||||
sscanf(packet, "qP%8lx%16" SCNx64, &mode, &threadid); | |||||
int found = -1; | |||||
if ((target->rtos != NULL) && (target->rtos->thread_details | |||||
!= NULL)) { | |||||
int thread_num; | |||||
for (thread_num = 0; thread_num | |||||
< target->rtos->thread_count; thread_num++) { | |||||
if (target->rtos->thread_details[thread_num].threadid | |||||
== threadid) { | |||||
if (target->rtos->thread_details[thread_num].exists) { | |||||
found = thread_num; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
if (found == -1) { | |||||
gdb_put_packet(connection, "E01", 3); // thread not found | |||||
return ERROR_OK; | |||||
} | |||||
detail = &target->rtos->thread_details[found]; | |||||
if ( detail->display_str != NULL ) | |||||
{ | |||||
mode &= TAG_DISPLAY; | |||||
} | |||||
if ( detail->thread_name_str != NULL ) | |||||
{ | |||||
mode &= TAG_THREADNAME; | |||||
} | |||||
if ( detail->extra_info_str != NULL ) | |||||
{ | |||||
mode &= TAG_MOREDISPLAY; | |||||
} | |||||
mode &= TAG_THREADID | TAG_EXISTS; | |||||
char thread_str[1000]; | |||||
sprintf(thread_str, "%08lx", mode); | |||||
sprintf(thread_str, "%016" PRIx64, threadid); | |||||
if (mode & TAG_THREADID) { | |||||
sprintf(thread_str, "%08" PRIx32 "10%016" PRIx64, TAG_THREADID, threadid); | |||||
} | |||||
if (mode & TAG_EXISTS) { | |||||
sprintf(thread_str, "%08" PRIx32 "08%08" PRIx32, TAG_EXISTS, (detail->exists==true)?1:0); | |||||
} | |||||
if (mode & TAG_DISPLAY) { | |||||
sprintf(thread_str, "%08" PRIx32 "%02x%s", TAG_DISPLAY, (unsigned char)strlen(detail->display_str), detail->display_str ); | |||||
} | |||||
if (mode & TAG_MOREDISPLAY) { | |||||
sprintf(thread_str, "%08" PRIx32 "%02x%s", TAG_MOREDISPLAY, (unsigned char)strlen(detail->extra_info_str), detail->extra_info_str ); | |||||
} | |||||
if (mode & TAG_THREADNAME) { | |||||
sprintf(thread_str, "%08" PRIx32 "%02x%s", TAG_THREADNAME, (unsigned char)strlen(detail->thread_name_str), detail->thread_name_str ); | |||||
} | |||||
//gdb_put_packet(connection, tmpstr, sizeof(tmpstr)-1); | |||||
gdb_put_packet(connection, thread_str, strlen(thread_str)); | |||||
// gdb_put_packet(connection, "", 0); | |||||
// gdb_put_packet(connection, "OK", 2); // all threads alive | |||||
return ERROR_OK; | |||||
} | |||||
else if (strstr(packet, "qThreadExtraInfo,")) | |||||
{ | |||||
if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) && (target->rtos->thread_count != 0)) | |||||
{ | |||||
threadid_t threadid = 0; | |||||
int found = -1; | |||||
sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid ); | |||||
if ((target->rtos != NULL) && (target->rtos->thread_details | |||||
!= NULL)) { | |||||
int thread_num; | |||||
for (thread_num = 0; thread_num | |||||
< target->rtos->thread_count; thread_num++) { | |||||
if (target->rtos->thread_details[thread_num].threadid | |||||
== threadid) { | |||||
if (target->rtos->thread_details[thread_num].exists) { | |||||
found = thread_num; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
if (found == -1) { | |||||
gdb_put_packet(connection, "E01", 3); // thread not found | |||||
return ERROR_OK; | |||||
} | |||||
struct thread_detail* detail = &target->rtos->thread_details[found]; | |||||
int str_size = 0; | |||||
if ( detail->display_str != NULL ) | |||||
{ | |||||
str_size += strlen(detail->display_str); | |||||
} | |||||
if ( detail->thread_name_str != NULL ) | |||||
{ | |||||
str_size += strlen(detail->thread_name_str); | |||||
} | |||||
if ( detail->extra_info_str != NULL ) | |||||
{ | |||||
str_size += strlen(detail->extra_info_str); | |||||
} | |||||
char * tmp_str = (char*) malloc( str_size + 7 ); | |||||
char* tmp_str_ptr = tmp_str; | |||||
if ( detail->display_str != NULL ) | |||||
{ | |||||
tmp_str_ptr += sprintf( tmp_str_ptr, "%s", detail->display_str ); | |||||
} | |||||
if ( detail->thread_name_str != NULL ) | |||||
{ | |||||
if ( tmp_str_ptr != tmp_str ) | |||||
{ | |||||
tmp_str_ptr += sprintf( tmp_str_ptr, " : " ); | |||||
} | |||||
tmp_str_ptr += sprintf( tmp_str_ptr, "%s", detail->thread_name_str ); | |||||
} | |||||
if ( detail->extra_info_str != NULL ) | |||||
{ | |||||
if ( tmp_str_ptr != tmp_str ) | |||||
{ | |||||
tmp_str_ptr += sprintf( tmp_str_ptr, " : " ); | |||||
} | |||||
tmp_str_ptr += sprintf( tmp_str_ptr, " : %s", detail->extra_info_str ); | |||||
} | |||||
char * hex_str = (char*) malloc( strlen(tmp_str)*2 +1 ); | |||||
str_to_hex( hex_str, tmp_str ); | |||||
gdb_put_packet(connection, hex_str, strlen(hex_str)); | |||||
free(hex_str); | |||||
free(tmp_str); | |||||
return ERROR_OK; | |||||
} | |||||
gdb_put_packet(connection, "", 0); | |||||
return ERROR_OK; | |||||
} | |||||
else if (strstr(packet, "qSymbol")) | |||||
{ | |||||
if ( target->rtos != NULL ) | |||||
{ | |||||
int next_symbol_num = -1; | |||||
if (target->rtos->symbols == NULL) | |||||
{ | |||||
target->rtos->type->get_symbol_list_to_lookup( &target->rtos->symbols ); | |||||
} | |||||
if (0 == strcmp( "qSymbol::", packet ) ) | |||||
{ | |||||
// first query - | |||||
next_symbol_num = 0; | |||||
} | |||||
else | |||||
{ | |||||
long long value = 0; | |||||
char * hex_name_str = malloc( strlen(packet)); | |||||
char * name_str; | |||||
int symbol_num; | |||||
char* found = strstr( packet, "qSymbol::" ); | |||||
int numconv; | |||||
if (0 == found ) | |||||
{ | |||||
numconv =sscanf(packet, "qSymbol:%" SCNx64 ":%s", &value, hex_name_str); | |||||
} | |||||
else | |||||
{ | |||||
// No value returned by GDB - symbol was not found | |||||
numconv =sscanf(packet, "qSymbol::%s", hex_name_str); | |||||
} | |||||
name_str = (char*) malloc( 1+ strlen(hex_name_str) / 2 ); | |||||
hex_to_str( name_str, hex_name_str ); | |||||
symbol_num = 0; | |||||
while ( ( target->rtos->symbols[ symbol_num ].symbol_name != NULL ) && ( 0 != strcmp( target->rtos->symbols[ symbol_num ].symbol_name, name_str ) ) ) | |||||
{ | |||||
symbol_num++; | |||||
} | |||||
if ( target->rtos->symbols[ symbol_num ].symbol_name == NULL ) | |||||
{ | |||||
LOG_OUTPUT("ERROR: unknown symbol\r\n"); | |||||
gdb_put_packet(connection, "OK", 2); | |||||
return ERROR_OK; | |||||
} | |||||
target->rtos->symbols[ symbol_num ].address = value; | |||||
next_symbol_num = symbol_num+1; | |||||
free( hex_name_str ); | |||||
free( name_str ); | |||||
} | |||||
int symbols_done = 0; | |||||
if ( target->rtos->symbols[ next_symbol_num ].symbol_name == NULL ) | |||||
{ | |||||
if ( ( target->rtos_auto_detect == false ) || | |||||
( 1 == target->rtos->type->detect_rtos( target ) ) ) | |||||
{ | |||||
// Found correct RTOS or not autodetecting | |||||
if ( target->rtos_auto_detect == true ) | |||||
{ | |||||
LOG_OUTPUT( "Auto-detected RTOS: %s\r\n",target->rtos->type->name ); | |||||
} | |||||
symbols_done = 1; | |||||
} | |||||
else | |||||
{ | |||||
// Auto detecting RTOS and currently not found | |||||
if( 1 != rtos_try_next( target ) ) | |||||
{ | |||||
// No more RTOS's to try | |||||
symbols_done = 1; | |||||
} | |||||
else | |||||
{ | |||||
next_symbol_num = 0; | |||||
target->rtos->type->get_symbol_list_to_lookup( &target->rtos->symbols ); | |||||
} | |||||
} | |||||
} | |||||
if ( symbols_done == 1 ) | |||||
{ | |||||
target->rtos_auto_detect = false; | |||||
target->rtos->type->create( target ); | |||||
target->rtos->type->update_threads(target->rtos); | |||||
// No more symbols needed | |||||
gdb_put_packet(connection, "OK", 2); | |||||
return ERROR_OK; | |||||
} | |||||
else | |||||
{ | |||||
char* symname = target->rtos->symbols[ next_symbol_num ].symbol_name; | |||||
char qsymstr[] = "qSymbol:"; | |||||
char * opstring = (char*)malloc(sizeof(qsymstr)+strlen(symname)*2+1); | |||||
char * posptr = opstring; | |||||
posptr += sprintf( posptr, "%s", qsymstr ); | |||||
str_to_hex( posptr, symname ); | |||||
gdb_put_packet(connection, opstring, strlen(opstring)); | |||||
free(opstring); | |||||
return ERROR_OK; | |||||
} | |||||
} | |||||
gdb_put_packet(connection, "OK", 2); | |||||
return ERROR_OK; | |||||
} | |||||
else if (strstr(packet, "qfThreadInfo")) | |||||
{ | |||||
int i; | |||||
if ( ( target->rtos != NULL ) && ( target->rtos->thread_count != 0 ) ) | |||||
{ | |||||
char* out_str = (char*) malloc(17 * target->rtos->thread_count + 5); | |||||
char* tmp_str = out_str; | |||||
tmp_str += sprintf(tmp_str, "m"); | |||||
for (i = 0; i < target->rtos->thread_count; i++) { | |||||
if (i != 0) { | |||||
tmp_str += sprintf(tmp_str, ","); | |||||
} | |||||
tmp_str += sprintf(tmp_str, "%016" PRIx64, | |||||
target->rtos->thread_details[i].threadid); | |||||
} | |||||
tmp_str[0] = 0; | |||||
gdb_put_packet(connection, out_str, strlen(out_str)); | |||||
} | |||||
else | |||||
{ | |||||
gdb_put_packet(connection, "", 0); | |||||
} | |||||
return ERROR_OK; | |||||
} | |||||
else if (strstr(packet, "qsThreadInfo")) | |||||
{ | |||||
gdb_put_packet(connection, "l", 1); | |||||
return ERROR_OK; | |||||
} | |||||
else if (strstr(packet, "qAttached")) | |||||
{ | |||||
gdb_put_packet(connection, "1", 1); | |||||
return ERROR_OK; | |||||
} | |||||
else if (strstr(packet, "qOffsets")) | |||||
{ | |||||
char offsets[] = "Text=0;Data=0;Bss=0"; | |||||
gdb_put_packet(connection, offsets, sizeof(offsets)-1); | |||||
return ERROR_OK; | |||||
} | |||||
else if (strstr(packet, "qC")) | |||||
{ | |||||
gdb_put_packet(connection, "QC0", 3); | |||||
return ERROR_OK; | |||||
} | |||||
else if ( packet[0] == 'T' ) // Is thread alive? | |||||
{ | |||||
threadid_t threadid; | |||||
int found = -1; | |||||
sscanf(packet, "T%" SCNx64, &threadid); | |||||
if ((target->rtos != NULL) && (target->rtos->thread_details | |||||
!= NULL)) { | |||||
int thread_num; | |||||
for (thread_num = 0; thread_num | |||||
< target->rtos->thread_count; thread_num++) { | |||||
if (target->rtos->thread_details[thread_num].threadid | |||||
== threadid) { | |||||
if (target->rtos->thread_details[thread_num].exists) { | |||||
found = thread_num; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
if (found != -1) { | |||||
gdb_put_packet(connection, "OK", 2); // thread alive | |||||
} else { | |||||
gdb_put_packet(connection, "E01", 3); // thread not found | |||||
} | |||||
} | |||||
else if ( packet[0] == 'H') // Set current thread ( 'c' for step and continue, 'g' for all other operations ) | |||||
{ | |||||
if (packet[1] == 'g') | |||||
{ | |||||
sscanf(packet, "Hg%16" SCNx64, ¤t_threadid); | |||||
} | |||||
gdb_put_packet(connection, "OK", 2); | |||||
} | |||||
return GDB_THREAD_PACKET_NOT_CONSUMED; | |||||
} | |||||
int rtos_get_gdb_reg_list(struct connection *connection, struct target *target, struct reg **reg_list[], int *reg_list_size) | |||||
{ | |||||
if ( ( target->rtos != NULL ) && | |||||
( current_threadid != 1 ) && | |||||
( current_threadid != 0 ) && | |||||
( current_threadid != target->rtos->current_thread ) ) | |||||
{ | |||||
char * hex_reg_list; | |||||
target->rtos->type->get_thread_reg_list( target->rtos, current_threadid, &hex_reg_list ); | |||||
if ( hex_reg_list != NULL ) | |||||
{ | |||||
gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list)); | |||||
free(hex_reg_list); | |||||
return ERROR_OK; | |||||
} | |||||
} | |||||
return ERROR_FAIL; | |||||
} | |||||
int rtos_generic_stack_read( struct target * target, const struct rtos_register_stacking* stacking, long long stack_ptr, char ** hex_reg_list ) | |||||
{ | |||||
int list_size = 0; | |||||
char * tmp_str_ptr; | |||||
long long new_stack_ptr; | |||||
int i; | |||||
int retval; | |||||
if ( stack_ptr == 0) | |||||
{ | |||||
LOG_OUTPUT("Error: null stack pointer in thread\r\n"); | |||||
return -5; | |||||
} | |||||
// Read the stack | |||||
uint8_t * stack_data = (uint8_t*) malloc( stacking->stack_registers_size ); | |||||
uint32_t address = stack_ptr; | |||||
if ( stacking->stack_growth_direction == 1 ) | |||||
{ | |||||
address -= stacking->stack_registers_size; | |||||
} | |||||
retval = target_read_buffer( target, stack_ptr, stacking->stack_registers_size, stack_data); | |||||
if ( retval != ERROR_OK ) | |||||
{ | |||||
LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n"); | |||||
return retval; | |||||
} | |||||
/* | |||||
LOG_OUTPUT("Stack Data :"); | |||||
for(i = 0; i < stacking->stack_registers_size; i++ ) | |||||
{ | |||||
LOG_OUTPUT("%02X",stack_data[i]); | |||||
} | |||||
LOG_OUTPUT("\r\n"); | |||||
*/ | |||||
for( i = 0; i < stacking->num_output_registers; i++ ) | |||||
{ | |||||
list_size += stacking->register_offsets[i].width_bits/8; | |||||
} | |||||
*hex_reg_list = (char*)malloc( list_size*2 +1 ); | |||||
tmp_str_ptr = *hex_reg_list; | |||||
new_stack_ptr = stack_ptr + stacking->stack_growth_direction * stacking->stack_registers_size; | |||||
for( i = 0; i < stacking->num_output_registers; i++ ) | |||||
{ | |||||
int j; | |||||
for ( j = 0; j < stacking->register_offsets[i].width_bits/8; j++ ) | |||||
{ | |||||
if ( stacking->register_offsets[i].offset == -1 ) | |||||
{ | |||||
tmp_str_ptr += sprintf( tmp_str_ptr, "%02x", 0 ); | |||||
} | |||||
else if ( stacking->register_offsets[i].offset == -2 ) | |||||
{ | |||||
tmp_str_ptr += sprintf( tmp_str_ptr, "%02x", ((uint8_t*)&new_stack_ptr)[j] ); | |||||
} | |||||
else | |||||
{ | |||||
tmp_str_ptr += sprintf( tmp_str_ptr,"%02x", stack_data[ stacking->register_offsets[i].offset + j ] ); | |||||
} | |||||
} | |||||
} | |||||
// LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); | |||||
return ERROR_OK; | |||||
} | |||||
int rtos_try_next( struct target * target ) | |||||
{ | |||||
int x; | |||||
if ( target->rtos == NULL ) | |||||
{ | |||||
return -1; | |||||
} | |||||
for (x = 0 ; rtos_types[x] ; x++) { | |||||
if (target->rtos->type == rtos_types[x] ) { | |||||
/* found */ | |||||
if ( rtos_types[x+1] != NULL ) | |||||
{ | |||||
target->rtos->type = rtos_types[x+1]; | |||||
if ( target->rtos->symbols != NULL ) | |||||
{ | |||||
free( target->rtos->symbols ); | |||||
} | |||||
return 1; | |||||
} | |||||
else | |||||
{ | |||||
// No more rtos types | |||||
return 0; | |||||
} | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
static void hex_to_str( char* dst, char * hex_src ) | |||||
{ | |||||
int src_pos = 0; | |||||
int dst_pos = 0; | |||||
while ( hex_src[src_pos] != '\x00' ) | |||||
{ | |||||
char hex_char = hex_src[src_pos]; | |||||
char hex_digit_val = (hex_char>='a')?hex_char-'a'+10:(hex_char>='A')?hex_char-'A'+10:hex_char-'0'; | |||||
if ( 0 == (src_pos & 0x01) ) | |||||
{ | |||||
dst[dst_pos] = hex_digit_val; | |||||
dst[dst_pos+1] = 0; | |||||
} | |||||
else | |||||
{ | |||||
((unsigned char*)dst)[dst_pos] <<= 4; | |||||
((unsigned char*)dst)[dst_pos] += hex_digit_val; | |||||
dst_pos++; | |||||
} | |||||
src_pos++; | |||||
} | |||||
} | |||||
static int str_to_hex( char* hex_dst, char* src ) | |||||
{ | |||||
char * posptr = hex_dst; | |||||
unsigned i; | |||||
for( i = 0; i < strlen(src); i++) | |||||
{ | |||||
posptr += sprintf( posptr, "%02x", (unsigned char)src[i] ); | |||||
} | |||||
return (posptr-hex_dst); | |||||
} | |||||
int rtos_update_threads( struct target* target ) | |||||
{ | |||||
if ((target->rtos != NULL) && (target->rtos->type != NULL)) | |||||
{ | |||||
target->rtos->type->update_threads(target->rtos); | |||||
} | |||||
return ERROR_OK; | |||||
} |
@@ -0,0 +1,106 @@ | |||||
/*************************************************************************** | |||||
* Copyright (C) 2011 by Broadcom Corporation * | |||||
* Evan Hunter - ehunter@broadcom.com * | |||||
* * | |||||
* This program is free software; you can redistribute it and/or modify * | |||||
* it under the terms of the GNU General Public License as published by * | |||||
* the Free Software Foundation; either version 2 of the License, or * | |||||
* (at your option) any later version. * | |||||
* * | |||||
* This program is distributed in the hope that it will be useful, * | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |||||
* GNU General Public License for more details. * | |||||
* * | |||||
* You should have received a copy of the GNU General Public License * | |||||
* along with this program; if not, write to the * | |||||
* Free Software Foundation, Inc., * | |||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||||
***************************************************************************/ | |||||
#ifndef RTOS_H | |||||
#define RTOS_H | |||||
#include "server/server.h" | |||||
#include <helper/types.h> | |||||
#include <jim-nvp.h> | |||||
typedef long long threadid_t; | |||||
typedef long long symbol_address_t; | |||||
struct reg; | |||||
/** | |||||
* Table should be terminated by an element with NULL in symbol_name | |||||
*/ | |||||
typedef struct symbol_table_elem_struct | |||||
{ | |||||
char * symbol_name; | |||||
symbol_address_t address; | |||||
} symbol_table_elem_t; | |||||
struct thread_detail | |||||
{ | |||||
threadid_t threadid; | |||||
bool exists; | |||||
char * display_str; | |||||
char * thread_name_str; | |||||
char * extra_info_str; | |||||
}; | |||||
struct rtos | |||||
{ | |||||
const struct rtos_type *type; | |||||
symbol_table_elem_t * symbols; | |||||
struct target *target; | |||||
threadid_t current_thread; | |||||
struct thread_detail* thread_details; | |||||
int thread_count; | |||||
void * rtos_specific_params; | |||||
}; | |||||
struct rtos_type | |||||
{ | |||||
char * name; | |||||
int (*detect_rtos) ( struct target* target ); | |||||
int (*create) ( struct target* target ); | |||||
int (*update_threads) ( struct rtos* rtos ); | |||||
int (*get_thread_reg_list) ( struct rtos *rtos, long long thread_id, char ** hex_reg_list ); | |||||
int (*get_symbol_list_to_lookup) (symbol_table_elem_t * symbol_list[] ); | |||||
}; | |||||
struct stack_register_offset | |||||
{ | |||||
signed short offset; // offset in bytes from stack head, or -1 to indicate register is not stacked, or -2 to indicate this is the stack pointer register | |||||
unsigned short width_bits; | |||||
}; | |||||
struct rtos_register_stacking | |||||
{ | |||||
unsigned char stack_registers_size; | |||||
signed char stack_growth_direction; | |||||
unsigned char num_output_registers; | |||||
const struct stack_register_offset* register_offsets; | |||||
}; | |||||
#define GDB_THREAD_PACKET_NOT_CONSUMED (-40) | |||||
int rtos_create(Jim_GetOptInfo *goi, struct target * target); | |||||
int rtos_generic_stack_read( struct target * target, const struct rtos_register_stacking* stacking, long long stack_ptr, char ** hex_reg_list ); | |||||
int rtos_try_next( struct target * target ); | |||||
int gdb_thread_packet(struct connection *connection, struct target *target, char *packet, int packet_size); | |||||
int rtos_get_gdb_reg_list(struct connection *connection, struct target *target, struct reg **reg_list[], int *reg_list_size); | |||||
int rtos_update_threads( struct target *target ); | |||||
#endif // RTOS_H |
@@ -0,0 +1,65 @@ | |||||
/*************************************************************************** | |||||
* Copyright (C) 2011 by Broadcom Corporation * | |||||
* Evan Hunter - ehunter@broadcom.com * | |||||
* * | |||||
* This program is free software; you can redistribute it and/or modify * | |||||
* it under the terms of the GNU General Public License as published by * | |||||
* the Free Software Foundation; either version 2 of the License, or * | |||||
* (at your option) any later version. * | |||||
* * | |||||
* This program is distributed in the hope that it will be useful, * | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |||||
* GNU General Public License for more details. * | |||||
* * | |||||
* You should have received a copy of the GNU General Public License * | |||||
* along with this program; if not, write to the * | |||||
* Free Software Foundation, Inc., * | |||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||||
***************************************************************************/ | |||||
#ifdef HAVE_CONFIG_H | |||||
#include "config.h" | |||||
#endif | |||||
#include "rtos.h" | |||||
static const struct stack_register_offset rtos_standard_Cortex_M3_stack_offsets [] = | |||||
{ { 0x20, 32 }, // r0 | |||||
{ 0x24, 32 }, // r1 | |||||
{ 0x28, 32 }, // r2 | |||||
{ 0x2c, 32 }, // r3 | |||||
{ 0x00, 32 }, // r4 | |||||
{ 0x04, 32 }, // r5 | |||||
{ 0x08, 32 }, // r6 | |||||
{ 0x0c, 32 }, // r7 | |||||
{ 0x10, 32 }, // r8 | |||||
{ 0x14, 32 }, // r9 | |||||
{ 0x18, 32 }, // r10 | |||||
{ 0x1c, 32 }, // r11 | |||||
{ 0x30, 32 }, // r12 | |||||
{ -2, 32 }, // sp | |||||
{ 0x34, 32 }, // lr | |||||
{ 0x38, 32 }, // pc | |||||
{ -1, 96 }, // FPA1 | |||||
{ -1, 96 }, // FPA2 | |||||
{ -1, 96 }, // FPA3 | |||||
{ -1, 96 }, // FPA4 | |||||
{ -1, 96 }, // FPA5 | |||||
{ -1, 96 }, // FPA6 | |||||
{ -1, 96 }, // FPA7 | |||||
{ -1, 96 }, // FPA8 | |||||
{ -1, 32 }, // FPS | |||||
{ 0x3c, 32 }, // xPSR | |||||
}; | |||||
const struct rtos_register_stacking rtos_standard_Cortex_M3_stacking = | |||||
{ | |||||
0x40, // stack_registers_size | |||||
1, // stack_growth_direction | |||||
26, // num_output_registers | |||||
rtos_standard_Cortex_M3_stack_offsets // register_offsets | |||||
}; | |||||
@@ -0,0 +1,32 @@ | |||||
/*************************************************************************** | |||||
* Copyright (C) 2011 by Broadcom Corporation * | |||||
* Evan Hunter - ehunter@broadcom.com * | |||||
* * | |||||
* This program is free software; you can redistribute it and/or modify * | |||||
* it under the terms of the GNU General Public License as published by * | |||||
* the Free Software Foundation; either version 2 of the License, or * | |||||
* (at your option) any later version. * | |||||
* * | |||||
* This program is distributed in the hope that it will be useful, * | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |||||
* GNU General Public License for more details. * | |||||
* * | |||||
* You should have received a copy of the GNU General Public License * | |||||
* along with this program; if not, write to the * | |||||
* Free Software Foundation, Inc., * | |||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | |||||
***************************************************************************/ | |||||
#ifndef INCLUDED_RTOS_STANDARD_STACKINGS_H_ | |||||
#define INCLUDED_RTOS_STANDARD_STACKINGS_H_ | |||||
#ifdef HAVE_CONFIG_H | |||||
#include "config.h" | |||||
#endif | |||||
#include "rtos.h" | |||||
extern const struct rtos_register_stacking rtos_standard_Cortex_M3_stacking; | |||||
#endif //ifndef INCLUDED_RTOS_STANDARD_STACKINGS_H_ |
@@ -8,6 +8,9 @@ | |||||
* Copyright (C) 2008 by Spencer Oliver * | * Copyright (C) 2008 by Spencer Oliver * | ||||
* spen@spen-soft.co.uk * | * spen@spen-soft.co.uk * | ||||
* * | * * | ||||
* Copyright (C) 2011 by Broadcom Corporation * | |||||
* Evan Hunter - ehunter@broadcom.com * | |||||
* * | |||||
* This program is free software; you can redistribute it and/or modify * | * This program is free software; you can redistribute it and/or modify * | ||||
* it under the terms of the GNU General Public License as published by * | * it under the terms of the GNU General Public License as published by * | ||||
* the Free Software Foundation; either version 2 of the License, or * | * the Free Software Foundation; either version 2 of the License, or * | ||||
@@ -35,6 +38,7 @@ | |||||
#include "gdb_server.h" | #include "gdb_server.h" | ||||
#include <target/image.h> | #include <target/image.h> | ||||
#include <jtag/jtag.h> | #include <jtag/jtag.h> | ||||
#include "rtos/rtos.h" | |||||
/** | /** | ||||
@@ -479,7 +483,7 @@ static int gdb_put_packet_inner(struct connection *connection, | |||||
return ERROR_OK; | return ERROR_OK; | ||||
} | } | ||||
static int gdb_put_packet(struct connection *connection, char *buffer, int len) | |||||
int gdb_put_packet(struct connection *connection, char *buffer, int len) | |||||
{ | { | ||||
struct gdb_connection *gdb_con = connection->priv; | struct gdb_connection *gdb_con = connection->priv; | ||||
gdb_con->busy = 1; | gdb_con->busy = 1; | ||||
@@ -767,6 +771,7 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec | |||||
snprintf(sig_reply, 4, "T%2.2x", signal_var); | snprintf(sig_reply, 4, "T%2.2x", signal_var); | ||||
gdb_put_packet(connection, sig_reply, 3); | gdb_put_packet(connection, sig_reply, 3); | ||||
gdb_connection->frontend_state = TARGET_HALTED; | gdb_connection->frontend_state = TARGET_HALTED; | ||||
rtos_update_threads( target ); | |||||
} | } | ||||
} | } | ||||
@@ -1034,6 +1039,12 @@ static int gdb_get_registers_packet(struct connection *connection, | |||||
LOG_DEBUG("-"); | LOG_DEBUG("-"); | ||||
#endif | #endif | ||||
if ( ( target->rtos != NULL ) && | |||||
( ERROR_FAIL != rtos_get_gdb_reg_list( connection, target, ®_list, ®_list_size) ) ) | |||||
{ | |||||
return ERROR_OK; | |||||
} | |||||
if ((retval = target_get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK) | if ((retval = target_get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK) | ||||
{ | { | ||||
return gdb_error(connection, retval); | return gdb_error(connection, retval); | ||||
@@ -2187,16 +2198,23 @@ static int gdb_input_inner(struct connection *connection) | |||||
retval = ERROR_OK; | retval = ERROR_OK; | ||||
switch (packet[0]) | switch (packet[0]) | ||||
{ | { | ||||
case 'H': | |||||
/* Hct... -- set thread | |||||
* we don't have threads, send empty reply */ | |||||
gdb_put_packet(connection, NULL, 0); | |||||
break; | |||||
case 'T': // Is thread alive? | |||||
gdb_thread_packet(connection, target, packet, packet_size); | |||||
break; | |||||
case 'H': // Set current thread ( 'c' for step and continue, 'g' for all other operations ) | |||||
gdb_thread_packet(connection, target, packet, packet_size); | |||||
break; | |||||
case 'q': | case 'q': | ||||
case 'Q': | case 'Q': | ||||
retval = gdb_query_packet(connection, | |||||
target, packet, | |||||
packet_size); | |||||
retval = gdb_thread_packet(connection, | |||||
target, packet, | |||||
packet_size); | |||||
if ( retval == GDB_THREAD_PACKET_NOT_CONSUMED ) | |||||
{ | |||||
retval = gdb_query_packet(connection, | |||||
target, packet, | |||||
packet_size); | |||||
} | |||||
break; | break; | ||||
case 'g': | case 'g': | ||||
retval = gdb_get_registers_packet( | retval = gdb_get_registers_packet( | ||||
@@ -8,6 +8,9 @@ | |||||
* Copyright (C) 2008 by Spencer Oliver * | * Copyright (C) 2008 by Spencer Oliver * | ||||
* spen@spen-soft.co.uk * | * spen@spen-soft.co.uk * | ||||
* * | * * | ||||
* Copyright (C) 2011 by Broadcom Corporation * | |||||
* Evan Hunter - ehunter@broadcom.com * | |||||
* * | |||||
* This program is free software; you can redistribute it and/or modify * | * This program is free software; you can redistribute it and/or modify * | ||||
* it under the terms of the GNU General Public License as published by * | * it under the terms of the GNU General Public License as published by * | ||||
* the Free Software Foundation; either version 2 of the License, or * | * the Free Software Foundation; either version 2 of the License, or * | ||||
@@ -39,6 +42,8 @@ struct gdb_service | |||||
int gdb_target_add_all(struct target *target); | int gdb_target_add_all(struct target *target); | ||||
int gdb_register_commands(struct command_context *command_context); | int gdb_register_commands(struct command_context *command_context); | ||||
int gdb_put_packet(struct connection *connection, char *buffer, int len); | |||||
#define ERROR_GDB_BUFFER_TOO_SMALL (-800) | #define ERROR_GDB_BUFFER_TOO_SMALL (-800) | ||||
#define ERROR_GDB_TIMEOUT (-801) | #define ERROR_GDB_TIMEOUT (-801) | ||||
@@ -14,6 +14,9 @@ | |||||
* Copyright (C) 2008 by Rick Altherr * | * Copyright (C) 2008 by Rick Altherr * | ||||
* kc8apf@kc8apf.net> * | * kc8apf@kc8apf.net> * | ||||
* * | * * | ||||
* Copyright (C) 2011 by Broadcom Corporation * | |||||
* Evan Hunter - ehunter@broadcom.com * | |||||
* * | |||||
* This program is free software; you can redistribute it and/or modify * | * This program is free software; you can redistribute it and/or modify * | ||||
* it under the terms of the GNU General Public License as published by * | * it under the terms of the GNU General Public License as published by * | ||||
* the Free Software Foundation; either version 2 of the License, or * | * the Free Software Foundation; either version 2 of the License, or * | ||||
@@ -44,6 +47,7 @@ | |||||
#include "register.h" | #include "register.h" | ||||
#include "trace.h" | #include "trace.h" | ||||
#include "image.h" | #include "image.h" | ||||
#include "rtos/rtos.h" | |||||
static int target_read_buffer_default(struct target *target, uint32_t address, | static int target_read_buffer_default(struct target *target, uint32_t address, | ||||
@@ -3704,6 +3708,7 @@ enum target_cfg_param { | |||||
TCFG_COREID, | TCFG_COREID, | ||||
TCFG_CHAIN_POSITION, | TCFG_CHAIN_POSITION, | ||||
TCFG_DBGBASE, | TCFG_DBGBASE, | ||||
TCFG_RTOS, | |||||
}; | }; | ||||
static Jim_Nvp nvp_config_opts[] = { | static Jim_Nvp nvp_config_opts[] = { | ||||
@@ -3718,6 +3723,7 @@ static Jim_Nvp nvp_config_opts[] = { | |||||
{ .name = "-coreid", .value = TCFG_COREID }, | { .name = "-coreid", .value = TCFG_COREID }, | ||||
{ .name = "-chain-position", .value = TCFG_CHAIN_POSITION }, | { .name = "-chain-position", .value = TCFG_CHAIN_POSITION }, | ||||
{ .name = "-dbgbase", .value = TCFG_DBGBASE }, | { .name = "-dbgbase", .value = TCFG_DBGBASE }, | ||||
{ .name = "-rtos", .value = TCFG_RTOS }, | |||||
{ .name = NULL, .value = -1 } | { .name = NULL, .value = -1 } | ||||
}; | }; | ||||
@@ -4024,6 +4030,18 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) | |||||
Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->dbgbase)); | Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->dbgbase)); | ||||
/* loop for more */ | /* loop for more */ | ||||
break; | break; | ||||
case TCFG_RTOS: | |||||
/* RTOS */ | |||||
{ | |||||
int result = rtos_create( goi, target ); | |||||
if ( result != JIM_OK ) | |||||
{ | |||||
return result; | |||||
} | |||||
} | |||||
/* loop for more */ | |||||
break; | |||||
} | } | ||||
} /* while (goi->argc) */ | } /* while (goi->argc) */ | ||||
@@ -4746,6 +4764,9 @@ static int target_create(Jim_GetOptInfo *goi) | |||||
target->endianness = TARGET_ENDIAN_UNKNOWN; | target->endianness = TARGET_ENDIAN_UNKNOWN; | ||||
target->rtos = NULL; | |||||
target->rtos_auto_detect = false; | |||||
/* Do the rest as "configure" options */ | /* Do the rest as "configure" options */ | ||||
goi->isconfigure = 1; | goi->isconfigure = 1; | ||||
e = target_configure(goi, target); | e = target_configure(goi, target); | ||||
@@ -8,6 +8,9 @@ | |||||
* Copyright (C) 2008 by Spencer Oliver * | * Copyright (C) 2008 by Spencer Oliver * | ||||
* spen@spen-soft.co.uk * | * spen@spen-soft.co.uk * | ||||
* * | * * | ||||
* Copyright (C) 2011 by Broadcom Corporation * | |||||
* Evan Hunter - ehunter@broadcom.com * | |||||
* * | |||||
* This program is free software; you can redistribute it and/or modify * | * This program is free software; you can redistribute it and/or modify * | ||||
* it under the terms of the GNU General Public License as published by * | * it under the terms of the GNU General Public License as published by * | ||||
* the Free Software Foundation; either version 2 of the License, or * | * the Free Software Foundation; either version 2 of the License, or * | ||||
@@ -160,6 +163,9 @@ struct target | |||||
uint32_t dbgbase; /* Really a Cortex-A specific option, but there is no | uint32_t dbgbase; /* Really a Cortex-A specific option, but there is no | ||||
system in place to support target specific options | system in place to support target specific options | ||||
currently. */ | currently. */ | ||||
struct rtos *rtos; /* Instance of Real Time Operating System support */ | |||||
bool rtos_auto_detect; /* A flag that indicates that the RTOS has been specified as "auto" | |||||
* and must be detected when symbols are offered */ | |||||
}; | }; | ||||
/** Returns the instance-specific name of the specified target. */ | /** Returns the instance-specific name of the specified target. */ | ||||