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

4.115
Last change on this file since a2e3f33 was a2e3f33, checked in by Sebastian Huber <sebastian.huber@…>, on 07/24/13 at 11:50:54

score: Create object implementation header

Move implementation specific parts of object.h and object.inl into new
header file objectimpl.h. The object.h contains now only the
application visible API.

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