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

4.104.114.84.95
Last change on this file since 1bbe2e1 was 1bbe2e1, checked in by Joel Sherrill <joel.sherrill@…>, on 02/27/02 at 22:32:15

2001-02-27 Joel Sherrill <joel@…>

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