Mercurial > ecos
diff packages/kernel/current/src/debug/dbg_gdb.cxx @ 0:3111d98ba7b3 ecos-v1_1-release
Initial commit of eCos version 1.1
| author | jlarmour |
|---|---|
| date | Tue, 11 May 1999 11:16:07 +0000 |
| parents | |
| children | 443894e2e912 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/kernel/current/src/debug/dbg_gdb.cxx @@ -0,0 +1,388 @@ +/*========================================================================== +// +// dbg_gdb.c +// +// GDB Debugging Interface +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Cygnus eCos Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://sourceware.cygnus.com/ecos +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Cygnus Operating System, released +// September 30, 1998. +// +// The Initial Developer of the Original Code is Cygnus. Portions created +// by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg +// Contributors: nickg +// Date: 1998-08-22 +// Purpose: GDB Debugging Interface +// Description: Interface for calls from GDB stubs into the OS. These +// currently mostly support thread awareness. +// +//####DESCRIPTIONEND#### +// +//========================================================================*/ + +#include <pkgconf/kernel.h> +#include <pkgconf/hal.h> // CYG_HAL_USE_ROM_MONITOR_CYGMON + +#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT + +#include <cyg/kernel/ktypes.h> + +#include <cyg/kernel/thread.hxx> +#include <cyg/kernel/sched.hxx> + +#include <cyg/kernel/thread.inl> +#include <cyg/kernel/sched.inl> + +#include <cyg/hal/hal_arch.h> + +#if !defined(CYG_HAL_USE_ROM_MONITOR_CYGMON) \ + && defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS) +// FIXME: This really needs to be handled in some other way. +#include <cyg/hal/hal_stub.h> +externC void __stub_copy_registers(target_register_t * dest, + target_register_t *src); +#endif + +extern "C" +{ +#include <cyg/hal/dbg-threads-api.h> +}; + +#define USE_ID 1 + +#if (CYG_BYTEORDER == CYG_LSBFIRST) + +unsigned long swap32(unsigned long x) +{ + unsigned long r = 0; + + r |= (x>>24)&0xFF; + r |= ((x>>16)&0xFF)<<8; + r |= ((x>>8)&0xFF)<<16; + r |= ((x)&0xFF)<<24; + + return r; +} + +#else + +#define swap32(x) ((unsigned long)(x)) + +#endif + +//-------------------------------------------------------------------------- + +externC int dbg_thread_capabilities(struct dbg_capabilities * cpb) +{ + cpb->mask1 = has_thread_current | + has_thread_registers | + has_thread_reg_change | + has_thread_list | + has_thread_info ; + return 1 ; +} + +//-------------------------------------------------------------------------- + +static void dbg_make_threadref(Cyg_Thread *thread, threadref *ref ) +{ + cyg_uint16 id = thread->get_unique_id(); + +#if USE_ID + ((unsigned long *)ref)[0] = (unsigned long)thread; + ((unsigned long *)ref)[1] = (unsigned long)swap32(id); +#else + ((unsigned long *)ref)[1] = (unsigned long)thread; + ((unsigned long *)ref)[0] = (unsigned long)id; +#endif + +} + +static Cyg_Thread *dbg_get_thread( threadref *ref) +{ +#if USE_ID + + cyg_uint16 id = 0; + + id = (cyg_uint16)swap32(((unsigned long *)ref)[1]); + + Cyg_Thread *th = Cyg_Thread::get_list_head(); + while( th != 0 ) + { + if( th->get_unique_id() == id ) break; + th = th->get_list_next(); + } + +// if( thread->get_unique_id() != id ) th = 0; + +#else + + cyg_uint16 id = 0; + + Cyg_Thread *thread = (Cyg_Thread *)(((unsigned long *)ref)[1]); + id = (cyg_uint16)(((unsigned long *)ref)[0]); + + // Validate the thread. + Cyg_Thread *th = Cyg_Thread::get_list_head(); + while( th != 0 ) + { + if( th == thread ) break; + th = th->get_list_next(); + } + +// if( thread->get_unique_id() != id ) th = 0; + +#endif + + return th; +} + +//-------------------------------------------------------------------------- + +externC int dbg_currthread(threadref * varparm) +{ + Cyg_Thread *thread = Cyg_Scheduler::get_current_thread(); + + dbg_make_threadref(thread, varparm ); + + return 1 ; +} + +//-------------------------------------------------------------------------- + +externC int dbg_currthread_id(void) +{ + Cyg_Thread *thread = Cyg_Scheduler::get_current_thread(); + return thread->get_unique_id (); +} + +//-------------------------------------------------------------------------- + +externC int dbg_threadlist(int startflag, + threadref * lastthreadid, + threadref * next_thread) +{ + Cyg_Thread *thread; + if( startflag ) + { + thread = Cyg_Thread::get_list_head(); + dbg_make_threadref(thread, next_thread); + } + else + { + thread = dbg_get_thread(lastthreadid); + + if( thread == 0 ) return 0; + thread = thread->get_list_next(); + + if( thread == 0 ) return 0; + dbg_make_threadref(thread, next_thread); + } + return 1 ; +} + +//-------------------------------------------------------------------------- +// Some support routines for manufacturing thread info strings + +static char *dbg_addstr(char *s, char *t) +{ + while( (*s++ = *t++) != 0 ); + + return s-1; +} + +static char *dbg_addint(char *s, int n, int base) +{ + char buf[16]; + char sign = '+'; + cyg_count8 bpos; + char *digits = "0123456789ABCDEF"; + + if( n < 0 ) n = -n, sign = '-'; + + /* Set pos to start */ + bpos = 0; + + /* construct digits into buffer in reverse order */ + if( n == 0 ) buf[bpos++] = '0'; + else while( n != 0 ) + { + cyg_ucount8 d = n % base; + buf[bpos++] = digits[d]; + n /= base; + } + + /* set sign if negative. */ + if( sign == '-' ) + { + buf[bpos] = sign; + } + else bpos--; + + /* Now write it out in correct order. */ + while( bpos >= 0 ) + *s++ = buf[bpos--]; + + *s = 0; + + return s; +} + +static char *dbg_adddec(char *s, int x) +{ + return dbg_addint(s, x, 10); +} + +//-------------------------------------------------------------------------- + +externC int dbg_threadinfo( + threadref * threadid, + struct cygmon_thread_debug_info * info) +{ + static char statebuf[60]; + + Cyg_Thread *thread = dbg_get_thread(threadid); + if( thread == 0 ) return 0; + + info->context_exists = 1; + + char *sbp = statebuf; + char *s; + + if( thread->get_state() & Cyg_Thread::SUSPENDED ) + { + sbp = dbg_addstr( sbp, "suspended+"); + } + + switch( thread->get_state() & ~Cyg_Thread::SUSPENDED ) + { + case Cyg_Thread::RUNNING: + s = "running"; break; + case Cyg_Thread::SLEEPING: + s = "sleeping"; break; + case Cyg_Thread::COUNTSLEEP: + s = "counted sleep"; break; + case Cyg_Thread::CREATING: + s = "creating"; break; + case Cyg_Thread::EXITED: + s = "exited"; break; + default: + s = "unknown state"; break; + } + + sbp = dbg_addstr( sbp, s ); + sbp = dbg_addstr( sbp, ", Priority: " ); + sbp = dbg_adddec( sbp, thread->get_priority() ); + + info->thread_display = statebuf; + +#ifdef CYGVAR_KERNEL_THREADS_NAME + info->unique_thread_name = thread->get_name(); +#else + info->unique_thread_name = 0; +#endif + + info->more_display = 0; + + return 1 ; +} + +//-------------------------------------------------------------------------- + +externC int dbg_getthreadreg( + threadref * osthreadid, + int regcount, /* count of registers in the array */ + void * regval) /* fillin this array */ +{ + Cyg_Thread *thread = dbg_get_thread(osthreadid); + + if( thread == 0 ) return 0; + + if( thread == Cyg_Scheduler::get_current_thread() ) + { +#if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON) + // We have no state for the current thread, Cygmon has + // got that and we cannot get at it. + return 0; +#elif defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS) + // _registers hold the state of the current thread. + extern target_register_t * _registers; + + __stub_copy_registers ((target_register_t *)regval, _registers); +#else + return 0; +#endif + } + else + { + HAL_SavedRegisters *regs = thread->get_saved_context(); + if( regs == 0 ) return 0; + + HAL_GET_GDB_REGISTERS (regval, regs); + } + + return 1 ; +} + +//-------------------------------------------------------------------------- + +externC int dbg_setthreadreg( + threadref * osthreadid, + int regcount , /* number of registers */ + void * regval) +{ + Cyg_Thread *thread = dbg_get_thread(osthreadid); + + if( thread == 0 ) return 0; + + if( thread == Cyg_Scheduler::get_current_thread() ) + { +#if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON) + // We have no state for the current thread, Cygmon has + // got that and we cannot get at it. + return 0; +#elif defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS) + // _registers hold the state of the current thread. + extern target_register_t * _registers; + + __stub_copy_registers (_registers, (target_register_t *)regval); +#else + return 0; +#endif + } + else + { + HAL_SavedRegisters *regs = thread->get_saved_context(); + if( regs == 0 ) return 0; + + HAL_SET_GDB_REGISTERS (regs, regval); + } + + + return 1; +} + +#endif // CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT + +//-------------------------------------------------------------------------- +// End of dbg_gdb.cxx
