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

4.104.114.84.95
Last change on this file since a681285 was a681285, checked in by Joel Sherrill <joel.sherrill@…>, on 08/14/02 at 22:58:30

2002-08-14 Greg Menke <gregory.menke@…>

  • mips-stub.c: Re-debugged a breakpoint problem, zbreak target address was a char * which caused the target instruction to not be fully copied, so the zbreak logic corrupted the original instruction and didn't insert a valid break instruction.
  • Property mode set to 100644
File size: 27.0 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_RTEMS_TASKS];
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_THREADS]->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_RTEMS_TASKS];
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_THREADS];
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_RTEMS_TASKS];
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_THREADS];
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_RTEMS_TASKS];
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 
375      name = *(unsigned32 *)(obj_info->local_table[thread]->name);
376     
377      info->name[0] = (name >> 24) & 0xff;
378      info->name[1] = (name >> 16) & 0xff;
379      info->name[2] = (name >> 8) & 0xff;
380      info->name[3] = name & 0xff;
381      info->name[4] = 0;
382
383      info->more_display[0] = 0; /* Nothing */
384
385      return 1;
386   }
387
388   first_posix_id = first_rtems_id + (max_id - min_id) + 1;
389
390   obj_info = _Objects_Information_table[OBJECTS_POSIX_THREADS];
391
392   min_id = obj_info->minimum_id;
393   max_id = obj_info->maximum_id;
394
395   th = (Thread_Control *)(obj_info->local_table[thread - first_posix_id + 1]);
396   if (th == NULL)
397   {
398      /* Thread does not exist */
399      return 0;
400   }
401
402   strcpy(info->display, "posix thread: control at 0x");
403
404   tmp_buf[0] = gdb_hexchars[(((int)th) >> 28) & 0xf];
405   tmp_buf[1] = gdb_hexchars[(((int)th) >> 24) & 0xf];
406   tmp_buf[2] = gdb_hexchars[(((int)th) >> 20) & 0xf];
407   tmp_buf[3] = gdb_hexchars[(((int)th) >> 16) & 0xf];
408   tmp_buf[4] = gdb_hexchars[(((int)th) >> 12) & 0xf];
409   tmp_buf[5] = gdb_hexchars[(((int)th) >> 8) & 0xf];
410   tmp_buf[6] = gdb_hexchars[(((int)th) >> 4) & 0xf];
411   tmp_buf[7] = gdb_hexchars[((int)th) & 0xf];
412   tmp_buf[8] = 0;
413
414   strcat(info->display, tmp_buf);
415
416   name = *(unsigned32 *)(obj_info->local_table[thread -
417                                                first_posix_id + 1]->name);
418
419   info->name[0] = (name >> 24) & 0xff;
420   info->name[1] = (name >> 16) & 0xff;
421   info->name[2] = (name >> 8) & 0xff;
422   info->name[3] = name & 0xff;
423   info->name[4] = 0;
424
425   info->more_display[0] = 0; /* Nothing */
426 
427   return 1;
428}
429
430/*******************************************************/
431
432
433
434
435
436
437/* Format: x<type-1x>,<address-x>,<length-x>, where x is 'z' or 'Z' */
438int parse_zbreak(const char *in, int *type, unsigned char **addr, int *len)
439{
440  int ttmp, atmp, ltmp;
441 
442  ASSERT(in != NULL);
443  ASSERT(type != NULL);
444  ASSERT(addr != NULL);
445  ASSERT(len != NULL);
446
447  ASSERT(*in == 'z' || *in == 'Z');
448
449  in++;
450
451  if (!hstr2nibble(in, &ttmp) || *(in+1) != ',')
452    {
453      return 0;
454    }
455  in += 2;
456
457  in = vhstr2int(in, &atmp);
458  if (in == NULL || *in != ',')
459    {
460      return 0;
461    }
462  in++;
463
464  in = vhstr2int(in, &ltmp);
465  if (in == NULL || ltmp < 1)
466    {
467      return 0;
468    }
469
470  *type = ttmp;
471  *addr = (unsigned char *)atmp;
472  *len  = ltmp;
473
474  return 1;
475}
476
477/* Format: qP<mask-08x><thread_id-ft> */
478static int
479parse_qp(const char *in, int *mask, int *thread)
480{
481  const char *ptr;
482
483  ASSERT(in != NULL);
484  ASSERT(*in == 'q');
485  ASSERT(*(in+1) == 'P');
486
487  ptr = fhstr2int(in+2, mask);
488  if (ptr == NULL)
489    {
490      return 0;
491    }
492
493  ptr = fhstr2thread(ptr, thread);
494  if (ptr == NULL)
495    {
496      return 0;
497    }
498
499  return 1;
500}
501
502/* Format: qQ<mask-08x><thread_id-ft><tag-08x><length-02x><value>...] */
503static void
504pack_qq(char *out, int mask, int thread, struct rtems_gdb_stub_thread_info *info)
505{
506  int len;
507
508  ASSERT(out != NULL);
509  ASSERT(info != NULL);
510
511  *out++ = 'q';
512  *out++ = 'Q';
513  out = int2fhstr(out, mask);
514  out = thread2fhstr(out, thread);
515
516  if (mask & 0x1) {
517    /* Thread id once again */
518    memcpy(out, "00000001", 8);
519    out   += 8;
520    *out++ = '1';
521    *out++ = '0';
522    out = thread2fhstr(out, thread);
523  }
524
525  if (mask & 0x2) {
526    /* Exists */
527    memcpy(out, "00000002", 8);
528    out   += 8;
529    *out++ = '0';
530    *out++ = '1';
531    *out++ = '1';
532  }
533
534  if (mask & 0x4) {
535    /* Display */
536    memcpy(out, "00000004", 8);
537    out += 8;
538
539    info->display[sizeof(info->display)-1] = 0; /* Fot God sake */
540
541    len = strlen(info->display);
542
543    *out++ = gdb_hexchars[len >> 4];
544    *out++ = gdb_hexchars[len & 0x0f];
545
546    memcpy(out, info->display, len);
547
548    out += len;
549  }
550
551  if (mask & 0x8) {
552    /* Name */
553    memcpy(out, "00000008", 8);
554    out += 8;
555
556    info->name[sizeof(info->name)-1] = 0; /* Fot God sake */
557
558    len = strlen(info->name);
559
560    *out++ = gdb_hexchars[len >> 4];
561    *out++ = gdb_hexchars[len & 0x0f];
562
563    memcpy(out, info->name, len);
564
565    out += len;
566  }
567
568  if (mask & 0x10) {
569    /* More display */
570    memcpy(out, "00000010", 8);
571    out += 8;
572
573    info->more_display[sizeof(info->more_display)-1] = 0; /* Fot God sake */
574
575    len = strlen(info->more_display);
576
577    *out++ = gdb_hexchars[len >> 4];
578    *out++ = gdb_hexchars[len & 0x0f];
579
580    memcpy(out, info->more_display, len);
581
582    out += len;
583  }
584
585  *out = 0;
586
587  return;
588}
589
590/* Format qL<first-01x><max_count-02x><arg_thread_id-ft> */
591static int
592parse_ql(const char *in, int *first, int *max_count, int *athread)
593{
594  const char *ptr;
595
596  ASSERT(in != NULL);
597  ASSERT(*in == 'q');
598  ASSERT(*(in+1) == 'L');
599  ASSERT(first != NULL);
600  ASSERT(max_count != NULL);
601  ASSERT(athread != NULL);
602
603  ptr = in + 2;
604
605  /*  First */
606  if (!hstr2nibble(ptr, first))
607    {
608      return 0;
609    }
610  ptr++;
611
612  /* Max count */
613  if (!hstr2byte(ptr, max_count))
614    {
615      return 0;
616    }
617  ptr += 2;
618
619  /* A thread */
620  ptr = fhstr2thread(ptr, athread);
621  if (ptr == NULL)
622    {
623      return 0;
624    }
625
626  return 1;
627}
628
629/* Format: qM<count-02x><done-01x><arg_thread_id>[<found_thread_id-ft>...] */
630static char *
631reserve_qm_header(char *out)
632{
633  ASSERT(out != NULL);
634
635  return out + 21;
636}
637
638/* Format: qM<count-02x><done-01x><arg_thread_id>[<found_thread_id-ft>...] */
639static char*
640pack_qm_thread(char *out, int thread)
641{
642  ASSERT(out != 0);
643
644  return thread2fhstr(out, thread);
645}
646
647/* Format: qM<count-02x><done-01x><arg_thread_id>[<found_thread_id-ft>...] */
648static void
649pack_qm_header(char *out, int count, int done, int athread)
650{
651   ASSERT(out != 0);
652   ASSERT(count >= 0 && count < 256);
653
654   *out++ = 'q';
655   *out++ = 'M';
656
657   *out++ = gdb_hexchars[(count >> 4) & 0x0f];
658   *out++ = gdb_hexchars[count & 0x0f];
659
660   if (done) {
661      *out++ = '1';
662   } else {
663      *out++ = '0';
664   }
665
666   thread2fhstr(out, athread);
667   return;
668}
669
670
671
672
673
674
675
676
677
678
679
680
681void rtems_gdb_process_query(
682  char *inbuffer,
683  char *outbuffer,
684  int   do_threads,
685  int   thread
686)
687{
688  char *optr;
689   
690  switch(inbuffer[1]) {
691    case 'C':
692      /* Current thread query query - return stopped thread */
693      if (!do_threads) {
694        break;
695      }
696
697      optr = outbuffer;
698
699      *optr++ = 'Q';
700      *optr++ = 'C';
701      optr    = thread2vhstr(optr, thread);
702      *optr   = 0;
703      break;
704
705
706
707
708    case 'P':
709      /* Thread info query */
710      if (!do_threads) {
711        break;
712      }
713
714      {
715        int ret, rthread, mask;
716        struct rtems_gdb_stub_thread_info info;
717
718        ret = parse_qp(inbuffer, &mask, &rthread);
719        if (!ret|| mask & ~0x1f) {
720          strcpy(outbuffer, "E01");
721          break;
722        }
723
724        ret = rtems_gdb_stub_get_thread_info(rthread, &info);
725        if (!ret) {
726          /* Good implementation would never ask for non-existing thread,
727             should we care about bad ones - it does not seem so */
728          strcpy(outbuffer, "E02");
729          break;
730        }
731
732        /* Build response */
733        pack_qq(outbuffer, mask, rthread, &info);
734      }
735      break;
736
737
738
739
740
741    case 'L':
742      /* Thread list query */
743      if (!do_threads) {
744        break;
745      }
746
747      {
748        int ret, athread, first, max_cnt, i, done, rthread;
749
750        ret = parse_ql(inbuffer, &first, &max_cnt, &athread);
751        if (!ret) {
752          strcpy(outbuffer, "E02");
753          break;
754        }
755
756        if (max_cnt == 0) {
757          strcpy(outbuffer, "E02");
758          break;
759        }
760
761        if (max_cnt > QM_MAX_THREADS) {
762          /* Limit max count by buffer size */
763          max_cnt = QM_MAX_THREADS;
764        }
765
766        /* Reserve place for output header */
767        optr = reserve_qm_header(outbuffer);
768
769        if (first) {
770          rthread = 0;
771        } else {
772          rthread = athread;
773        }
774
775        done = 0;
776
777        for (i=0; i<max_cnt; i++) {
778          rthread = rtems_gdb_stub_get_next_thread(rthread);
779
780          if (rthread <= 0) {
781            done = 1; /* Set done flag */
782            break;
783          }
784
785          optr = pack_qm_thread(optr, rthread);
786        }
787
788        *optr = 0;
789
790        ASSERT((optr - outbuffer) < BUFMAX);
791
792        /* Fill header */
793        pack_qm_header(outbuffer, i, done, athread);
794      }
795      break;
796
797
798
799
800
801
802    default:
803      if (memcmp(inbuffer, "qOffsets", 8) == 0) {
804        unsigned char *t, *d, *b;
805        char *out;
806
807        if (!rtems_gdb_stub_get_offsets(&t, &d, &b)) {
808          break;
809        }
810
811        out = outbuffer;
812
813        *out++ = 'T';
814        *out++ = 'e';
815        *out++ = 'x';
816        *out++ = 't';
817        *out++ = '=';
818
819        out = int2vhstr(out, (int)t);
820
821        *out++ = ';';
822        *out++ = 'D';
823        *out++ = 'a';
824        *out++ = 't';
825        *out++ = 'a';
826        *out++ = '=';
827
828        out = int2vhstr(out, (int)d);
829
830        *out++ = ';';
831        *out++ = 'B';
832        *out++ = 's';
833        *out++ = 's';
834        *out++ = '=';
835
836        out = int2vhstr(out, (int)b);
837
838        *out++ = ';';
839        *out++ = 0;
840
841        break;
842      }
843
844      /*  qCRC, qRcmd, qu and qz will be added here */
845      break;
846    }
847}
848
849
850
851
852
853
854/* Present thread in the variable length string format */
855char*
856thread2vhstr(char *buf, int thread)
857{
858  int i, nibble, shift;
859
860  ASSERT(buf != NULL);
861
862  for(i=0, shift=28; i<8; i++, shift-=4)
863    {
864      nibble = (thread >> shift) & 0x0f;
865     
866      if (nibble != 0)
867        {
868          break;
869        }
870    }
871
872  if (i == 8)
873    {
874      *buf++ = '0';
875      return buf;
876    }
877
878  *buf++ = gdb_hexchars[nibble];
879
880  for(i++, shift-=4; i<8; i++, shift-=4, buf++)
881    {
882      nibble = (thread >> shift) & 0x0f;
883      *buf   = gdb_hexchars[nibble];
884    }
885
886  return buf;
887}
888
889/* Present thread in fixed length string format */
890char*
891thread2fhstr(char *buf, int thread)
892{
893  int i, nibble, shift;
894
895  ASSERT(buf != NULL);
896
897  for(i=0; i<8; i++, buf++)
898    {
899      *buf = '0';
900    }
901
902  for(i=0, shift=28; i<8; i++, shift-=4, buf++)
903    {
904      nibble = (thread >> shift) & 0x0f;
905      *buf   = gdb_hexchars[nibble];
906    }
907
908  return buf;
909}
910
911/* Parse thread presented in fixed length format */
912const char*
913fhstr2thread(const char *buf, int *thread)
914{
915  int i, val, nibble;
916
917  ASSERT(buf != NULL);
918  ASSERT(thread != NULL);
919
920  for(i=0; i<8; i++, buf++)
921    {
922      if (*buf != '0')
923        {
924          return NULL;
925        }
926    }
927
928  val = 0;
929
930  for(i=0; i<8; i++, buf++)
931    {
932      if (!hstr2nibble(buf, &nibble))
933        {
934          return NULL;
935        }
936
937      ASSERT(nibble >=0 && nibble < 16);
938
939      val = (val << 4) | nibble;
940    }
941
942  *thread = val;
943
944  return buf;
945}
946
947/* Parse thread presented in variable length format */
948const char*
949vhstr2thread(const char *buf, int *thread)
950{
951  int i, val, nibble;
952  int found_zero, lim;
953
954  ASSERT(buf != NULL);
955  ASSERT(thread != NULL);
956
957
958  /* If we have leading zeros, skip them */
959  found_zero = 0;
960
961  for(i=0; i<16; i++, buf++)
962    {
963      if (*buf != '0')
964        {
965          break;
966        }
967
968      found_zero = 1;
969    }
970
971  /* Process non-zeros */
972  lim = 16 - i;
973  val = 0;
974
975  for(i=0; i<lim; i++, buf++)
976    {
977      if (!hstr2nibble(buf, &nibble))
978        {
979          if (i == 0 && !found_zero)
980            {
981              /* Empty value */
982              return NULL;
983            }
984
985          *thread = val;
986          return buf;
987        }
988         
989      ASSERT(nibble >= 0 && nibble < 16);
990
991      val = (val << 4) | nibble;
992    }
993
994  if (hstr2nibble(buf, &nibble))
995    {
996      /* Value is too long */
997      return NULL;
998    }
999 
1000  *thread = val;
1001  return buf;
1002}
1003
1004
1005/* Present integer in the variable length string format */
1006char*
1007int2vhstr(char *buf, int val)
1008{
1009  int i, nibble, shift;
1010
1011  ASSERT(buf != NULL);
1012
1013  for(i=0, shift=28; i<8; i++, shift-=4)
1014    {
1015      nibble = (val >> shift) & 0x0f;
1016     
1017      if (nibble != 0)
1018        {
1019          break;
1020        }
1021    }
1022
1023  if (i == 8)
1024    {
1025      *buf++ = '0';
1026      return buf;
1027    }
1028
1029  *buf++ = gdb_hexchars[nibble];
1030
1031  for(i++, shift-=4; i<8; i++, shift-=4, buf++)
1032    {
1033      nibble = (val >> shift) & 0x0f;
1034      *buf   = gdb_hexchars[nibble];
1035    }
1036
1037  return buf;
1038}
1039
1040/* Present int in fixed length string format */
1041char*
1042int2fhstr(char *buf, int val)
1043{
1044  int i, nibble, shift;
1045
1046  ASSERT(buf != NULL);
1047
1048  for(i=0, shift=28; i<8; i++, shift-=4, buf++)
1049    {
1050      nibble = (val >> shift) & 0x0f;
1051      *buf   = gdb_hexchars[nibble];
1052    }
1053
1054  return buf;
1055}
1056
1057/* Parse int presented in fixed length format */
1058const char*
1059fhstr2int(const char *buf, int *ival)
1060{
1061  int i, val, nibble;
1062
1063  ASSERT(buf != NULL);
1064  ASSERT(ival != NULL);
1065
1066  val = 0;
1067
1068  for(i=0; i<8; i++, buf++)
1069    {
1070      if (!hstr2nibble(buf, &nibble))
1071        {
1072          return NULL;
1073        }
1074
1075      ASSERT(nibble >=0 && nibble < 16);
1076
1077      val = (val << 4) | nibble;
1078    }
1079
1080  *ival = val;
1081
1082  return buf;
1083}
1084
1085/* Parse int presented in variable length format */
1086const char*
1087vhstr2int(const char *buf, int *ival)
1088{
1089  int i, val, nibble;
1090  int found_zero, lim;
1091
1092  ASSERT(buf != NULL);
1093  ASSERT(ival != NULL);
1094
1095
1096  /* If we have leading zeros, skip them */
1097  found_zero = 0;
1098
1099  for(i=0; i<8; i++, buf++)
1100    {
1101      if (*buf != '0')
1102        {
1103          break;
1104        }
1105
1106      found_zero = 1;
1107    }
1108
1109  /* Process non-zeros */
1110  lim = 8 - i;
1111  val = 0;
1112
1113  for(i=0; i<lim; i++, buf++)
1114    {
1115      if (!hstr2nibble(buf, &nibble))
1116        {
1117          if (i == 0 && !found_zero)
1118            {
1119              /* Empty value */
1120              return NULL;
1121            }
1122
1123          *ival = val;
1124          return buf;
1125        }
1126         
1127      ASSERT(nibble >= 0 && nibble < 16);
1128
1129      val = (val << 4) | nibble;
1130    }
1131
1132  if (hstr2nibble(buf, &nibble))
1133    {
1134      /* Value is too long */
1135      return NULL;
1136    }
1137
1138  *ival = val;
1139  return buf;
1140}
1141
1142int
1143hstr2byte(const char *buf, int *bval)
1144{
1145  int hnib, lnib;
1146
1147  ASSERT(buf != NULL);
1148  ASSERT(bval != NULL);
1149
1150  if (!hstr2nibble(buf, &hnib) || !hstr2nibble(buf+1, &lnib))
1151    {
1152      return 0;
1153    }
1154
1155  *bval = (hnib << 4) | lnib;
1156  return 1;
1157}
1158
1159int
1160hstr2nibble(const char *buf, int *nibble)
1161{
1162  int ch;
1163
1164  ASSERT(buf != NULL);
1165  ASSERT(nibble != NULL);
1166
1167  ch = *buf;
1168
1169  if (ch >= '0' && ch <= '9')
1170    {
1171      *nibble = ch  - '0';
1172      return 1;
1173    }
1174
1175  if (ch >= 'a' && ch <= 'f')
1176    {
1177      *nibble = ch - 'a' + 10;
1178      return 1;
1179    }
1180
1181  if (ch >= 'A' && ch <= 'F')
1182    {
1183      *nibble = ch - 'A' + 10;
1184      return 1;
1185    }
1186
1187  return 0;
1188}
1189
1190static volatile char mem_err = 0;
1191void  set_mem_err(void);
1192static void (*volatile mem_fault_routine) (void) = NULL;
1193
1194
1195
1196/* convert count bytes of the memory pointed to by mem into hex string,
1197   placing result in buf, return pointer to next location in hex strng
1198   in case of success or NULL otherwise */
1199char*
1200mem2hstr(char *buf, const unsigned char *mem, int count)
1201{
1202  int i;
1203  unsigned char ch;
1204
1205  mem_err = 0;
1206
1207  mem_fault_routine = set_mem_err;
1208 
1209  for (i = 0; i<count; i++, mem++)
1210    {
1211      ch = get_byte (mem);
1212      if (mem_err)
1213        {
1214          mem_fault_routine = NULL;
1215          return NULL;
1216        }
1217     
1218      *buf++ = gdb_hexchars[ch >> 4];
1219      *buf++ = gdb_hexchars[ch & 0x0f];
1220    }
1221 
1222  *buf = 0;
1223
1224  mem_fault_routine = NULL;
1225
1226  return buf;
1227}
1228
1229/* convert the hex string to into count bytes of binary to be placed in mem
1230   return 1 in case of success and  0 otherwise */
1231int
1232hstr2mem (unsigned char *mem, const char *buf, int count)
1233{
1234  int i;
1235  int bval;
1236
1237  mem_err = 0;
1238
1239  mem_fault_routine = set_mem_err;
1240
1241  for (i = 0; i < count; i++, mem++, buf+=2)
1242    {
1243      if (!hstr2byte(buf, &bval))
1244        {
1245          mem_fault_routine = NULL;
1246          return 0;
1247        }
1248         
1249      ASSERT(bval >=0 && bval < 256);
1250
1251      set_byte (mem, bval);
1252
1253      if (mem_err)
1254        {
1255          mem_fault_routine = NULL;
1256          return 0;
1257        }
1258    }
1259
1260  mem_fault_routine = NULL;
1261  return 1;
1262}
1263
1264void
1265set_mem_err (void)
1266{
1267  mem_err = 1;
1268}
1269
1270
1271/* These are separate functions so that they are so short and sweet
1272   that the compiler won't save any registers (if there is a fault
1273   to mem_fault, they won't get restored, so there better not be any
1274   saved).  */
1275
1276unsigned char
1277get_byte (const unsigned char *addr)
1278{
1279  return *addr;
1280}
1281
1282void
1283set_byte (unsigned char *addr, int val)
1284{
1285  *addr = val;
1286}
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296/*
1297 *  From here down, the code is CPU model specific and generally maps
1298 *  the RTEMS thread context format to gdb's.
1299 */
1300
1301#if defined(__i386__)
1302
1303#include "i386-stub.h"
1304
1305/* Packing order of registers */
1306enum i386_stub_regnames {
1307  I386_STUB_REG_EAX, I386_STUB_REG_ECX, I386_STUB_REG_EDX, I386_STUB_REG_EBX,
1308  I386_STUB_REG_ESP, I386_STUB_REG_EBP, I386_STUB_REG_ESI, I386_STUB_REG_EDI,
1309  I386_STUB_REG_PC /* also known as eip */ ,
1310  I386_STUB_REG_PS /* also known as eflags */ ,
1311  I386_STUB_REG_CS, I386_STUB_REG_SS, I386_STUB_REG_DS, I386_STUB_REG_ES,
1312  I386_STUB_REG_FS, I386_STUB_REG_GS
1313};
1314
1315void rtems_gdb_stub_get_registers_from_context(
1316  int            *registers,
1317  Thread_Control *th
1318)
1319{
1320  registers[I386_STUB_REG_EAX] = 0;
1321  registers[I386_STUB_REG_ECX] = 0;
1322  registers[I386_STUB_REG_EDX] = 0;
1323  registers[I386_STUB_REG_EBX] = (int)th->Registers.ebx;
1324  registers[I386_STUB_REG_ESP] = (int)th->Registers.esp;
1325  registers[I386_STUB_REG_EBP] = (int)th->Registers.ebp;
1326  registers[I386_STUB_REG_ESI] = (int)th->Registers.esi;
1327  registers[I386_STUB_REG_EDI] = (int)th->Registers.edi;
1328  registers[I386_STUB_REG_PC]  = *(int *)th->Registers.esp;
1329  registers[I386_STUB_REG_PS]  = (int)th->Registers.eflags;
1330
1331  /* RTEMS never changes base registers (especially once
1332     threads are running) */
1333
1334  registers[I386_STUB_REG_CS]  = 0x8; /* We just know these values */
1335  registers[I386_STUB_REG_SS]  = 0x10;
1336  registers[I386_STUB_REG_DS]  = 0x10;
1337  registers[I386_STUB_REG_ES]  = 0x10;
1338  registers[I386_STUB_REG_FS]  = 0x10;
1339  registers[I386_STUB_REG_GS]  = 0x10;
1340}
1341
1342int rtems_gdb_stub_get_offsets(
1343  unsigned char **text_addr,
1344  unsigned char **data_addr,
1345  unsigned char **bss_addr
1346)
1347{
1348  extern unsigned char _text_start;
1349  extern unsigned char _data_start;
1350  extern unsigned char _bss_start;
1351
1352  *text_addr = &_text_start;
1353  *data_addr = &_data_start;
1354  *bss_addr  = &_bss_start;
1355
1356  return 1;
1357}
1358
1359
1360
1361
1362
1363#elif defined(__mips__)
1364
1365
1366void rtems_gdb_stub_get_registers_from_context(
1367  int            *registers,
1368  Thread_Control *th
1369)
1370{
1371   registers[S0] = (unsigned)th->Registers.s0;
1372   registers[S1] = (unsigned)th->Registers.s1;
1373   registers[S2] = (unsigned)th->Registers.s2;
1374   registers[S3] = (unsigned)th->Registers.s3;
1375   registers[S4] = (unsigned)th->Registers.s4;
1376   registers[S5] = (unsigned)th->Registers.s5;
1377   registers[S6] = (unsigned)th->Registers.s6;
1378   registers[S7] = (unsigned)th->Registers.s7;
1379
1380   registers[SP] = (unsigned)th->Registers.sp;
1381   registers[RA] = (unsigned)th->Registers.ra;
1382
1383   registers[SR] = (unsigned)th->Registers.c0_sr;
1384   registers[PC] = (unsigned)th->Registers.c0_epc;
1385}
1386
1387
1388int rtems_gdb_stub_get_offsets(
1389  unsigned char **text_addr,
1390  unsigned char **data_addr,
1391  unsigned char **bss_addr
1392)
1393{
1394/*
1395** These are the right symbols for the desired addresses,
1396** but giving them causes gdb to have fits, so we leave
1397** the reported values as 0.  Doesn't hurt the stub's
1398** operation as far as I've observed.
1399*/
1400
1401/*
1402  extern unsigned32 _ftext;
1403  extern unsigned32 _fdata;
1404  extern unsigned32 _bss_start;
1405
1406  *text_addr = &_ftext;
1407  *data_addr = &_fdata;
1408  *bss_addr  = &_bss_start;
1409*/
1410  *text_addr = 0;
1411  *data_addr = 0;
1412  *bss_addr  = 0;
1413  return 1;
1414}
1415
1416#else
1417#error "rtems-gdb-stub.c: Unsupported CPU!"
1418#endif
Note: See TracBrowser for help on using the repository browser.