Browse Source

RTOS Thread awareness support wip

- 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
Broadcom Corporation (Evan Hunter) 13 years ago
committed by Øyvind Harboe
parent
commit
b69119668e
13 changed files with 1975 additions and 10 deletions
  1. +1
    -0
      configure.in
  2. +3
    -1
      src/Makefile.am
  3. +481
    -0
      src/rtos/FreeRTOS.c
  4. +35
    -0
      src/rtos/Makefile.am
  5. +536
    -0
      src/rtos/ThreadX.c
  6. +657
    -0
      src/rtos/rtos.c
  7. +106
    -0
      src/rtos/rtos.h
  8. +65
    -0
      src/rtos/rtos_standard_stackings.c
  9. +32
    -0
      src/rtos/rtos_standard_stackings.h
  10. +27
    -9
      src/server/gdb_server.c
  11. +5
    -0
      src/server/gdb_server.h
  12. +21
    -0
      src/target/target.c
  13. +6
    -0
      src/target/target.h

+ 1
- 0
configure.in View File

@@ -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


+ 3
- 1
src/Makefile.am View File

@@ -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)




+ 481
- 0
src/rtos/FreeRTOS.c View File

@@ -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;
}

+ 35
- 0
src/rtos/Makefile.am View File

@@ -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

+ 536
- 0
src/rtos/ThreadX.c View File

@@ -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;
}

+ 657
- 0
src/rtos/rtos.c View File

@@ -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, &current_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;
}

+ 106
- 0
src/rtos/rtos.h View File

@@ -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

+ 65
- 0
src/rtos/rtos_standard_stackings.c View File

@@ -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
};



+ 32
- 0
src/rtos/rtos_standard_stackings.h View File

@@ -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_

+ 27
- 9
src/server/gdb_server.c View File

@@ -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, &reg_list, &reg_list_size) ) )
{
return ERROR_OK;
}

if ((retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK) if ((retval = target_get_gdb_reg_list(target, &reg_list, &reg_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(


+ 5
- 0
src/server/gdb_server.h View File

@@ -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)




+ 21
- 0
src/target/target.c View File

@@ -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);


+ 6
- 0
src/target/target.h View File

@@ -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. */


Loading…
Cancel
Save