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

4.104.115
Last change on this file since dce79aee was dce79aee, checked in by Joel Sherrill <joel.sherrill@…>, on 05/05/09 at 21:17:47

2009-05-05 Joel Sherrill <joel.sherrill@…>

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