1 /*==========================================================================
5 // GDB Debugging Interface
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
44 // Contributors: nickg
46 // Purpose: GDB Debugging Interface
47 // Description: Interface for calls from GDB stubs into the OS. These
48 // currently mostly support thread awareness.
50 //####DESCRIPTIONEND####
52 //========================================================================*/
54 #include <pkgconf/kernel.h>
55 #include <pkgconf/hal.h> // CYG_HAL_USE_ROM_MONITOR_CYGMON
57 #ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
59 #include <cyg/kernel/ktypes.h>
61 #include <cyg/kernel/thread.hxx>
62 #include <cyg/kernel/sched.hxx>
64 #include <cyg/kernel/thread.inl>
65 #include <cyg/kernel/sched.inl>
67 #include <cyg/hal/hal_arch.h>
68 #include <cyg/hal/hal_stub.h>
72 #include <cyg/hal/dbg-threads-api.h>
77 #if (CYG_BYTEORDER == CYG_LSBFIRST)
79 unsigned long swap32(unsigned long x)
84 r |= ((x>>16)&0xFF)<<8;
85 r |= ((x>>8)&0xFF)<<16;
93 #define swap32(x) ((unsigned long)(x))
97 //--------------------------------------------------------------------------
99 externC int dbg_thread_capabilities(struct dbg_capabilities * cpb)
101 cpb->mask1 = has_thread_current |
102 has_thread_registers |
103 has_thread_reg_change |
109 //--------------------------------------------------------------------------
111 static void dbg_make_threadref(Cyg_Thread *thread, threadref *ref )
113 // The following test tries to avoid accessing uninitialized pointers.
114 // This can happen if we take a breakpoint before the data is copied
115 // or the BSS zeroed. We currently assume that RAM will reset to zero
116 // or 0xff. If it is random, we have no hope.
118 if( (CYG_ADDRWORD)thread == 0 || (CYG_ADDRWORD)thread == 0xffffffff )
120 ((unsigned long *)ref)[0] = 0;
121 ((unsigned long *)ref)[1] = 0;
125 cyg_uint16 id = thread->get_unique_id();
128 ((unsigned long *)ref)[0] = (unsigned long)thread;
129 ((unsigned long *)ref)[1] = (unsigned long)swap32(id);
131 ((unsigned long *)ref)[1] = (unsigned long)thread;
132 ((unsigned long *)ref)[0] = (unsigned long)id;
137 static Cyg_Thread *dbg_get_thread( threadref *ref)
143 id = (cyg_uint16)swap32(((unsigned long *)ref)[1]);
145 Cyg_Thread *th = Cyg_Thread::get_list_head();
148 if( th->get_unique_id() == id ) break;
149 th = th->get_list_next();
152 // if( thread->get_unique_id() != id ) th = 0;
158 Cyg_Thread *thread = (Cyg_Thread *)(((unsigned long *)ref)[1]);
159 id = (cyg_uint16)(((unsigned long *)ref)[0]);
161 // Validate the thread.
162 Cyg_Thread *th = Cyg_Thread::get_list_head();
165 if( th == thread ) break;
166 th = th->get_list_next();
169 // if( thread->get_unique_id() != id ) th = 0;
176 //--------------------------------------------------------------------------
178 externC int dbg_currthread(threadref * varparm)
180 Cyg_Thread *thread = Cyg_Scheduler::get_current_thread();
182 dbg_make_threadref(thread, varparm );
187 //--------------------------------------------------------------------------
189 externC int dbg_thread_id(threadref *threadid)
191 Cyg_Thread *thread = dbg_get_thread(threadid);
192 if( thread == 0 ) return 0;
193 return thread->get_unique_id ();
196 //--------------------------------------------------------------------------
198 externC int dbg_currthread_id(void)
200 Cyg_Thread *thread = Cyg_Scheduler::get_current_thread();
201 return thread->get_unique_id ();
204 //--------------------------------------------------------------------------
206 externC int dbg_threadlist(int startflag,
207 threadref * lastthreadid,
208 threadref * next_thread)
213 thread = Cyg_Thread::get_list_head();
214 dbg_make_threadref(thread, next_thread);
218 thread = dbg_get_thread(lastthreadid);
220 if( thread == 0 ) return 0;
221 thread = thread->get_list_next();
223 if( thread == 0 ) return 0;
224 dbg_make_threadref(thread, next_thread);
229 //--------------------------------------------------------------------------
230 // Some support routines for manufacturing thread info strings
232 static char *dbg_addstr(char *s, char *t)
234 while( (*s++ = *t++) != 0 );
239 static char *dbg_addint(char *s, int n, int base)
244 char *digits = (char *)"0123456789ABCDEF";
246 if( n < 0 ) n = -n, sign = '-';
248 /* Set pos to start */
251 /* construct digits into buffer in reverse order */
252 if( n == 0 ) buf[bpos++] = '0';
255 cyg_ucount8 d = n % base;
256 buf[bpos++] = digits[d];
260 /* set sign if negative. */
267 /* Now write it out in correct order. */
276 static char *dbg_adddec(char *s, int x)
278 return dbg_addint(s, x, 10);
281 //--------------------------------------------------------------------------
283 externC int dbg_threadinfo(
284 threadref * threadid,
285 struct cygmon_thread_debug_info * info)
287 static char statebuf[60];
289 Cyg_Thread *thread = dbg_get_thread(threadid);
290 if( thread == 0 ) return 0;
292 info->context_exists = 1;
294 char *sbp = statebuf;
297 if( thread->get_state() & Cyg_Thread::SUSPENDED )
299 sbp = dbg_addstr( sbp, (char *)"suspended+");
302 switch( thread->get_state() & ~Cyg_Thread::SUSPENDED )
304 case Cyg_Thread::RUNNING:
305 if ( Cyg_Scheduler::get_current_thread() == thread ) {
306 s = (char *)"running"; break;
308 else if ( thread->get_state() & Cyg_Thread::SUSPENDED ) {
309 s = (char *)""; sbp--; /*kill '+'*/ break;
312 s = (char *)"ready"; break;
314 case Cyg_Thread::SLEEPING:
315 s = (char *)"sleeping"; break;
316 case Cyg_Thread::COUNTSLEEP | Cyg_Thread::SLEEPING:
317 case Cyg_Thread::COUNTSLEEP:
318 s = (char *)"counted sleep"; break;
319 case Cyg_Thread::CREATING:
320 s = (char *)"creating"; sbp = statebuf; break;
321 case Cyg_Thread::EXITED:
322 s = (char *)"exited"; sbp = statebuf; break;
324 s = (char *)"unknown state"; break;
327 sbp = dbg_addstr( sbp, s );
328 sbp = dbg_addstr( sbp, (char *)", Priority: " );
329 sbp = dbg_adddec( sbp, thread->get_priority() );
331 info->thread_display = statebuf;
333 #ifdef CYGVAR_KERNEL_THREADS_NAME
334 info->unique_thread_name = thread->get_name();
336 info->unique_thread_name = 0;
339 info->more_display = 0;
344 //--------------------------------------------------------------------------
346 externC int dbg_getthreadreg(
347 threadref * osthreadid,
348 int regcount, /* count of registers in the array */
349 void * regval) /* fillin this array */
351 Cyg_Thread *thread = dbg_get_thread(osthreadid);
353 if( thread == 0 ) return 0;
355 if( thread == Cyg_Scheduler::get_current_thread() )
357 #if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON)
358 // We have no state for the current thread, Cygmon has
359 // got that and we cannot get at it.
361 #elif defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
362 // registers hold the state of the current thread.
363 __stub_copy_registers ((target_register_t *)regval, registers);
370 HAL_SavedRegisters *regs = thread->get_saved_context();
371 if( regs == 0 ) return 0;
373 HAL_GET_GDB_REGISTERS (regval, regs);
379 //--------------------------------------------------------------------------
381 externC int dbg_setthreadreg(
382 threadref * osthreadid,
383 int regcount , /* number of registers */
386 Cyg_Thread *thread = dbg_get_thread(osthreadid);
388 if( thread == 0 ) return 0;
390 if( thread == Cyg_Scheduler::get_current_thread() )
392 #if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON)
393 // We have no state for the current thread, Cygmon has
394 // got that and we cannot get at it.
396 #elif defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
397 // registers hold the state of the current thread.
398 __stub_copy_registers (registers, (target_register_t *)regval);
405 HAL_SavedRegisters *regs = thread->get_saved_context();
406 if( regs == 0 ) return 0;
408 HAL_SET_GDB_REGISTERS (regs, regval);
414 //--------------------------------------------------------------------------
415 // Thread scheduler control for debugger.
417 // osthreadid : must match currently executing thread.
418 // Future use: change the currently executing thread.
419 // lock : 0 == unlock scheduler, 1 == lock scheduler
420 // mode : 0 == single-instruction step, 1 == free running
425 // -1 == request that the caller handle this itself
426 // (eg.by disabling interrupts)
429 externC int dbg_scheduler(
430 threadref * osthreadid,
431 int lock, /* 0 == unlock, 1 == lock */
432 int mode) /* 0 == step, 1 == continue */
435 /* Minimal implementation: let stub do the work. */
436 return -1; // Stub will disable interrupts
438 Cyg_Thread *thread = dbg_get_thread(osthreadid);
440 if( thread == 0 ) return 0; // fail
442 if( thread == Cyg_Scheduler::get_current_thread() )
448 Cyg_Scheduler::lock();
452 if (Cyg_Scheduler::get_sched_lock() >= 1)
453 Cyg_Scheduler::unlock_simple();
459 // Cannot accept any thread other than current one
466 #endif // CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
468 //--------------------------------------------------------------------------
469 // End of dbg_gdb.cxx