source: rtems/c/src/lib/libbsp/shared/gdbstub/rtems-stub-glue.c @ 17083db

4.104.114.84.95
Last change on this file since 17083db was 17083db, checked in by Joel Sherrill <joel.sherrill@…>, on 07/01/02 at 22:21:03

2002-07-01 Joel Sherrill <joel@…>

  • rtems-stub-glue.c: Corrected use of _Objects_Information_table now that it is a two dimensional array based upon API and class.
  • Property mode set to 100644
File size: 28.4 KB
Line 
1/*
2 *  This file contains the RTEMS thread awareness support for GDB stubs.
3 *
4 *  This file is derived from an RTEMS thread aware i386-stub.c that
5 *  had the following copyright announcements:
6 *
7 *    This software is Copyright (C) 1998 by T.sqware - all rights limited
8 *    It is provided in to the public domain "as is", can be freely modified
9 *    as far as this copyight notice is kept unchanged, but does not imply
10 *    an endorsement by T.sqware of the product in which it is included.
11 *
12 * 
13 *     Modifications for RTEMS threads and more
14 *
15 *     Copyright (C) 2000 Quality Quorum, Inc.
16 *
17 *     All Rights Reserved
18 *
19 *     Permission to use, copy, modify, and distribute this software and its
20 *     documentation for any purpose and without fee is hereby granted.
21 *
22 *     QQI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
23 *     ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
24 *     QQI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
25 *     ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
26 *     WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
27 *     ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
28 *     SOFTWARE.
29 */
30
31#include <rtems.h>
32#include <string.h>
33
34#include "gdb_if.h"
35
36/* Change it to something meaningful when debugging */
37#undef ASSERT
38#define ASSERT(x)
39
40extern const char gdb_hexchars[];
41
42
43/*
44 *  Prototypes for CPU dependent routines that are conditional
45 *  at the bottom of this file.
46 */
47
48void rtems_gdb_stub_get_registers_from_context(
49  int            *registers,
50  Thread_Control *th
51);
52
53
54
55
56
57
58
59/* Check whether it is OK to enable thread support */
60int rtems_gdb_stub_thread_support_ok(void)
61{
62  if (_System_state_Get() == SYSTEM_STATE_UP) {
63    return 1;
64  }
65  return 0;
66}
67
68
69
70
71
72/*
73 *  rtems_gdb_stub_id_to_index
74 *
75 *  Return the gdb thread id for the specified RTEMS thread id
76 */
77
78int rtems_gdb_stub_id_to_index(
79  Objects_Id thread_obj_id
80)
81{
82  Objects_Id min_id, max_id;
83  int first_posix_id, first_rtems_id;
84  Objects_Information *obj_info;
85
86  if (_System_state_Get() != SYSTEM_STATE_UP) {
87    /* We have one thread let us use value reserved for idle thread */
88    return 1;
89  }
90
91  if (_Thread_Executing == _Thread_Idle) {
92    return 1;
93  }
94
95  /* Let us figure out thread_id for gdb */
96  first_rtems_id = 2;
97
98  obj_info = _Objects_Information_table[OBJECTS_CLASSIC_API][1];
99
100  min_id = obj_info->minimum_id;
101  max_id = obj_info->maximum_id;
102
103  if (thread_obj_id >= min_id && thread_obj_id < max_id) {
104    return first_rtems_id + (thread_obj_id - min_id);
105  }
106
107  first_posix_id = first_rtems_id + (max_id - min_id) + 1;
108
109  min_id = _Objects_Information_table[OBJECTS_POSIX_API][1]->minimum_id;
110
111  return first_posix_id + (thread_obj_id - min_id);
112}
113
114
115
116/* Return the RTEMS thread id from a gdb thread id */
117Thread_Control *rtems_gdb_index_to_stub_id(
118  int thread
119)
120{
121   Objects_Id thread_obj_id;
122   Objects_Id min_id, max_id;
123   int first_posix_id, first_rtems_id;
124   Objects_Information *obj_info;
125   Thread_Control *th;
126
127   ASSERT(registers != NULL);
128
129   if (_System_state_Get() != SYSTEM_STATE_UP || thread <= 0) {
130      /* Should not happen */
131      return NULL;
132   }
133
134   if (thread == 1) {
135      th = _Thread_Idle;
136      goto found;
137   }
138
139   /* Let us get object associtated with current thread */
140   first_rtems_id = 2;
141
142   thread_obj_id = _Thread_Executing->Object.id;
143
144   /* Let us figure out thread_id for gdb */
145   obj_info = _Objects_Information_table[OBJECTS_CLASSIC_API][1];
146
147   min_id = obj_info->minimum_id;
148   max_id = obj_info->maximum_id;
149
150   if (thread <= (first_rtems_id + (max_id - min_id))) {
151      th = (Thread_Control *)(obj_info->local_table[thread - first_rtems_id + 1]);
152
153      if (th != NULL) {
154         goto found;
155      }
156
157      /* Thread does not exist */
158      return NULL;
159   }
160
161   first_posix_id = first_rtems_id + (max_id - min_id) + 1;
162
163   obj_info = _Objects_Information_table[OBJECTS_POSIX_API][1];
164
165   min_id = obj_info->minimum_id;
166   max_id = obj_info->maximum_id;
167
168   th = (Thread_Control *)(obj_info->local_table[thread - first_posix_id + 1]);
169   if (th == NULL) {
170      /* Thread does not exist */
171      return NULL;
172   }
173
174  found:
175   return th;
176}
177
178
179
180
181
182
183/* Get id of the thread stopped by exception */
184int rtems_gdb_stub_get_current_thread(void)
185{
186  return rtems_gdb_stub_id_to_index( _Thread_Executing->Object.id );
187}
188
189
190
191
192/* Get id of the next thread after athread, if argument <= 0 find the
193   first available thread, return thread if found or 0 if not */
194int rtems_gdb_stub_get_next_thread(int athread)
195{
196  Objects_Id id, min_id, max_id;
197  int lim, first_posix_id, first_rtems_id;
198  Objects_Information *obj_info;
199  int start;
200
201  if (_System_state_Get() != SYSTEM_STATE_UP) {
202    /* We have one thread let us use value of idle thread */
203    return (athread < 1) ? 1 : 0;
204  }
205
206  if (athread < 1) {
207    return 1;
208  }
209
210  first_rtems_id = 2;
211 
212  obj_info = _Objects_Information_table[OBJECTS_CLASSIC_API][1];
213
214  min_id = obj_info->minimum_id;
215  max_id = obj_info->maximum_id;
216
217  lim = first_rtems_id + max_id - min_id;
218
219  if (athread < lim) {
220    if (athread < first_rtems_id) {
221      start = first_rtems_id;
222    } else {
223      start = 1 + athread;
224    }
225
226    for (id=start; id<=lim; id++) {
227      if (obj_info->local_table[id - first_rtems_id + 1] != NULL) {
228        return id;
229      }
230    }
231  }
232     
233  first_posix_id = first_rtems_id + (max_id - min_id) + 1;
234
235  obj_info = _Objects_Information_table[OBJECTS_POSIX_API][1];
236
237  min_id = obj_info->minimum_id;
238  max_id = obj_info->maximum_id;
239
240  lim = first_posix_id + (max_id - min_id);
241
242  if (athread < lim) {
243    if (athread < first_posix_id) {
244      start = first_posix_id;
245    } else {
246      start = 1 + athread;
247    }
248     
249    for (id=start; id<=lim; id++) {
250      if (obj_info->local_table[id - first_posix_id + 1] != NULL) {
251        return id;
252      }
253    }
254  }
255
256  /* Not found */
257  return 0;
258}
259
260
261
262
263
264
265/* Get thread registers, return 0 if thread does not
266   exist, and 1 otherwise */
267int rtems_gdb_stub_get_thread_regs(
268  int thread,
269  unsigned int *registers
270)
271{
272   Thread_Control *th;
273
274   th= rtems_gdb_index_to_stub_id(thread);
275
276   if( th )
277   {
278      rtems_gdb_stub_get_registers_from_context( registers, th );
279      return 1;
280   }
281   return 0;
282}
283
284
285
286
287
288
289/* Set thread registers, return 0 if thread does not
290   exist or register values will screw up the threads,
291   and 1 otherwise */
292
293int rtems_gdb_stub_set_thread_regs(
294  int thread,
295  unsigned int *registers
296)
297{
298  /* In current situation there is no point in changing any registers here
299     thread status is displayed as being deep inside thread switching
300     and we better do not screw up anything there - it may be fixed eventually
301     though */
302  return 1;
303}
304
305
306
307
308
309
310/* Get thread information, return 0 if thread does not
311   exist and 1 otherwise */
312int rtems_gdb_stub_get_thread_info(
313  int thread,
314  struct rtems_gdb_stub_thread_info *info
315)
316{
317   Objects_Id thread_obj_id;
318   Objects_Id min_id, max_id;
319   int first_posix_id, first_rtems_id;
320   Objects_Information *obj_info;
321   Thread_Control *th;
322   unsigned32 name;
323   char tmp_buf[20];
324
325   ASSERT(info != NULL);
326
327   if (thread <= 0) {
328      return 0;
329   }
330
331   if (_System_state_Get() != SYSTEM_STATE_UP || thread == 1) {
332      /* We have one thread let us use value
333         which will never happen for real thread */
334      strcpy(info->display, "idle thread");
335      strcpy(info->name, "IDLE");
336      info->more_display[0] = 0; /* Nothing */
337
338      return 1;
339   }
340
341   /* Let us get object associtated with current thread */
342   thread_obj_id = _Thread_Executing->Object.id;
343
344   /* Let us figure out thread_id for gdb */
345   first_rtems_id = 2;
346 
347   obj_info = _Objects_Information_table[OBJECTS_CLASSIC_API][1];
348
349   min_id = obj_info->minimum_id;
350   max_id = obj_info->maximum_id;
351
352   if (thread <= (first_rtems_id + (max_id - min_id))) {
353      th = (Thread_Control *)(obj_info->local_table[thread -
354                                                    first_rtems_id + 1]);
355
356      if (th == NULL) {
357         /* Thread does not exist */
358         return 0;
359      }
360
361      strcpy(info->display, "rtems task:   control at 0x");
362
363      tmp_buf[0] = gdb_hexchars[(((int)th) >> 28) & 0xf];
364      tmp_buf[1] = gdb_hexchars[(((int)th) >> 24) & 0xf];
365      tmp_buf[2] = gdb_hexchars[(((int)th) >> 20) & 0xf];
366      tmp_buf[3] = gdb_hexchars[(((int)th) >> 16) & 0xf];
367      tmp_buf[4] = gdb_hexchars[(((int)th) >> 12) & 0xf];
368      tmp_buf[5] = gdb_hexchars[(((int)th) >> 8) & 0xf];
369      tmp_buf[6] = gdb_hexchars[(((int)th) >> 4) & 0xf];
370      tmp_buf[7] = gdb_hexchars[((int)th) & 0xf];
371      tmp_buf[8] = 0;
372
373      strcat(info->display, tmp_buf);
374#if 0
375      name = *(unsigned32 *)(obj_info->local_table[thread]->name);
376#else
377      name = *(unsigned32 *)(obj_info->local_table[thread -
378                                                   first_rtems_id + 1]->name);
379#endif
380      info->name[0] = (name >> 24) & 0xff;
381      info->name[1] = (name >> 16) & 0xff;
382      info->name[2] = (name >> 8) & 0xff;
383      info->name[3] = name & 0xff;
384      info->name[4] = 0;
385
386      info->more_display[0] = 0; /* Nothing */
387
388      return 1;
389   }
390
391   first_posix_id = first_rtems_id + (max_id - min_id) + 1;
392
393   obj_info = _Objects_Information_table[OBJECTS_POSIX_API][1];
394
395   min_id = obj_info->minimum_id;
396   max_id = obj_info->maximum_id;
397
398   th = (Thread_Control *)(obj_info->local_table[thread - first_posix_id + 1]);
399   if (th == NULL)
400   {
401      /* Thread does not exist */
402      return 0;
403   }
404
405   strcpy(info->display, "posix thread: control at 0x");
406
407   tmp_buf[0] = gdb_hexchars[(((int)th) >> 28) & 0xf];
408   tmp_buf[1] = gdb_hexchars[(((int)th) >> 24) & 0xf];
409   tmp_buf[2] = gdb_hexchars[(((int)th) >> 20) & 0xf];
410   tmp_buf[3] = gdb_hexchars[(((int)th) >> 16) & 0xf];
411   tmp_buf[4] = gdb_hexchars[(((int)th) >> 12) & 0xf];
412   tmp_buf[5] = gdb_hexchars[(((int)th) >> 8) & 0xf];
413   tmp_buf[6] = gdb_hexchars[(((int)th) >> 4) & 0xf];
414   tmp_buf[7] = gdb_hexchars[((int)th) & 0xf];
415   tmp_buf[8] = 0;
416
417   strcat(info->display, tmp_buf);
418
419   name = *(unsigned32 *)(obj_info->local_table[thread -
420                                                first_posix_id + 1]->name);
421
422   info->name[0] = (name >> 24) & 0xff;
423   info->name[1] = (name >> 16) & 0xff;
424   info->name[2] = (name >> 8) & 0xff;
425   info->name[3] = name & 0xff;
426   info->name[4] = 0;
427
428   info->more_display[0] = 0; /* Nothing */
429 
430   return 1;
431}
432
433/*******************************************************/
434
435
436
437
438
439
440/* Format: x<type-1x>,<address-x>,<length-x>, where x is 'z' or 'Z' */
441int parse_zbreak(const char *in, int *type, unsigned char **addr, int *len)
442{
443  int ttmp, atmp, ltmp;
444 
445  ASSERT(in != NULL);
446  ASSERT(type != NULL);
447  ASSERT(addr != NULL);
448  ASSERT(len != NULL);
449
450  ASSERT(*in == 'z' || *in == 'Z');
451
452  in++;
453
454  if (!hstr2nibble(in, &ttmp) || *(in+1) != ',')
455    {
456      return 0;
457    }
458  in += 2;
459
460  in = vhstr2int(in, &atmp);
461  if (in == NULL || *in != ',')
462    {
463      return 0;
464    }
465  in++;
466
467  in = vhstr2int(in, &ltmp);
468  if (in == NULL || ltmp < 1)
469    {
470      return 0;
471    }
472
473  *type = ttmp;
474  *addr = (unsigned char *)atmp;
475  *len  = ltmp;
476
477  return 1;
478}
479
480/* Format: qP<mask-08x><thread_id-ft> */
481static int
482parse_qp(const char *in, int *mask, int *thread)
483{
484  const char *ptr;
485
486  ASSERT(in != NULL);
487  ASSERT(*in == 'q');
488  ASSERT(*(in+1) == 'P');
489
490  ptr = fhstr2int(in+2, mask);
491  if (ptr == NULL)
492    {
493      return 0;
494    }
495
496  ptr = fhstr2thread(ptr, thread);
497  if (ptr == NULL)
498    {
499      return 0;
500    }
501
502  return 1;
503}
504
505/* Format: qQ<mask-08x><thread_id-ft><tag-08x><length-02x><value>...] */
506static void
507pack_qq(char *out, int mask, int thread, struct rtems_gdb_stub_thread_info *info)
508{
509  int len;
510
511  ASSERT(out != NULL);
512  ASSERT(info != NULL);
513
514  *out++ = 'q';
515  *out++ = 'Q';
516  out = int2fhstr(out, mask);
517  out = thread2fhstr(out, thread);
518
519  if (mask & 0x1) {
520    /* Thread id once again */
521    memcpy(out, "00000001", 8);
522    out   += 8;
523    *out++ = '1';
524    *out++ = '0';
525    out = thread2fhstr(out, thread);
526  }
527
528  if (mask & 0x2) {
529    /* Exists */
530    memcpy(out, "00000002", 8);
531    out   += 8;
532    *out++ = '0';
533    *out++ = '1';
534    *out++ = '1';
535  }
536
537  if (mask & 0x4) {
538    /* Display */
539    memcpy(out, "00000004", 8);
540    out += 8;
541
542    info->display[sizeof(info->display)-1] = 0; /* Fot God sake */
543
544    len = strlen(info->display);
545
546    *out++ = gdb_hexchars[len >> 4];
547    *out++ = gdb_hexchars[len & 0x0f];
548
549    memcpy(out, info->display, len);
550
551    out += len;
552  }
553
554  if (mask & 0x8) {
555    /* Name */
556    memcpy(out, "00000008", 8);
557    out += 8;
558
559    info->name[sizeof(info->name)-1] = 0; /* Fot God sake */
560
561    len = strlen(info->name);
562
563    *out++ = gdb_hexchars[len >> 4];
564    *out++ = gdb_hexchars[len & 0x0f];
565
566    memcpy(out, info->name, len);
567
568    out += len;
569  }
570
571  if (mask & 0x10) {
572    /* More display */
573    memcpy(out, "00000010", 8);
574    out += 8;
575
576    info->more_display[sizeof(info->more_display)-1] = 0; /* Fot God sake */
577
578    len = strlen(info->more_display);
579
580    *out++ = gdb_hexchars[len >> 4];
581    *out++ = gdb_hexchars[len & 0x0f];
582
583    memcpy(out, info->more_display, len);
584
585    out += len;
586  }
587
588  *out = 0;
589
590  return;
591}
592
593/* Format qL<first-01x><max_count-02x><arg_thread_id-ft> */
594static int
595parse_ql(const char *in, int *first, int *max_count, int *athread)
596{
597  const char *ptr;
598
599  ASSERT(in != NULL);
600  ASSERT(*in == 'q');
601  ASSERT(*(in+1) == 'L');
602  ASSERT(first != NULL);
603  ASSERT(max_count != NULL);
604  ASSERT(athread != NULL);
605
606  ptr = in + 2;
607
608  /*  First */
609  if (!hstr2nibble(ptr, first))
610    {
611      return 0;
612    }
613  ptr++;
614
615  /* Max count */
616  if (!hstr2byte(ptr, max_count))
617    {
618      return 0;
619    }
620  ptr += 2;
621
622  /* A thread */
623  ptr = fhstr2thread(ptr, athread);
624  if (ptr == NULL)
625    {
626      return 0;
627    }
628
629  return 1;
630}
631
632/* Format: qM<count-02x><done-01x><arg_thread_id>[<found_thread_id-ft>...] */
633static char *
634reserve_qm_header(char *out)
635{
636  ASSERT(out != NULL);
637
638  return out + 21;
639}
640
641/* Format: qM<count-02x><done-01x><arg_thread_id>[<found_thread_id-ft>...] */
642static char*
643pack_qm_thread(char *out, int thread)
644{
645  ASSERT(out != 0);
646
647  return thread2fhstr(out, thread);
648}
649
650/* Format: qM<count-02x><done-01x><arg_thread_id>[<found_thread_id-ft>...] */
651static void
652pack_qm_header(char *out, int count, int done, int athread)
653{
654   ASSERT(out != 0);
655   ASSERT(count >= 0 && count < 256);
656
657   *out++ = 'q';
658   *out++ = 'M';
659
660   *out++ = gdb_hexchars[(count >> 4) & 0x0f];
661   *out++ = gdb_hexchars[count & 0x0f];
662
663   if (done) {
664      *out++ = '1';
665   } else {
666      *out++ = '0';
667   }
668
669   thread2fhstr(out, athread);
670   return;
671}
672
673
674
675
676
677
678
679
680
681
682
683
684void rtems_gdb_process_query(
685  char *inbuffer,
686  char *outbuffer,
687  int   do_threads,
688  int   thread
689)
690{
691  char *optr;
692   
693  switch(inbuffer[1]) {
694    case 'C':
695      /* Current thread query query - return stopped thread */
696      if (!do_threads) {
697        break;
698      }
699
700      optr = outbuffer;
701
702      *optr++ = 'Q';
703      *optr++ = 'C';
704      optr    = thread2vhstr(optr, thread);
705      *optr   = 0;
706      break;
707
708
709
710
711    case 'P':
712      /* Thread info query */
713      if (!do_threads) {
714        break;
715      }
716
717      {
718        int ret, rthread, mask;
719        struct rtems_gdb_stub_thread_info info;
720
721        ret = parse_qp(inbuffer, &mask, &rthread);
722        if (!ret|| mask & ~0x1f) {
723          strcpy(outbuffer, "E01");
724          break;
725        }
726
727        ret = rtems_gdb_stub_get_thread_info(rthread, &info);
728        if (!ret) {
729          /* Good implementation would never ask for non-existing thread,
730             should we care about bad ones - it does not seem so */
731          strcpy(outbuffer, "E02");
732          break;
733        }
734
735        /* Build response */
736        pack_qq(outbuffer, mask, rthread, &info);
737      }
738      break;
739
740
741
742
743
744    case 'L':
745      /* Thread list query */
746      if (!do_threads) {
747        break;
748      }
749
750      {
751        int ret, athread, first, max_cnt, i, done, rthread;
752
753        ret = parse_ql(inbuffer, &first, &max_cnt, &athread);
754        if (!ret) {
755          strcpy(outbuffer, "E02");
756          break;
757        }
758
759        if (max_cnt == 0) {
760          strcpy(outbuffer, "E02");
761          break;
762        }
763
764        if (max_cnt > QM_MAX_THREADS) {
765          /* Limit max count by buffer size */
766          max_cnt = QM_MAX_THREADS;
767        }
768
769        /* Reserve place for output header */
770        optr = reserve_qm_header(outbuffer);
771
772        if (first) {
773          rthread = 0;
774        } else {
775          rthread = athread;
776        }
777
778        done = 0;
779
780        for (i=0; i<max_cnt; i++) {
781          rthread = rtems_gdb_stub_get_next_thread(rthread);
782
783          if (rthread <= 0) {
784            done = 1; /* Set done flag */
785            break;
786          }
787
788          optr = pack_qm_thread(optr, rthread);
789        }
790
791        *optr = 0;
792
793        ASSERT((optr - outbuffer) < BUFMAX);
794
795        /* Fill header */
796        pack_qm_header(outbuffer, i, done, athread);
797      }
798      break;
799
800
801
802
803
804
805    default:
806      if (memcmp(inbuffer, "qOffsets", 8) == 0) {
807        unsigned char *t, *d, *b;
808        char *out;
809
810        if (!rtems_gdb_stub_get_offsets(&t, &d, &b)) {
811          break;
812        }
813
814        out = outbuffer;
815
816        *out++ = 'T';
817        *out++ = 'e';
818        *out++ = 'x';
819        *out++ = 't';
820        *out++ = '=';
821
822        out = int2vhstr(out, (int)t);
823
824        *out++ = ';';
825        *out++ = 'D';
826        *out++ = 'a';
827        *out++ = 't';
828        *out++ = 'a';
829        *out++ = '=';
830
831        out = int2vhstr(out, (int)d);
832
833        *out++ = ';';
834        *out++ = 'B';
835        *out++ = 's';
836        *out++ = 's';
837        *out++ = '=';
838
839        out = int2vhstr(out, (int)b);
840
841        *out++ = ';';
842        *out++ = 0;
843
844        break;
845      }
846
847      /*  qCRC, qRcmd, qu and qz will be added here */
848      break;
849    }
850}
851
852
853
854
855
856
857/* Present thread in the variable length string format */
858char*
859thread2vhstr(char *buf, int thread)
860{
861  int i, nibble, shift;
862
863  ASSERT(buf != NULL);
864
865  for(i=0, shift=28; i<8; i++, shift-=4)
866    {
867      nibble = (thread >> shift) & 0x0f;
868     
869      if (nibble != 0)
870        {
871          break;
872        }
873    }
874
875  if (i == 8)
876    {
877      *buf++ = '0';
878      return buf;
879    }
880
881  *buf++ = gdb_hexchars[nibble];
882
883  for(i++, shift-=4; i<8; i++, shift-=4, buf++)
884    {
885      nibble = (thread >> shift) & 0x0f;
886      *buf   = gdb_hexchars[nibble];
887    }
888
889  return buf;
890}
891
892/* Present thread in fixed length string format */
893char*
894thread2fhstr(char *buf, int thread)
895{
896  int i, nibble, shift;
897
898  ASSERT(buf != NULL);
899
900  for(i=0; i<8; i++, buf++)
901    {
902      *buf = '0';
903    }
904
905  for(i=0, shift=28; i<8; i++, shift-=4, buf++)
906    {
907      nibble = (thread >> shift) & 0x0f;
908      *buf   = gdb_hexchars[nibble];
909    }
910
911  return buf;
912}
913
914/* Parse thread presented in fixed length format */
915const char*
916fhstr2thread(const char *buf, int *thread)
917{
918  int i, val, nibble;
919
920  ASSERT(buf != NULL);
921  ASSERT(thread != NULL);
922
923  for(i=0; i<8; i++, buf++)
924    {
925      if (*buf != '0')
926        {
927          return NULL;
928        }
929    }
930
931  val = 0;
932
933  for(i=0; i<8; i++, buf++)
934    {
935      if (!hstr2nibble(buf, &nibble))
936        {
937          return NULL;
938        }
939
940      ASSERT(nibble >=0 && nibble < 16);
941
942      val = (val << 4) | nibble;
943    }
944
945  *thread = val;
946
947  return buf;
948}
949
950/* Parse thread presented in variable length format */
951const char*
952vhstr2thread(const char *buf, int *thread)
953{
954  int i, val, nibble;
955  int found_zero, lim;
956
957  ASSERT(buf != NULL);
958  ASSERT(thread != NULL);
959
960
961  /* If we have leading zeros, skip them */
962  found_zero = 0;
963
964  for(i=0; i<16; i++, buf++)
965    {
966      if (*buf != '0')
967        {
968          break;
969        }
970
971      found_zero = 1;
972    }
973
974  /* Process non-zeros */
975  lim = 16 - i;
976  val = 0;
977
978  for(i=0; i<lim; i++, buf++)
979    {
980      if (!hstr2nibble(buf, &nibble))
981        {
982          if (i == 0 && !found_zero)
983            {
984              /* Empty value */
985              return NULL;
986            }
987
988          *thread = val;
989          return buf;
990        }
991         
992      ASSERT(nibble >= 0 && nibble < 16);
993
994      val = (val << 4) | nibble;
995    }
996
997  if (hstr2nibble(buf, &nibble))
998    {
999      /* Value is too long */
1000      return NULL;
1001    }
1002 
1003  *thread = val;
1004  return buf;
1005}
1006
1007
1008/* Present integer in the variable length string format */
1009char*
1010int2vhstr(char *buf, int val)
1011{
1012  int i, nibble, shift;
1013
1014  ASSERT(buf != NULL);
1015
1016  for(i=0, shift=28; i<8; i++, shift-=4)
1017    {
1018      nibble = (val >> shift) & 0x0f;
1019     
1020      if (nibble != 0)
1021        {
1022          break;
1023        }
1024    }
1025
1026  if (i == 8)
1027    {
1028      *buf++ = '0';
1029      return buf;
1030    }
1031
1032  *buf++ = gdb_hexchars[nibble];
1033
1034  for(i++, shift-=4; i<8; i++, shift-=4, buf++)
1035    {
1036      nibble = (val >> shift) & 0x0f;
1037      *buf   = gdb_hexchars[nibble];
1038    }
1039
1040  return buf;
1041}
1042
1043/* Present int in fixed length string format */
1044char*
1045int2fhstr(char *buf, int val)
1046{
1047  int i, nibble, shift;
1048
1049  ASSERT(buf != NULL);
1050
1051  for(i=0, shift=28; i<8; i++, shift-=4, buf++)
1052    {
1053      nibble = (val >> shift) & 0x0f;
1054      *buf   = gdb_hexchars[nibble];
1055    }
1056
1057  return buf;
1058}
1059
1060/* Parse int presented in fixed length format */
1061const char*
1062fhstr2int(const char *buf, int *ival)
1063{
1064  int i, val, nibble;
1065
1066  ASSERT(buf != NULL);
1067  ASSERT(ival != NULL);
1068
1069  val = 0;
1070
1071  for(i=0; i<8; i++, buf++)
1072    {
1073      if (!hstr2nibble(buf, &nibble))
1074        {
1075          return NULL;
1076        }
1077
1078      ASSERT(nibble >=0 && nibble < 16);
1079
1080      val = (val << 4) | nibble;
1081    }
1082
1083  *ival = val;
1084
1085  return buf;
1086}
1087
1088/* Parse int presented in variable length format */
1089const char*
1090vhstr2int(const char *buf, int *ival)
1091{
1092  int i, val, nibble;
1093  int found_zero, lim;
1094
1095  ASSERT(buf != NULL);
1096  ASSERT(ival != NULL);
1097
1098
1099  /* If we have leading zeros, skip them */
1100  found_zero = 0;
1101
1102  for(i=0; i<8; i++, buf++)
1103    {
1104      if (*buf != '0')
1105        {
1106          break;
1107        }
1108
1109      found_zero = 1;
1110    }
1111
1112  /* Process non-zeros */
1113  lim = 8 - i;
1114  val = 0;
1115
1116  for(i=0; i<lim; i++, buf++)
1117    {
1118      if (!hstr2nibble(buf, &nibble))
1119        {
1120          if (i == 0 && !found_zero)
1121            {
1122              /* Empty value */
1123              return NULL;
1124            }
1125
1126          *ival = val;
1127          return buf;
1128        }
1129         
1130      ASSERT(nibble >= 0 && nibble < 16);
1131
1132      val = (val << 4) | nibble;
1133    }
1134
1135  if (hstr2nibble(buf, &nibble))
1136    {
1137      /* Value is too long */
1138      return NULL;
1139    }
1140
1141  *ival = val;
1142  return buf;
1143}
1144
1145int
1146hstr2byte(const char *buf, int *bval)
1147{
1148  int hnib, lnib;
1149
1150  ASSERT(buf != NULL);
1151  ASSERT(bval != NULL);
1152
1153  if (!hstr2nibble(buf, &hnib) || !hstr2nibble(buf+1, &lnib))
1154    {
1155      return 0;
1156    }
1157
1158  *bval = (hnib << 4) | lnib;
1159  return 1;
1160}
1161
1162int
1163hstr2nibble(const char *buf, int *nibble)
1164{
1165  int ch;
1166
1167  ASSERT(buf != NULL);
1168  ASSERT(nibble != NULL);
1169
1170  ch = *buf;
1171
1172  if (ch >= '0' && ch <= '9')
1173    {
1174      *nibble = ch  - '0';
1175      return 1;
1176    }
1177
1178  if (ch >= 'a' && ch <= 'f')
1179    {
1180      *nibble = ch - 'a' + 10;
1181      return 1;
1182    }
1183
1184  if (ch >= 'A' && ch <= 'F')
1185    {
1186      *nibble = ch - 'A' + 10;
1187      return 1;
1188    }
1189
1190  return 0;
1191}
1192
1193static volatile char mem_err = 0;
1194void  set_mem_err(void);
1195static void (*volatile mem_fault_routine) (void) = NULL;
1196
1197
1198
1199/* convert count bytes of the memory pointed to by mem into hex string,
1200   placing result in buf, return pointer to next location in hex strng
1201   in case of success or NULL otherwise */
1202char*
1203mem2hstr(char *buf, const unsigned char *mem, int count)
1204{
1205  int i;
1206  unsigned char ch;
1207
1208  mem_err = 0;
1209
1210  mem_fault_routine = set_mem_err;
1211 
1212  for (i = 0; i<count; i++, mem++)
1213    {
1214      ch = get_byte (mem);
1215      if (mem_err)
1216        {
1217          mem_fault_routine = NULL;
1218          return NULL;
1219        }
1220     
1221      *buf++ = gdb_hexchars[ch >> 4];
1222      *buf++ = gdb_hexchars[ch & 0x0f];
1223    }
1224 
1225  *buf = 0;
1226
1227  mem_fault_routine = NULL;
1228
1229  return buf;
1230}
1231
1232/* convert the hex string to into count bytes of binary to be placed in mem
1233   return 1 in case of success and  0 otherwise */
1234int
1235hstr2mem (unsigned char *mem, const char *buf, int count)
1236{
1237  int i;
1238  int bval;
1239
1240  mem_err = 0;
1241
1242  mem_fault_routine = set_mem_err;
1243
1244  for (i = 0; i < count; i++, mem++, buf+=2)
1245    {
1246      if (!hstr2byte(buf, &bval))
1247        {
1248          mem_fault_routine = NULL;
1249          return 0;
1250        }
1251         
1252      ASSERT(bval >=0 && bval < 256);
1253
1254      set_byte (mem, bval);
1255
1256      if (mem_err)
1257        {
1258          mem_fault_routine = NULL;
1259          return 0;
1260        }
1261    }
1262
1263  mem_fault_routine = NULL;
1264  return 1;
1265}
1266
1267void
1268set_mem_err (void)
1269{
1270  mem_err = 1;
1271}
1272
1273
1274/* These are separate functions so that they are so short and sweet
1275   that the compiler won't save any registers (if there is a fault
1276   to mem_fault, they won't get restored, so there better not be any
1277   saved).  */
1278
1279unsigned char
1280get_byte (const unsigned char *addr)
1281{
1282  return *addr;
1283}
1284
1285void
1286set_byte (unsigned char *addr, int val)
1287{
1288  *addr = val;
1289}
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299/*
1300 *  From here down, the code is CPU model specific and generally maps
1301 *  the RTEMS thread context format to gdb's.
1302 */
1303
1304#if defined(__i386__)
1305
1306#include "i386-stub.h"
1307
1308/* Packing order of registers */
1309enum i386_stub_regnames {
1310  I386_STUB_REG_EAX, I386_STUB_REG_ECX, I386_STUB_REG_EDX, I386_STUB_REG_EBX,
1311  I386_STUB_REG_ESP, I386_STUB_REG_EBP, I386_STUB_REG_ESI, I386_STUB_REG_EDI,
1312  I386_STUB_REG_PC /* also known as eip */ ,
1313  I386_STUB_REG_PS /* also known as eflags */ ,
1314  I386_STUB_REG_CS, I386_STUB_REG_SS, I386_STUB_REG_DS, I386_STUB_REG_ES,
1315  I386_STUB_REG_FS, I386_STUB_REG_GS
1316};
1317
1318void rtems_gdb_stub_get_registers_from_context(
1319  int            *registers,
1320  Thread_Control *th
1321)
1322{
1323  registers[I386_STUB_REG_EAX] = 0;
1324  registers[I386_STUB_REG_ECX] = 0;
1325  registers[I386_STUB_REG_EDX] = 0;
1326  registers[I386_STUB_REG_EBX] = (int)th->Registers.ebx;
1327  registers[I386_STUB_REG_ESP] = (int)th->Registers.esp;
1328  registers[I386_STUB_REG_EBP] = (int)th->Registers.ebp;
1329  registers[I386_STUB_REG_ESI] = (int)th->Registers.esi;
1330  registers[I386_STUB_REG_EDI] = (int)th->Registers.edi;
1331  registers[I386_STUB_REG_PC]  = *(int *)th->Registers.esp;
1332  registers[I386_STUB_REG_PS]  = (int)th->Registers.eflags;
1333
1334  /* RTEMS never changes base registers (especially once
1335     threads are running) */
1336
1337  registers[I386_STUB_REG_CS]  = 0x8; /* We just know these values */
1338  registers[I386_STUB_REG_SS]  = 0x10;
1339  registers[I386_STUB_REG_DS]  = 0x10;
1340  registers[I386_STUB_REG_ES]  = 0x10;
1341  registers[I386_STUB_REG_FS]  = 0x10;
1342  registers[I386_STUB_REG_GS]  = 0x10;
1343}
1344
1345int rtems_gdb_stub_get_offsets(
1346  unsigned char **text_addr,
1347  unsigned char **data_addr,
1348  unsigned char **bss_addr
1349)
1350{
1351  extern unsigned char _text_start;
1352  extern unsigned char _data_start;
1353  extern unsigned char _bss_start;
1354
1355  *text_addr = &_text_start;
1356  *data_addr = &_data_start;
1357  *bss_addr  = &_bss_start;
1358
1359  return 1;
1360}
1361
1362
1363
1364
1365
1366#elif defined(__mips__)
1367
1368
1369void rtems_gdb_stub_get_registers_from_context(
1370  int            *registers,
1371  Thread_Control *th
1372)
1373{
1374   registers[S0] = (unsigned)th->Registers.s0;
1375   registers[S1] = (unsigned)th->Registers.s1;
1376   registers[S2] = (unsigned)th->Registers.s2;
1377   registers[S3] = (unsigned)th->Registers.s3;
1378   registers[S4] = (unsigned)th->Registers.s4;
1379   registers[S5] = (unsigned)th->Registers.s5;
1380   registers[S6] = (unsigned)th->Registers.s6;
1381   registers[S7] = (unsigned)th->Registers.s7;
1382
1383   registers[SP] = (unsigned)th->Registers.sp;
1384   registers[RA] = (unsigned)th->Registers.ra;
1385
1386   registers[SR] = (unsigned)th->Registers.c0_sr;
1387   registers[PC] = (unsigned)th->Registers.c0_epc;
1388}
1389
1390
1391int rtems_gdb_stub_get_offsets(
1392  unsigned char **text_addr,
1393  unsigned char **data_addr,
1394  unsigned char **bss_addr
1395)
1396{
1397/*
1398  extern unsigned32 _ftext;
1399  extern unsigned32 _fdata;
1400  extern unsigned32 _bss_start;
1401
1402  *text_addr = &_ftext;
1403  *data_addr = &_fdata;
1404  *bss_addr  = &_bss_start;
1405*/
1406  *text_addr = 0;
1407  *data_addr = 0;
1408  *bss_addr  = 0;
1409  return 1;
1410}
1411
1412#elif defined(__mc68000__)
1413
1414
1415void rtems_gdb_stub_get_registers_from_context(
1416  int            *registers,
1417  Thread_Control *th
1418)
1419{
1420  /*
1421   * how about register D0/D1/A0/A1
1422   * they are located on thread stack ...
1423   * -> they are not needed for context switch
1424   */
1425  registers[D0] = 0;
1426  registers[D1] = 0;
1427  registers[D2] = (unsigned32)th->Registers.d2;
1428  registers[D3] = (unsigned32)th->Registers.d3;
1429  registers[D4] = (unsigned32)th->Registers.d4;
1430  registers[D5] = (unsigned32)th->Registers.d5;
1431  registers[D6] = (unsigned32)th->Registers.d6;
1432  registers[D7] = (unsigned32)th->Registers.d7;
1433
1434  registers[A0] = 0;
1435  registers[A1] = 0;
1436  registers[A2] = (unsigned32)th->Registers.a2;
1437  registers[A3] = (unsigned32)th->Registers.a3;
1438  registers[A4] = (unsigned32)th->Registers.a4;
1439  registers[A5] = (unsigned32)th->Registers.a5;
1440  registers[A6] = (unsigned32)th->Registers.a6;
1441  registers[A7] = (unsigned32)th->Registers.a7_msp;
1442 
1443  registers[PS] = (unsigned32)th->Registers.sr;
1444#if 0
1445  registers[PC] = *(unsigned32 *)th->Registers.a7_msp; /* *SP = ret adr */
1446#else
1447  registers[PC] = (unsigned32)_CPU_Context_switch;
1448#endif
1449}
1450
1451
1452int rtems_gdb_stub_get_offsets(
1453  unsigned char **text_addr,
1454  unsigned char **data_addr,
1455  unsigned char **bss_addr
1456)
1457{
1458/*
1459  extern unsigned32 _ftext;
1460  extern unsigned32 _fdata;
1461  extern unsigned32 _bss_start;
1462
1463  *text_addr = &_ftext;
1464  *data_addr = &_fdata;
1465  *bss_addr  = &_bss_start;
1466*/
1467  *text_addr = 0;
1468  *data_addr = 0;
1469  *bss_addr  = 0;
1470  return 1;
1471}
1472
1473#else
1474#error "rtems-gdb-stub.c: Unsupported CPU!"
1475#endif
Note: See TracBrowser for help on using the repository browser.