]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/kernel/v2_0/src/debug/dbg_gdb.cxx
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / kernel / v2_0 / src / debug / dbg_gdb.cxx
1 /*==========================================================================
2 //
3 //      dbg_gdb.c
4 //
5 //      GDB Debugging Interface
6 //
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.
12 //
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.
16 //
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
20 // for more details.
21 //
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.
25 //
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.
32 //
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.
35 //
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####
42 //
43 // Author(s):   nickg
44 // Contributors:        nickg
45 // Date:        1998-08-22
46 // Purpose:     GDB Debugging Interface
47 // Description: Interface for calls from GDB stubs into the OS. These
48 //              currently mostly support thread awareness.
49 //
50 //####DESCRIPTIONEND####
51 //
52 //========================================================================*/
53
54 #include <pkgconf/kernel.h>
55 #include <pkgconf/hal.h>                // CYG_HAL_USE_ROM_MONITOR_CYGMON
56
57 #ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
58
59 #include <cyg/kernel/ktypes.h>
60
61 #include <cyg/kernel/thread.hxx>
62 #include <cyg/kernel/sched.hxx>
63
64 #include <cyg/kernel/thread.inl>
65 #include <cyg/kernel/sched.inl>
66
67 #include <cyg/hal/hal_arch.h>
68 #include <cyg/hal/hal_stub.h>
69
70 extern "C"
71 {
72 #include <cyg/hal/dbg-threads-api.h>
73 };
74
75 #define USE_ID 1
76
77 #if (CYG_BYTEORDER == CYG_LSBFIRST)
78
79 unsigned long swap32(unsigned long x)
80 {
81     unsigned long r = 0;
82
83     r |= (x>>24)&0xFF;
84     r |= ((x>>16)&0xFF)<<8;
85     r |= ((x>>8)&0xFF)<<16;
86     r |= ((x)&0xFF)<<24;
87
88     return r;
89 }
90
91 #else
92
93 #define swap32(x) ((unsigned long)(x))
94
95 #endif
96
97 //--------------------------------------------------------------------------
98
99 externC int dbg_thread_capabilities(struct dbg_capabilities * cpb)
100 {
101     cpb->mask1 = has_thread_current     |
102         has_thread_registers            |
103         has_thread_reg_change           |
104         has_thread_list                 |
105         has_thread_info                 ;
106     return 1 ; 
107 }
108
109 //--------------------------------------------------------------------------
110
111 static void dbg_make_threadref(Cyg_Thread *thread, threadref *ref )
112 {
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.
117
118     if( (CYG_ADDRWORD)thread == 0 || (CYG_ADDRWORD)thread == 0xffffffff )                     
119     {
120         ((unsigned long *)ref)[0] = 0;
121         ((unsigned long *)ref)[1] = 0;
122     }
123     else
124     {
125         cyg_uint16 id = thread->get_unique_id();
126
127 #if USE_ID
128         ((unsigned long *)ref)[0] = (unsigned long)thread;
129         ((unsigned long *)ref)[1] = (unsigned long)swap32(id);
130 #else    
131         ((unsigned long *)ref)[1] = (unsigned long)thread;
132         ((unsigned long *)ref)[0] = (unsigned long)id;
133 #endif
134     }
135 }
136
137 static Cyg_Thread *dbg_get_thread( threadref *ref)
138 {
139 #if USE_ID
140
141     cyg_uint16 id = 0;
142
143     id = (cyg_uint16)swap32(((unsigned long *)ref)[1]);
144
145     Cyg_Thread *th = Cyg_Thread::get_list_head();
146     while( th != 0 )
147     {
148         if( th->get_unique_id() == id ) break;
149         th = th->get_list_next();
150     }
151
152 //    if( thread->get_unique_id() != id ) th = 0;
153
154 #else
155  
156     cyg_uint16 id = 0;
157
158     Cyg_Thread *thread = (Cyg_Thread *)(((unsigned long *)ref)[1]);
159     id = (cyg_uint16)(((unsigned long *)ref)[0]);
160
161     // Validate the thread.
162     Cyg_Thread *th = Cyg_Thread::get_list_head();
163     while( th != 0 )
164     {
165         if( th == thread ) break;
166         th = th->get_list_next();
167     }
168
169 //    if( thread->get_unique_id() != id ) th = 0;
170
171 #endif
172  
173     return th;
174 }
175
176 //--------------------------------------------------------------------------
177
178 externC int dbg_currthread(threadref * varparm)
179 {
180     Cyg_Thread *thread = Cyg_Scheduler::get_current_thread();
181
182     dbg_make_threadref(thread, varparm );
183   
184     return 1 ; 
185 }
186
187 //--------------------------------------------------------------------------
188
189 externC int dbg_thread_id(threadref *threadid)
190 {
191     Cyg_Thread *thread = dbg_get_thread(threadid);
192     if( thread == 0 ) return 0;
193     return thread->get_unique_id ();
194 }
195
196 //--------------------------------------------------------------------------
197
198 externC int dbg_currthread_id(void)
199 {
200     Cyg_Thread *thread = Cyg_Scheduler::get_current_thread();
201     return thread->get_unique_id ();
202 }
203
204 //--------------------------------------------------------------------------
205
206 externC int dbg_threadlist(int startflag,
207                    threadref * lastthreadid,
208                    threadref * next_thread)
209 {
210     Cyg_Thread *thread;
211     if( startflag )
212     {
213         thread = Cyg_Thread::get_list_head();
214         dbg_make_threadref(thread, next_thread);
215     }
216     else
217     {
218         thread = dbg_get_thread(lastthreadid);
219
220         if( thread == 0 ) return 0;
221         thread = thread->get_list_next();
222
223         if( thread == 0 ) return 0;
224         dbg_make_threadref(thread, next_thread);        
225     }
226     return 1 ;
227 }
228
229 //--------------------------------------------------------------------------
230 // Some support routines for manufacturing thread info strings
231
232 static char *dbg_addstr(char *s, char *t)
233 {
234     while( (*s++ = *t++) != 0 );
235
236     return s-1;
237 }
238
239 static char *dbg_addint(char *s, int n, int base)
240 {
241     char buf[16];
242     char sign = '+';
243     cyg_count8 bpos;
244     char *digits = (char *)"0123456789ABCDEF";
245
246     if( n < 0 ) n = -n, sign = '-';
247     
248     /* Set pos to start */
249     bpos = 0;
250
251     /* construct digits into buffer in reverse order */
252     if( n == 0 ) buf[bpos++] = '0';
253     else while( n != 0 )
254     {
255         cyg_ucount8 d = n % base;
256         buf[bpos++] = digits[d];
257         n /= base;
258     }
259
260     /* set sign if negative. */
261     if( sign == '-' )
262     {
263         buf[bpos] = sign;
264     }
265     else bpos--;
266
267     /* Now write it out in correct order. */
268     while( bpos >= 0 )
269         *s++ = buf[bpos--];
270
271     *s = 0;
272     
273     return s;
274 }
275
276 static char *dbg_adddec(char *s, int x)
277 {
278     return dbg_addint(s, x, 10);
279 }
280
281 //--------------------------------------------------------------------------
282
283 externC int dbg_threadinfo(
284                    threadref * threadid,
285                    struct cygmon_thread_debug_info * info)
286 {
287     static char statebuf[60];
288     
289     Cyg_Thread *thread = dbg_get_thread(threadid);
290     if( thread == 0 ) return 0;
291
292     info->context_exists        = 1;
293
294     char *sbp = statebuf;
295     char *s;
296
297     if( thread->get_state() & Cyg_Thread::SUSPENDED )
298     {
299         sbp = dbg_addstr( sbp, (char *)"suspended+");
300     }
301
302     switch( thread->get_state() & ~Cyg_Thread::SUSPENDED )
303     {
304     case Cyg_Thread::RUNNING:
305         if ( Cyg_Scheduler::get_current_thread() == thread ) {
306             s = (char *)"running";              break;
307         }
308         else if ( thread->get_state() & Cyg_Thread::SUSPENDED ) {
309             s = (char *)""; sbp--; /*kill '+'*/ break;
310         }
311         else {
312             s = (char *)"ready";                break;
313         }
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;
323     default:
324         s = (char *)"unknown state";            break;
325     }
326
327     sbp = dbg_addstr( sbp, s );
328     sbp = dbg_addstr( sbp, (char *)", Priority: " );
329     sbp = dbg_adddec( sbp, thread->get_priority() );
330     
331     info->thread_display        = statebuf;
332
333 #ifdef CYGVAR_KERNEL_THREADS_NAME
334     info->unique_thread_name    = thread->get_name();
335 #else
336     info->unique_thread_name    = 0;
337 #endif
338
339     info->more_display          = 0;
340
341     return 1 ;
342 }
343
344 //--------------------------------------------------------------------------
345
346 externC int dbg_getthreadreg(
347                      threadref * osthreadid,
348                      int regcount, /* count of registers in the array */
349                      void * regval)  /* fillin this array */
350 {
351     Cyg_Thread *thread = dbg_get_thread(osthreadid);
352
353     if( thread == 0 ) return 0;
354
355     if( thread == Cyg_Scheduler::get_current_thread() )
356     {
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.
360         return 0;
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);
364 #else
365         return 0;
366 #endif
367     }
368     else
369     {
370         HAL_SavedRegisters *regs = thread->get_saved_context();
371         if( regs == 0 ) return 0;
372
373         HAL_GET_GDB_REGISTERS (regval, regs);
374     }
375     
376     return 1 ;
377 }
378
379 //--------------------------------------------------------------------------
380                    
381 externC int dbg_setthreadreg(
382                             threadref * osthreadid, 
383                             int regcount , /* number of registers */
384                             void * regval) 
385 {
386     Cyg_Thread *thread = dbg_get_thread(osthreadid);
387     
388     if( thread == 0 ) return 0;
389
390     if( thread == Cyg_Scheduler::get_current_thread() )
391     {
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.
395         return 0;
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);
399 #else
400         return 0;
401 #endif
402     }
403     else
404     {
405         HAL_SavedRegisters *regs = thread->get_saved_context();
406         if( regs == 0 ) return 0;
407
408         HAL_SET_GDB_REGISTERS (regs, regval);
409     }
410     
411     return 1;
412 }
413
414 //--------------------------------------------------------------------------
415 // Thread scheduler control for debugger.
416 // Arguments:
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
421 //
422 // Return values:
423 // 1  == success
424 // 0  == failure
425 // -1 == request that the caller handle this itself
426 //       (eg.by disabling interrupts)
427 //
428
429 externC int dbg_scheduler(
430                           threadref * osthreadid,
431                           int lock,     /* 0 == unlock, 1 == lock */
432                           int mode)     /* 0 == step,   1 == continue */
433 {
434 #if 0
435     /* Minimal implementation: let stub do the work.  */
436     return -1;                          // Stub will disable interrupts
437 #else
438     Cyg_Thread *thread = dbg_get_thread(osthreadid);
439
440     if( thread == 0 ) return 0;         // fail
441
442     if( thread == Cyg_Scheduler::get_current_thread() )
443     {
444         // OK to proceed
445
446         if (lock)
447         {
448             Cyg_Scheduler::lock();
449         }
450         else
451         {
452             if (Cyg_Scheduler::get_sched_lock() >= 1)
453                 Cyg_Scheduler::unlock_simple();
454         }
455         return 1;                       // success
456     }
457     else
458     {
459         // Cannot accept any thread other than current one
460         return 0;                       // fail
461     }
462 #endif
463 }
464
465
466 #endif // CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
467
468 //--------------------------------------------------------------------------
469 // End of dbg_gdb.cxx