source: rtems/cpukit/libdebugger/rtems-debugger-server.c @ 7f95cc0

5
Last change on this file since 7f95cc0 was 7f95cc0, checked in by Chris Johns <chrisj@…>, on 04/19/17 at 04:33:29

libdebugger: Fix the mode on task create. Clean up warnings.

Closes #2976.

  • Property mode set to 100644
File size: 51.4 KB
Line 
1/*
2 * Copyright (c) 2016 Chris Johns <chrisj@rtems.org>.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <errno.h>
27#include <stdlib.h>
28#include <unistd.h>
29
30#include <rtems/rtems-debugger.h>
31#include <rtems/debugger/rtems-debugger-server.h>
32#include <rtems/debugger/rtems-debugger-remote.h>
33
34#include "rtems-debugger-target.h"
35#include "rtems-debugger-threads.h"
36
37/*
38 * GDB Debugger Remote Server for RTEMS.
39 */
40
41/*
42 * Hack to void including bsp.h. The reset needs a better API.
43 */
44extern void bsp_reset(void);
45
46/*
47 * Command lookup table.
48 */
49typedef int (*rtems_debugger_command)(uint8_t* buffer, int size);
50
51typedef struct rtems_debugger_packet
52{
53  const char const*      label;
54  rtems_debugger_command command;
55} rtems_debugger_packet;
56
57/**
58 * Common error strings.
59 */
60static const char const* r_OK = "OK";
61static const char const* r_E01 = "E01";
62
63/*
64 * Global Debugger.
65 *
66 * The server instance is allocated on the heap so memory is only used then the
67 * server is running. A global is used because:
68 *
69 *  1. There can only be a single instance at once.
70 *  2. The backend's need access to the data and holding pointers in the TCB
71 *     for each thread is mess.
72 *  3. The code is smaller and faster.
73 */
74rtems_debugger_server* rtems_debugger;
75
76int
77rtems_debugger_printf(const char* format, ...)
78{
79  int     len;
80  va_list ap;
81  va_start(ap, format);
82  len = rtems_vprintf(&rtems_debugger->printer, format, ap);
83  va_end(ap);
84  return len;
85}
86
87bool
88rtems_debugger_verbose(void)
89{
90  return rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VERBOSE);
91}
92
93static inline int
94hex_decode(uint8_t ch)
95{
96  int i;
97  if (ch >= '0' && ch <= '9')
98    i = (int) (ch - '0');
99  else if (ch >= 'a' && ch <= 'f')
100    i = (int) (ch - 'a') + 10;
101  else if (ch >= 'A' && ch <= 'F')
102    i = (int) (ch - 'A') + 10;
103  else
104    i = -1;
105  return i;
106}
107
108static inline uint8_t
109hex_encode(int val)
110{
111  return "0123456789abcdef"[val & 0xf];
112}
113
114static inline DB_UINT
115hex_decode_uint(const uint8_t* data)
116{
117  DB_UINT ui = 0;
118  size_t  i;
119  if (data[0] == '-') {
120    if (data[1] == '1')
121      ui = (DB_UINT) -1;
122  }
123  else {
124    for (i = 0; i < (sizeof(ui) * 2); ++i) {
125      int v = hex_decode(data[i]);
126      if (v < 0)
127        break;
128      ui = (ui << 4) | v;
129    }
130  }
131  return ui;
132}
133
134static inline int
135hex_decode_int(const uint8_t* data)
136{
137  return (int) hex_decode_uint(data);
138}
139
140static bool
141thread_id_decode(const char* data, DB_UINT* pid, DB_UINT* tid)
142{
143  bool is_extended = false;
144  if (*data == 'p') {
145    is_extended = true;
146    ++data;
147  }
148  *pid = *tid = hex_decode_uint((const uint8_t*) data);
149  if (is_extended) {
150    const char* stop = strchr(data, '.');
151    if (stop != NULL) {
152      *tid = hex_decode_uint((const uint8_t*) stop + 1);
153    }
154  }
155  return is_extended;
156}
157
158static inline bool
159check_pid(DB_UINT pid)
160{
161  return pid == 0|| rtems_debugger->pid == (pid_t) pid;
162}
163
164int
165rtems_debugger_lock(void)
166{
167  if (rtems_debugger->lock != 0) {
168    rtems_status_code sc;
169    sc = rtems_semaphore_obtain(rtems_debugger->lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
170    if (sc != RTEMS_SUCCESSFUL) {
171      rtems_debugger_printf("error: rtems-db: lock: %s\n",
172                            rtems_status_text(sc));
173      return -1;
174    }
175  }
176  return 0;
177}
178
179int
180rtems_debugger_unlock(void)
181{
182  if (rtems_debugger->lock != 0) {
183    rtems_status_code sc;
184    sc = rtems_semaphore_release(rtems_debugger->lock);
185    if (sc != RTEMS_SUCCESSFUL) {
186      rtems_debugger_printf("error: rtems-db: unlock: %s\n",
187                            rtems_status_text(sc));
188      return -1;
189    }
190  }
191  return 0;
192}
193
194static int
195rtems_debugger_lock_create(void)
196{
197  #define LOCK_ATTRIBUTES \
198    RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY | RTEMS_BINARY_SEMAPHORE
199  rtems_status_code sc;
200  sc = rtems_semaphore_create(rtems_build_name('G', 'D', 'B', 's'),
201                              1,
202                              LOCK_ATTRIBUTES,
203                              0,
204                              &rtems_debugger->lock);
205  if (sc != RTEMS_SUCCESSFUL) {
206    rtems_debugger_printf("error: rtems-db: sema create: %s\n",
207                          rtems_status_text(sc));
208    errno = EIO;
209    return -1;
210  }
211  return 0;
212}
213
214static int
215rtems_debugger_lock_destroy(void)
216{
217  rtems_debugger_lock();
218  if (rtems_debugger->lock != 0) {
219    rtems_status_code sc;
220    rtems_semaphore_release(rtems_debugger->lock);
221    sc = rtems_semaphore_delete(rtems_debugger->lock);
222    rtems_debugger->lock = 0;
223    if (sc != RTEMS_SUCCESSFUL) {
224      rtems_debugger_printf("error: rtems-db: sema delete: %s\n",
225                            rtems_status_text(sc));
226      return -1;
227    }
228  }
229  return 0;
230}
231
232static int
233rtems_debugger_task_create(const char*         name,
234                           rtems_task_priority priority,
235                           size_t              stack_size,
236                           rtems_task_entry    entry_point,
237                           rtems_task_argument argument,
238                           rtems_id*           id)
239{
240  rtems_name        tname;
241  rtems_status_code sc;
242
243  tname = rtems_build_name(name[0], name[1], name[2], name[3]);
244
245  sc = rtems_task_create (tname,
246                          priority,
247                          stack_size,
248                          RTEMS_PREEMPT | RTEMS_NO_ASR,
249                          RTEMS_LOCAL | RTEMS_FLOATING_POINT,
250                          id);
251  if (sc != RTEMS_SUCCESSFUL) {
252    *id = 0;
253    rtems_debugger_printf("error: rtems-db: thread create: %s: %s\n",
254                          name, rtems_status_text(sc));
255    errno = EIO;
256    return -1;
257  }
258
259  sc = rtems_task_start(*id, entry_point, argument);
260  if (sc != RTEMS_SUCCESSFUL) {
261    rtems_debugger_printf("error: rtems-db: thread start: %s: %s\n",
262                          name, rtems_status_text(sc));
263    rtems_task_delete(*id);
264    *id = 0;
265    errno = EIO;
266    return -1;
267  }
268
269  return 0;
270}
271
272static int
273rtems_debugger_task_destroy(const char*    name,
274                            rtems_id       id,
275                            volatile bool* finished,
276                            int            timeout)
277{
278  while (timeout) {
279    bool has_finished;
280
281    rtems_debugger_lock();
282    has_finished = *finished;
283    rtems_debugger_unlock();
284
285    if (has_finished)
286      break;
287
288    usleep(RTEMS_DEBUGGER_POLL_WAIT);
289    if (timeout < RTEMS_DEBUGGER_POLL_WAIT)
290      timeout = 0;
291    else
292      timeout -= RTEMS_DEBUGGER_POLL_WAIT;
293  }
294
295  if (timeout == 0) {
296    rtems_debugger_printf("rtems-db: %s not stopping, killing\n", name);
297    rtems_task_delete(id);
298  }
299  return 0;
300}
301
302bool
303rtems_debugger_server_running(void)
304{
305  bool running;
306  rtems_debugger_lock();
307  running = rtems_debugger->server_running;
308  rtems_debugger_unlock();
309  return running;
310}
311
312rtems_debugger_remote*
313rtems_debugger_remote_handle(void)
314{
315  rtems_debugger_remote* remote;
316  rtems_debugger_lock();
317  remote = rtems_debugger->remote;
318  rtems_debugger_unlock();
319  return remote;
320}
321
322bool
323rtems_debugger_connected(void)
324{
325  bool isconnected = false;
326  rtems_debugger_lock();
327  if (rtems_debugger->remote != NULL)
328    isconnected = rtems_debugger->remote->isconnected(rtems_debugger->remote);
329  rtems_debugger_unlock();
330  return isconnected;
331}
332
333bool
334rtems_debugger_server_events_running(void)
335{
336  bool running;
337  rtems_debugger_lock();
338  running = rtems_debugger->events_running;
339  rtems_debugger_unlock();
340  return running;
341}
342
343int
344rtems_debugger_server_events_wake(void)
345{
346  rtems_status_code sc;
347  int               r = 0;
348  sc = rtems_event_send(rtems_debugger->events_task, RTEMS_EVENT_1);
349  if (sc != RTEMS_SUCCESSFUL) {
350    rtems_debugger_printf("error: rtems-db: event send: %s\n",
351                          rtems_status_text(sc));
352    errno = EIO;
353    r = -1;
354  }
355  return r;
356}
357
358static int
359rtems_debugger_server_events_wait(void)
360{
361  rtems_event_set   out = 0;
362  rtems_status_code sc;
363  int               r = 0;
364  rtems_debugger_unlock();
365  while (true) {
366    sc = rtems_event_receive(RTEMS_EVENT_1,
367                             RTEMS_EVENT_ALL | RTEMS_WAIT,
368                             RTEMS_NO_TIMEOUT,
369                             &out);
370    if (sc != RTEMS_SUCCESSFUL) {
371      rtems_debugger_printf("error: rtems-db: event receive: %s\n",
372                            rtems_status_text(sc));
373      errno = EIO;
374      r = -1;
375      break;
376    }
377    if (out == RTEMS_EVENT_1)
378      break;
379  }
380  rtems_debugger_lock();
381  return r;
382}
383
384static int
385rtems_debugger_remote_connect(void)
386{
387  rtems_debugger_remote* remote = rtems_debugger_remote_handle();
388  if (remote != NULL) {
389    if (!remote->isconnected(remote))
390      return remote->connect(remote);
391  }
392  errno = EIO;
393  return -1;
394}
395
396static int
397rtems_debugger_remote_disconnect(void)
398{
399  rtems_debugger_remote* remote = rtems_debugger_remote_handle();
400  if (remote != NULL) {
401    if (remote->isconnected(remote))
402      return remote->disconnect(remote);
403  }
404  errno = EIO;
405  return -1;
406}
407
408static int
409rtems_debugger_remote_receive(uint8_t* buffer, size_t size)
410{
411  rtems_debugger_remote* remote = rtems_debugger_remote_handle();
412  ssize_t len = remote->read(remote, buffer, size);
413  if (len < 0 && errno != EAGAIN)
414    rtems_debugger_printf("rtems-db: read: (%d) %s\n",
415                          errno, strerror(errno));
416  return (int) len;
417}
418
419static int
420rtems_debugger_remote_send(void)
421{
422  const uint8_t* buffer = rtems_debugger->output;
423  ssize_t        size = rtems_debugger->output_level;
424
425  if (rtems_debugger->output_level > RTEMS_DEBUGGER_BUFFER_SIZE) {
426    rtems_debugger_printf("rtems-db: write too big: %d\n",
427                          (int) rtems_debugger->output_level);
428    return -1;
429  }
430
431  if (rtems_debugger->remote_debug) {
432    size_t i = 0;
433    rtems_debugger_printf("rtems-db: put:%4zu: ", rtems_debugger->output_level);
434    while (i < rtems_debugger->output_level)
435      rtems_debugger_printf("%c", (char) rtems_debugger->output[i++]);
436    rtems_debugger_printf("\n");
437  }
438
439  while (size) {
440    rtems_debugger_remote* remote = rtems_debugger_remote_handle();
441    ssize_t                w;
442    if (remote == NULL) {
443      errno = EIO;
444      return -1;
445    }
446    w = remote->write(remote, buffer, size);
447    if (w < 0 && errno != EINTR) {
448      rtems_debugger_printf("rtems-db: write: (%d) %s\n",
449                            errno, strerror(errno));
450      break;
451    }
452    else {
453      size -= w;
454      buffer += w;
455    }
456  }
457
458  return (int) rtems_debugger->output_level;
459}
460
461static int
462rtems_debugger_remote_send_ack(void)
463{
464  rtems_debugger->output[0] = '+';
465  rtems_debugger->output_level = 1;
466  return rtems_debugger_remote_send();
467}
468
469static int
470rtems_debugger_remote_send_nack(void)
471{
472  rtems_debugger->output[0] = '-';
473  rtems_debugger->output_level = 1;
474  return rtems_debugger_remote_send();
475}
476
477static int
478rtems_debugger_remote_packet_in(void)
479{
480  uint8_t buf[256];
481  uint8_t state;
482  int     in = 0;
483  uint8_t csum = 0;
484  uint8_t rx_csum = 0;
485  bool    junk = false;
486  bool    escaped = false;
487  bool    remote_debug_header = true;
488
489  /*
490   * States:
491   *  'H' : Looking for the start character '$', '-' or '+'.
492   *  'P' : Looking for the checksum character '#' else buffer data.
493   *  '1' : Looking for the first checksum character.
494   *  '2' : Looking for the second checksum character.
495   *  'F' : Finished.
496   */
497
498  state = 'H';
499
500  while (state != 'F') {
501    int r;
502    int i;
503
504    rtems_debugger_unlock();
505
506    r = rtems_debugger_remote_receive(buf, sizeof(buf));
507
508    rtems_debugger_lock();
509
510    if (r <= 0) {
511      /*
512       * Timeout?
513       */
514      if (r < 0 && errno == EAGAIN) {
515        if (rtems_debugger->ack_pending) {
516          rtems_debugger_remote_send();
517        }
518        continue;
519      }
520      if (r == 0)
521        rtems_debugger_printf("rtems-db: remote disconnected\n");
522      return -1;
523    }
524
525    i = 0;
526
527    while (i < r) {
528      uint8_t c = buf[i++];
529
530      if (rtems_debugger->remote_debug && remote_debug_header) {
531        rtems_debugger_printf("rtems-db: get:%4d: ", r);
532        remote_debug_header = false;
533      }
534
535      if (rtems_debugger->remote_debug)
536        rtems_debugger_printf("%c", c);
537
538      switch (state) {
539      case 'H':
540        switch (c) {
541        case '+':
542          if (rtems_debugger->remote_debug) {
543            rtems_debugger_printf(" [[ACK%s]]\n",
544                                  rtems_debugger->ack_pending ? "" : "?");
545            remote_debug_header = true;
546          }
547          rtems_debugger->ack_pending = false;
548          break;
549        case '-':
550          if (rtems_debugger->remote_debug) {
551            rtems_debugger_printf(" [[NACK]]\n");
552            remote_debug_header = true;
553          }
554          /*
555           * Resend.
556           */
557          rtems_debugger_remote_send();
558          break;
559        case '$':
560          state = 'P';
561          csum = 0;
562          in = 0;
563          if (junk && rtems_debugger->remote_debug) {
564            rtems_debugger_printf("\b [[junk dropped]]\nrtems-db: get:   : $");
565            remote_debug_header = false;
566          }
567          break;
568        case '\x3':
569          if (rtems_debugger->remote_debug)
570            rtems_debugger_printf("^C [[BREAK]]\n");
571          rtems_debugger->ack_pending = false;
572          rtems_debugger->input[0] =  '^';
573          rtems_debugger->input[1] =  'C';
574          rtems_debugger->input[2] =  '\0';
575          return 2;
576        default:
577          junk = true;
578          break;
579        }
580        break;
581      case 'P':
582        if (c == '{' && !escaped) {
583          escaped = true;
584        }
585        else if (c == '$' && !escaped) {
586          csum = 0;
587          in = 0;
588          if (rtems_debugger->remote_debug) {
589            rtems_debugger_printf("\n");
590            remote_debug_header = true;
591          }
592        }
593        else if (c == '#' && !escaped) {
594          rtems_debugger->input[in] = '\0';
595          rx_csum = 0;
596          state = '1';
597        }
598        else {
599          if (in >= (RTEMS_DEBUGGER_BUFFER_SIZE - 1)) {
600            rtems_debugger_printf("rtems-db: input buffer overflow\n");
601            return -1;
602          }
603          csum += c;
604          rtems_debugger->input[in++] = c;
605        }
606        break;
607      case '1':
608        rx_csum = (rx_csum << 4) | (uint8_t) hex_decode(c);
609        state = '2';
610        break;
611      case '2':
612        rx_csum = (rx_csum << 4) | (uint8_t) hex_decode(c);
613        if (csum == rx_csum) {
614          state = 'F';
615          if (rtems_debugger->remote_debug)
616            rtems_debugger_printf("\n");
617          rtems_debugger_remote_send_ack();
618        }
619        else {
620          if (rtems_debugger->remote_debug) {
621            rtems_debugger_printf(" [[invalid checksum]]\n");
622            remote_debug_header = true;
623            rtems_debugger_remote_send_nack();
624          }
625          state = 'H';
626        }
627        break;
628      case 'F':
629          if (rtems_debugger->remote_debug)
630            rtems_debugger_printf(" [[extra data: 0x%02x]]", (int) c);
631        break;
632      default:
633        rtems_debugger_printf("rtems-db: bad state\n");
634        rtems_debugger_remote_send_nack();
635        return -1;
636      }
637    }
638  }
639
640  return in;
641}
642
643static int
644rtems_debugger_remote_packet_in_hex(uint8_t*    addr,
645                                    const char* data,
646                                    size_t      size)
647{
648  size_t i;
649  for (i = 0; i < size; ++i) {
650    *addr = (hex_decode(*data++) << 4);
651    *addr++ |= hex_decode(*data++);
652  }
653  return 0;
654}
655
656#if KEEP_INCASE
657static void
658remote_packet_out_rewind(size_t size)
659{
660  size_t i = 0;
661  while (rtems_debugger->output_level > 0 && i < size) {
662    if (rtems_debugger->output_level > 1) {
663      if (rtems_debugger->output[rtems_debugger->output_level - 1] == '}') {
664        --rtems_debugger->output_level;
665      }
666    }
667    --rtems_debugger->output_level;
668    --i;
669  }
670}
671#endif
672
673static int
674remote_packet_out_append_buffer(const char* buffer, size_t size)
675{
676  size_t ol = rtems_debugger->output_level;
677  size_t i = 0;
678  while (i < size) {
679    char c = buffer[i++];
680    if (c == '#' || c == '$') {
681      if (rtems_debugger->output_level >= (RTEMS_DEBUGGER_BUFFER_SIZE - 1)) {
682        rtems_debugger->output_level = ol;
683        rtems_debugger_printf("rtems-db: output overflow\n");
684        return -1;
685      }
686      rtems_debugger->output[rtems_debugger->output_level++] = '}';
687      c ^= 0x20;
688    }
689    if (rtems_debugger->output_level >= (RTEMS_DEBUGGER_BUFFER_SIZE - 1)) {
690      rtems_debugger->output_level = ol;
691      rtems_debugger_printf("rtems-db: output overflow\n");
692      return -1;
693    }
694    rtems_debugger->output[rtems_debugger->output_level++] = c;
695  }
696  return 0;
697}
698
699static int
700remote_packet_out_append_hex(const uint8_t* data, size_t size)
701{
702  size_t ol = rtems_debugger->output_level;
703  size_t i = 0;
704  while (i < size) {
705    uint8_t byte = data[i++];
706    if (rtems_debugger->output_level >= (RTEMS_DEBUGGER_BUFFER_SIZE - 2)) {
707      rtems_debugger->output_level = ol;
708      rtems_debugger_printf("rtems-db: output overflow\n");
709      return -1;
710    }
711    rtems_debugger->output[rtems_debugger->output_level++] = hex_encode(byte >> 4);
712    rtems_debugger->output[rtems_debugger->output_level++] = hex_encode(byte);
713  }
714  return 0;
715}
716
717static int
718remote_packet_out_append_str(const char* str)
719{
720  return remote_packet_out_append_buffer(str, strlen(str));
721}
722
723static int
724remote_packet_out_append_vprintf(const char* fmt, va_list ap)
725{
726  int  len;
727  char buffer[64];
728  len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
729  return remote_packet_out_append_buffer(buffer, len);
730}
731
732static int
733remote_packet_out_append(const char* fmt, ...)
734{
735  va_list ap;
736  int     r;
737  va_start(ap, fmt);
738  r = remote_packet_out_append_vprintf(fmt, ap);
739  va_end(ap);
740  return r;
741}
742
743static void
744remote_packet_out_reset(void)
745{
746  rtems_debugger->output_level = 1;
747  rtems_debugger->output[0] = '$';
748}
749
750static int
751remote_packet_out_buffer(const char* buffer, size_t size)
752{
753  remote_packet_out_reset();
754  return remote_packet_out_append_buffer(buffer, size);
755}
756
757static int
758remote_packet_out_str(const char* str)
759{
760  remote_packet_out_reset();
761  return remote_packet_out_append_buffer(str, strlen(str));
762}
763
764static int
765remote_packet_out(const char* fmt, ...)
766{
767  va_list ap;
768  int     r;
769  va_start(ap, fmt);
770  remote_packet_out_reset();
771  r = remote_packet_out_append_vprintf(fmt, ap);
772  va_end(ap);
773  return r;
774}
775
776static int
777remote_packet_out_send(void)
778{
779  uint8_t csum = 0;
780  size_t  i = 1;
781
782  if (rtems_debugger->output_level >= (RTEMS_DEBUGGER_BUFFER_SIZE - 3)) {
783    rtems_debugger_printf("rtems-db: output overflow\n");
784    return -1;
785  }
786
787  while (i < rtems_debugger->output_level) {
788    csum += rtems_debugger->output[i++];
789  }
790
791  rtems_debugger->output[rtems_debugger->output_level++] = '#';
792  rtems_debugger->output[rtems_debugger->output_level++] = hex_encode((csum >> 4) & 0xf);
793  rtems_debugger->output[rtems_debugger->output_level++] = hex_encode(csum & 0xf);
794
795  rtems_debugger->ack_pending = true;;
796
797  return rtems_debugger_remote_send();
798}
799
800static int
801remote_packet_dispatch(const rtems_debugger_packet* packet,
802                       size_t                       packets,
803                       uint8_t*                     buffer,
804                       int                          size)
805{
806  const rtems_debugger_packet* p;
807  size_t                       i;
808  int                          r = -1;
809  for (i = 0, p = &packet[0]; i < packets; ++i, ++p) {
810    if (strncmp(p->label,
811                (const char*) &buffer[0],
812                strlen(p->label)) == 0) {
813      r = p->command(buffer, size);
814      break;
815    }
816  }
817  if (r < 0) {
818    remote_packet_out_buffer("", 0);
819    remote_packet_out_send();
820  }
821  return 0;
822}
823
824static int
825remote_detach(uint8_t* buffer, int size)
826{
827  remote_packet_out_str(r_OK);
828  remote_packet_out_send();
829  rtems_debugger_remote_disconnect();
830  return 0;
831}
832
833static int
834remote_ut_features(uint8_t* buffer, int size)
835{
836  return -1;
837}
838
839static int
840remote_ut_osdata(uint8_t* buffer, int size)
841{
842  return -1;
843}
844
845static const rtems_debugger_packet uninterpreted_transfer[] = {
846  { .label   = "qXfer:features",
847    .command = remote_ut_features },
848  { .label   = "qXfer:osdata",
849    .command = remote_ut_osdata },
850};
851
852#define REMOTE_UNINTERPRETED_TRANSFERS \
853  RTEMS_DEBUGGER_NUMOF(uninterpreted_transfer)
854
855static int
856remote_gq_uninterpreted_transfer(uint8_t* buffer, int size)
857{
858  return remote_packet_dispatch(uninterpreted_transfer,
859                                REMOTE_UNINTERPRETED_TRANSFERS,
860                                buffer, size);
861}
862
863static int
864remote_gq_thread_info_subsequent(uint8_t* buffer, int size)
865{
866  rtems_debugger_threads* threads = rtems_debugger->threads;
867  if (threads->next >= threads->current.level)
868    remote_packet_out_str("l");
869  else {
870    rtems_debugger_thread* current;
871    const char*            format = "p%d.%08lx";
872    current = rtems_debugger_thread_current(threads);
873    remote_packet_out_str("m");
874    while (threads->next < threads->current.level) {
875      int r;
876      r = remote_packet_out_append(format,
877                                   rtems_debugger->pid,
878                                   current[threads->next].id);
879      if (r < 0)
880        break;
881      format = ",p%d.%08lx";
882      ++threads->next;
883    }
884  }
885  remote_packet_out_send();
886  return 0;
887}
888
889static int
890remote_gq_thread_info_first(uint8_t* buffer, int size)
891{
892  rtems_debugger->threads->next = 0;
893  return remote_gq_thread_info_subsequent(buffer, size);
894}
895
896static int
897remote_gq_thread_extra_info(uint8_t* buffer, int size)
898{
899  const char* comma;
900  remote_packet_out_reset();
901  comma = strchr((const char*) buffer, ',');
902  if (comma != NULL) {
903    DB_UINT pid = 0;
904    DB_UINT tid = 0;
905    bool    extended;
906    extended = thread_id_decode(comma + 1, &pid, &tid);
907    if (!extended || (extended && check_pid(pid))) {
908      int r;
909      r = rtems_debugger_thread_find_index(tid);
910      if (r >= 0) {
911        rtems_debugger_threads* threads = rtems_debugger->threads;
912        rtems_debugger_thread*  current;
913        rtems_debugger_thread*  thread;
914        char                    buf[128];
915        char                    str[32];
916        size_t                  l;
917        current = rtems_debugger_thread_current(threads);
918        thread = &current[r];
919        l = snprintf(buf, sizeof(buf),
920                     "%4s (%08lx), ", thread->name, thread->id);
921        remote_packet_out_append_hex((const uint8_t*) buf, l);
922        l = snprintf(buf, sizeof(buf),
923                     "priority(c:%3d r:%3d), ",
924                     rtems_debugger_thread_current_priority(thread),
925                     rtems_debugger_thread_real_priority(thread));
926        remote_packet_out_append_hex((const uint8_t*) buf, l);
927        l = snprintf(buf, sizeof(buf),
928                     "stack(s:%6lu a:%p), ",
929                     rtems_debugger_thread_stack_size(thread),
930                     rtems_debugger_thread_stack_area(thread));
931        remote_packet_out_append_hex((const uint8_t*) buf, l);
932        rtems_debugger_thread_state_str(thread, str, sizeof(str));
933        l = snprintf(buf, sizeof(buf), "state(%s)", str);
934        remote_packet_out_append_hex((const uint8_t*) buf, l);
935      }
936    }
937  }
938  remote_packet_out_send();
939  return 0;
940}
941
942static int
943remote_gq_supported(uint8_t* buffer, int size)
944{
945  uint32_t    capabilities = rtems_debugger_target_capabilities();
946  const char* p;
947  bool        swbreak = false;
948  bool        hwbreak = false;
949  bool        vCont = false;
950  bool        no_resumed = false;
951  bool        multiprocess = false;
952  remote_packet_out("qSupported:PacketSize=%d;QNonStop-",
953                    RTEMS_DEBUGGER_BUFFER_SIZE);
954  p = strchr((const char*) buffer, ':');
955  if (p != NULL)
956    ++p;
957  while (p != NULL && p != '\0') {
958    bool  echo = false;
959    char* sc;
960    sc = strchr(p, ';');
961    if (sc != NULL) {
962      *sc++ = '\0';
963    }
964    if (strcmp(p, "swbreak+") == 0 &&
965        !swbreak && (capabilities & RTEMS_DEBUGGER_TARGET_CAP_SWBREAK) != 0) {
966      swbreak = true;
967      echo = true;
968    }
969    if (strcmp(p, "hwbreak+") == 0 &&
970        !hwbreak && (capabilities & RTEMS_DEBUGGER_TARGET_CAP_HWBREAK) != 0) {
971      hwbreak = true;
972      echo = true;
973    }
974    if (!vCont && strcmp(p, "vContSupported+") == 0) {
975      rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_VCONT;
976      vCont = true;
977      echo = true;
978    }
979    if (!no_resumed && strcmp(p, "no-resumed+") == 0) {
980      no_resumed = true;
981      echo = true;
982    }
983    if (!multiprocess && strcmp(p, "multiprocess+") == 0) {
984      rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_MULTIPROCESS;
985      multiprocess = true;
986      echo = true;
987    }
988
989    if (echo) {
990      remote_packet_out_append_str(";");
991      remote_packet_out_append_str(p);
992    }
993    else if (strncmp(p, "xmlRegisters", sizeof("xmlRegisters") - 1) == 0) {
994      /* ignore */
995    }
996    else {
997      remote_packet_out_append_str(";");
998      remote_packet_out_append_buffer(p, strlen(p) - 1);
999      remote_packet_out_append_str("-");
1000    }
1001    p = sc;
1002  }
1003  if (!swbreak && (capabilities & RTEMS_DEBUGGER_TARGET_CAP_SWBREAK) != 0) {
1004    remote_packet_out_append_str("swbreak+;");
1005  }
1006  if (!hwbreak && (capabilities & RTEMS_DEBUGGER_TARGET_CAP_HWBREAK) != 0) {
1007    remote_packet_out_append_str("hwbreak+;");
1008  }
1009  if (!vCont) {
1010    remote_packet_out_append_str("vContSupported+;");
1011  }
1012  if (!no_resumed) {
1013    remote_packet_out_append_str("no-resumed+;");
1014  }
1015  if (!multiprocess) {
1016    remote_packet_out_append_str("multiprocess+;");
1017  }
1018  remote_packet_out_send();
1019  return 0;
1020}
1021
1022static int
1023remote_gq_attached(uint8_t* buffer, int size)
1024{
1025  const char const* response = "1";
1026  const char*       colon = strchr((const char*) buffer, ':');
1027  if (colon != NULL) {
1028    DB_UINT pid = hex_decode_uint((const uint8_t*) colon + 1);
1029    if ((pid_t) pid != rtems_debugger->pid)
1030      response = r_E01;
1031  }
1032  remote_packet_out_str(response);
1033  remote_packet_out_send();
1034  return 0;
1035}
1036
1037static const rtems_debugger_packet general_query[] = {
1038  { .label   = "qfThreadInfo",
1039    .command = remote_gq_thread_info_first },
1040  { .label   = "qsThreadInfo",
1041    .command = remote_gq_thread_info_subsequent },
1042  { .label   = "qThreadExtraInfo",
1043    .command = remote_gq_thread_extra_info },
1044  { .label   = "qSupported",
1045    .command = remote_gq_supported },
1046  { .label   = "qAttached",
1047    .command = remote_gq_attached },
1048  { .label   = "qXfer",
1049    .command = remote_gq_uninterpreted_transfer },
1050};
1051
1052#define REMOTE_GENERAL_QUERIES RTEMS_DEBUGGER_NUMOF(general_query)
1053
1054static int
1055remote_general_query(uint8_t* buffer, int size)
1056{
1057  return remote_packet_dispatch(general_query, REMOTE_GENERAL_QUERIES,
1058                                buffer, size);
1059}
1060
1061static int
1062remote_gs_non_stop(uint8_t* buffer, int size)
1063{
1064  const char const* response = r_E01;
1065  char*       p = strchr((char*) buffer, ':');
1066  if (p != NULL) {
1067    ++p;
1068    response = r_OK;
1069    if (*p == '0') {
1070      rtems_debugger->flags &= ~RTEMS_DEBUGGER_FLAG_NON_STOP;
1071    }
1072    else if (*p == '1') {
1073      rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_NON_STOP;
1074    }
1075    else
1076      response = r_E01;
1077  }
1078  remote_packet_out_str(response);
1079  remote_packet_out_send();
1080  return 0;
1081}
1082
1083static const rtems_debugger_packet general_set[] = {
1084  { .label   = "QNonStop",
1085    .command = remote_gs_non_stop },
1086};
1087
1088#define REMOTE_GENERAL_SETS RTEMS_DEBUGGER_NUMOF(general_set)
1089
1090static int
1091remote_general_set(uint8_t* buffer, int size)
1092{
1093  return remote_packet_dispatch(general_set, REMOTE_GENERAL_SETS,
1094                                buffer, size);
1095}
1096
1097static int
1098remote_v_stopped(uint8_t* buffer, int size)
1099{
1100  rtems_debugger_threads* threads = rtems_debugger->threads;
1101  if (threads->next >= threads->stopped.level)
1102    remote_packet_out_str(r_OK);
1103  else {
1104    rtems_id* stopped;
1105    remote_packet_out("T%02x", rtems_debugger->signal);
1106    stopped = rtems_debugger_thread_stopped(threads);
1107    while (threads->next < threads->stopped.level) {
1108      int r;
1109      r = remote_packet_out_append("thread:p%d.%08lx;",
1110                                   rtems_debugger->pid,
1111                                   stopped[threads->next]);
1112      if (r < 0)
1113        break;
1114      ++threads->next;
1115    }
1116  }
1117  remote_packet_out_send();
1118  return 0;
1119}
1120
1121static int
1122remote_stop_reason(uint8_t* buffer, int size)
1123{
1124  rtems_debugger->threads->next = 0;
1125  return remote_v_stopped(buffer, size);
1126}
1127
1128static int
1129remote_v_continue(uint8_t* buffer, int size)
1130{
1131  buffer += 5;
1132
1133  if (buffer[0] == '?') {
1134    /*
1135     * You need to supply 'c' and 'C' or GDB says vCont is not supported. As
1136     * Sammy-J says "Silly GDB".
1137     */
1138    remote_packet_out_str("vCont;c;C;s;r;");
1139  }
1140  else {
1141    const char* semi = (const char*) &buffer[0];
1142    bool        resume = false;
1143    bool        ok = true;
1144    while (ok && semi != NULL) {
1145      const char* colon = strchr(semi + 1, ':');
1146      const char  action = *(semi + 1);
1147      DB_UINT     pid = 0;
1148      DB_UINT     tid = 0;
1149      bool        extended;
1150      if (colon != NULL) {
1151        int r = -1;
1152        extended = thread_id_decode(colon + 1, &pid, &tid);
1153        if (extended || check_pid(pid)) {
1154          rtems_debugger_threads* threads = rtems_debugger->threads;
1155          rtems_debugger_thread*  thread = NULL;
1156          int                     index = 0;
1157          if (tid != (DB_UINT) -1) {
1158            rtems_debugger_thread* current;
1159            current = rtems_debugger_thread_current(threads);
1160            index = rtems_debugger_thread_find_index(tid);
1161            if (index >= 0)
1162              thread = &current[index];
1163          }
1164          switch (action) {
1165          case 'c':
1166          case 'C':
1167            if (tid == (DB_UINT) -1) {
1168              r = rtems_debugger_thread_continue_all();
1169            }
1170            else if (thread != NULL) {
1171              r = rtems_debugger_thread_continue(thread);
1172            }
1173            if (r == 0)
1174              resume = true;
1175            break;
1176          case 's':
1177            if (thread != NULL) {
1178              r = rtems_debugger_thread_step(thread);
1179              if (r == 0)
1180                resume = true;
1181            }
1182            break;
1183          case 'r':
1184            /*
1185             * Range to step around inside: `r start,end`.
1186             */
1187            if (thread != NULL) {
1188              const char* comma;
1189              comma = strchr(semi + 2, ',');
1190              if (comma != NULL) {
1191                DB_UINT start;
1192                DB_UINT end;
1193                start = hex_decode_uint((const uint8_t*) semi + 2);
1194                end = hex_decode_uint((const uint8_t*) comma + 1);
1195                r = rtems_debugger_thread_stepping(thread, start, end);
1196                if (r == 0)
1197                  resume = true;
1198              }
1199              else {
1200                ok = false;
1201              }
1202            }
1203            break;
1204          default:
1205            ok = false;
1206            break;
1207          }
1208          if (r < 0)
1209            ok = false;
1210        }
1211      }
1212      else {
1213        ok = false;
1214      }
1215      semi = strchr(semi + 1, ';');
1216    }
1217
1218    if (ok)
1219      remote_packet_out_str(r_OK);
1220    else
1221      remote_packet_out_str(r_E01);
1222
1223    if (resume)
1224      rtems_debugger_thread_system_resume(false);
1225  }
1226
1227  remote_packet_out_send();
1228
1229  return 0;
1230}
1231
1232static int
1233remote_v_kill(uint8_t* buffer, int size)
1234{
1235  rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_RESET;
1236  return remote_detach(buffer, size);
1237}
1238
1239static const rtems_debugger_packet v_packets[] = {
1240  { .label   = "vCont",
1241    .command = remote_v_continue },
1242  { .label   = "vStopped",
1243    .command = remote_v_stopped },
1244  { .label   = "vKill",
1245    .command = remote_v_kill },
1246};
1247
1248#define REMOTE_V_PACKETS RTEMS_DEBUGGER_NUMOF(v_packets)
1249
1250static int
1251remote_v_packets(uint8_t* buffer, int size)
1252{
1253  return remote_packet_dispatch(v_packets, REMOTE_V_PACKETS,
1254                                buffer, size);
1255}
1256
1257static int
1258remote_thread_select(uint8_t* buffer, int size)
1259{
1260  const char const* response = r_OK;
1261  int*              index = NULL;
1262
1263  if (buffer[1] == 'g')
1264    index = &rtems_debugger->threads->selector_gen;
1265  else if (buffer[1] == 'c')
1266    index = &rtems_debugger->threads->selector_cont;
1267  else
1268    response = r_E01;
1269
1270  if (index != NULL) {
1271    DB_UINT pid = 0;
1272    DB_UINT tid = 0;
1273    bool    extended;
1274    extended = thread_id_decode((const char*) &buffer[2], &pid, &tid);
1275    if (extended && !check_pid(pid)) {
1276      response = r_E01;
1277    }
1278    else {
1279      if (tid == 0 || tid == (DB_UINT) -1)
1280        *index = (int) tid;
1281      else {
1282        int r;
1283        r = rtems_debugger_thread_find_index(tid);
1284        if (r < 0) {
1285          response = r_E01;
1286          *index = -1;
1287        }
1288        else
1289          *index = r;
1290      }
1291    }
1292  }
1293
1294  remote_packet_out_str(response);
1295  remote_packet_out_send();
1296  return 0;
1297}
1298
1299static int
1300remote_thread_alive(uint8_t* buffer, int size)
1301{
1302  const char const* response = r_E01;
1303  DB_UINT           pid = 0;
1304  DB_UINT           tid = 0;
1305  bool              extended;
1306  extended = thread_id_decode((const char*) &buffer[1], &pid, &tid);
1307  if (!extended || (extended && check_pid(pid))) {
1308    int r;
1309    r = rtems_debugger_thread_find_index(tid);
1310    if (r >= 0)
1311      response = r_OK;
1312  }
1313  remote_packet_out_str(response);
1314  remote_packet_out_send();
1315  return 0;
1316}
1317
1318static int
1319remote_argc_argv(uint8_t* buffer, int size)
1320{
1321  return -1;
1322}
1323
1324static int
1325remote_continue_at(uint8_t* buffer, int size)
1326{
1327  if (!rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VCONT)) {
1328    char* vCont_c = "vCont;c:p1.-1";
1329    return remote_v_continue((uint8_t*) vCont_c, strlen(vCont_c));
1330  }
1331  return -1;
1332}
1333
1334static int
1335remote_read_general_regs(uint8_t* buffer, int size)
1336{
1337  rtems_debugger_threads* threads = rtems_debugger->threads;
1338  bool                    ok = false;
1339  int                     r;
1340  if (threads->selector_gen >= 0 &&
1341      threads->selector_gen < (int) threads->current.level) {
1342    rtems_debugger_thread* current;
1343    rtems_debugger_thread* thread;
1344    current = rtems_debugger_thread_current(threads);
1345    thread = &current[threads->selector_gen];
1346    r = rtems_debugger_target_read_regs(thread);
1347    if (r >= 0) {
1348      remote_packet_out_reset();
1349      r = remote_packet_out_append_hex((const uint8_t*) &thread->registers[0],
1350                                       rtems_debugger_target_reg_size());
1351      if (r >= 0)
1352        ok = true;
1353    }
1354  }
1355  if (!ok)
1356    remote_packet_out_str(r_E01);
1357  remote_packet_out_send();
1358  return 0;
1359}
1360
1361static int
1362remote_write_general_regs(uint8_t* buffer, int size)
1363{
1364  rtems_debugger_threads* threads = rtems_debugger->threads;
1365  size_t                  reg_size = rtems_debugger_target_reg_size();
1366  bool                    ok = false;
1367  int                     r;
1368  if (threads->selector_gen >= 0 &&
1369      threads->selector_gen < (int) threads->current.level &&
1370      ((size - 1) / 2) == (int) reg_size) {
1371    rtems_debugger_thread* current;
1372    rtems_debugger_thread* thread;
1373    current = rtems_debugger_thread_current(threads);
1374    thread = &current[threads->selector_gen];
1375    r = rtems_debugger_target_read_regs(thread);
1376    if (r >= 0) {
1377      r = rtems_debugger_remote_packet_in_hex((uint8_t*) &thread->registers[0],
1378                                              (const char*) &buffer[1],
1379                                              reg_size);
1380      if (r >= 0) {
1381        thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
1382        ok = true;
1383      }
1384    }
1385  }
1386  if (!ok)
1387    remote_packet_out_str(r_E01);
1388  remote_packet_out_send();
1389  return 0;
1390}
1391
1392static int
1393remote_read_reg(uint8_t* buffer, int size)
1394{
1395  rtems_debugger_threads* threads = rtems_debugger->threads;
1396  bool                    ok = false;
1397  int                     r;
1398  if (threads->selector_gen >= 0
1399      && threads->selector_gen < (int) threads->current.level) {
1400    size_t reg = hex_decode_int(&buffer[1]);
1401    if (reg < rtems_debugger_target_reg_num()) {
1402      rtems_debugger_thread* current;
1403      rtems_debugger_thread* thread;
1404      current = rtems_debugger_thread_current(threads);
1405      thread = &current[threads->selector_gen];
1406      r = rtems_debugger_target_read_regs(thread);
1407      if (r >= 0) {
1408        const uint8_t* addr = (const uint8_t*) &thread->registers[reg];
1409        remote_packet_out_reset();
1410        r = remote_packet_out_append_hex(addr, sizeof(thread->registers[0]));
1411        if (r >= 0)
1412          ok = true;
1413      }
1414    }
1415  }
1416  if (!ok)
1417    remote_packet_out_str(r_E01);
1418  remote_packet_out_send();
1419  return 0;
1420}
1421
1422static int
1423remote_write_reg(uint8_t* buffer, int size)
1424{
1425  rtems_debugger_threads* threads = rtems_debugger->threads;
1426  const char const*       response = r_E01;
1427  if (threads->selector_gen >= 0
1428      && threads->selector_gen < (int) threads->current.level) {
1429    const char* equals;
1430    equals = strchr((const char*) buffer, '=');
1431    if (equals != NULL) {
1432      size_t reg = hex_decode_int(&buffer[1]);
1433      if (reg < rtems_debugger_target_reg_num()) {
1434        rtems_debugger_thread* current;
1435        rtems_debugger_thread* thread;
1436        int                    r;
1437        current = rtems_debugger_thread_current(threads);
1438        thread = &current[threads->selector_gen];
1439        r = rtems_debugger_target_read_regs(thread);
1440        if (r >= 0) {
1441          uint8_t* addr = (uint8_t*) &thread->registers[reg];
1442          r = rtems_debugger_remote_packet_in_hex(addr,
1443                                                  equals + 1,
1444                                                  sizeof(thread->registers[reg]));
1445          if (r == 0) {
1446            thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
1447            response = r_OK;
1448          }
1449        }
1450      }
1451    }
1452  }
1453  remote_packet_out_str(response);
1454  remote_packet_out_send();
1455  return 0;
1456}
1457
1458static int
1459remote_read_memory(uint8_t* buffer, int size)
1460{
1461  const char* comma;
1462  comma = strchr((const char*) buffer, ',');
1463  if (comma == NULL)
1464    remote_packet_out_str(r_E01);
1465  else {
1466    DB_UINT addr;
1467    DB_UINT length;
1468    int     r;
1469    addr = hex_decode_uint(&buffer[1]);
1470    length = hex_decode_uint((const uint8_t*) comma + 1);
1471    remote_packet_out_reset();
1472    r = rtems_debugger_target_start_memory_access();
1473    if (r == 0) {
1474      /*
1475       * There should be specific target access for 8, 16, 32 and 64 bit reads.
1476       */
1477      r = remote_packet_out_append_hex((const uint8_t*) addr, length);
1478    }
1479    rtems_debugger_target_end_memory_access();
1480    if (r < 0)
1481      remote_packet_out_str(r_E01);
1482  }
1483  remote_packet_out_send();
1484  return 0;
1485}
1486
1487static int
1488remote_write_memory(uint8_t* buffer, int size)
1489{
1490  const char const* response = r_E01;
1491  const char*       comma;
1492  const char*       colon;
1493  comma = strchr((const char*) buffer, ',');
1494  colon = strchr((const char*) buffer, ':');
1495  if (comma != NULL && colon != NULL) {
1496    DB_UINT addr;
1497    DB_UINT length;
1498    int     r;
1499    addr = hex_decode_uint(&buffer[1]);
1500    length = hex_decode_uint((const uint8_t*) comma + 1);
1501    r = rtems_debugger_target_start_memory_access();
1502    if (r == 0) {
1503      r = rtems_debugger_remote_packet_in_hex((uint8_t*) addr,
1504                                              colon + 1,
1505                                              length);
1506    }
1507    rtems_debugger_target_end_memory_access();
1508    if (r == 0)
1509      response = r_OK;
1510  }
1511  remote_packet_out_str(response);
1512  remote_packet_out_send();
1513  return 0;
1514}
1515
1516static int
1517remote_single_step(uint8_t* buffer, int size)
1518{
1519  if (!rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VCONT)) {
1520    rtems_debugger_threads* threads = rtems_debugger->threads;
1521    if (threads != NULL && rtems_debugger_thread_current(threads) != NULL) {
1522      rtems_debugger_thread* current;
1523      char                   vCont_s[32];
1524      current = rtems_debugger_thread_current(threads);
1525      snprintf(vCont_s, sizeof(vCont_s), "vCont;s:p1.%08lx;c:p1.-1",
1526               current[threads->selector_cont].id);
1527      return remote_v_continue((uint8_t*) vCont_s, strlen(vCont_s));
1528    }
1529    remote_packet_out_str(r_E01);
1530    remote_packet_out_send();
1531    return 0;
1532  }
1533  return -1;
1534}
1535
1536static int
1537remote_breakpoints(bool insert, uint8_t* buffer, int size)
1538{
1539  const char* comma1;
1540  int         r = -1;
1541  comma1 = strchr((const char*) buffer, ',');
1542  if (comma1 != NULL) {
1543    const char* comma2;
1544    comma2 = strchr(comma1 + 1, ',');
1545    if (comma2 != NULL) {
1546      uint32_t capabilities;
1547      DB_UINT  addr;
1548      DB_UINT  kind;
1549      addr = hex_decode_uint((const uint8_t*) comma1 + 1);
1550      kind = hex_decode_uint((const uint8_t*)comma2 + 1);
1551      capabilities = rtems_debugger_target_capabilities();
1552      switch (buffer[1]) {
1553      case '0':
1554        if ((capabilities & RTEMS_DEBUGGER_TARGET_CAP_SWBREAK) != 0) {
1555          r = rtems_debugger_target_swbreak_control(insert, addr, kind);
1556        }
1557        break;
1558      case '1': /* execute */
1559      case '2': /* write */
1560      case '3': /* read */
1561      case '4': /* access */
1562        if ((capabilities & RTEMS_DEBUGGER_TARGET_CAP_HWWATCH) != 0) {
1563          rtems_debugger_target_watchpoint type;
1564          switch (buffer[1]) {
1565          case '1':
1566            type = rtems_debugger_target_hw_execute;
1567            break;
1568          case '2':
1569            type = rtems_debugger_target_hw_write;
1570            break;
1571          case '3':
1572            type = rtems_debugger_target_hw_read;
1573            break;
1574          case '4':
1575          default:
1576            type = rtems_debugger_target_hw_read_write;
1577            break;
1578          }
1579          r = rtems_debugger_target_hwbreak_control(type, insert, addr, kind);
1580        }
1581        break;
1582      default:
1583        break;
1584      }
1585    }
1586  }
1587  remote_packet_out_str(r < 0 ?  r_E01 : r_OK);
1588  remote_packet_out_send();
1589  return 0;
1590}
1591
1592static int
1593remote_insert_breakpoint(uint8_t* buffer, int size)
1594{
1595  return remote_breakpoints(true, buffer, size);
1596}
1597
1598static int
1599remote_remove_breakpoint(uint8_t* buffer, int size)
1600{
1601  return remote_breakpoints(false, buffer, size);
1602}
1603
1604static int
1605remote_break(uint8_t* buffer, int size)
1606{
1607  int r;
1608  r = rtems_debugger_thread_system_suspend();
1609  if (r < 0) {
1610    rtems_debugger_printf("error: rtems-db: suspend all on break\n");
1611  }
1612  return remote_stop_reason(buffer, size);
1613}
1614
1615static const rtems_debugger_packet packets[] = {
1616  { .label   = "q",
1617    .command = remote_general_query },
1618  { .label   = "Q",
1619    .command = remote_general_set },
1620  { .label   = "v",
1621    .command = remote_v_packets },
1622  { .label   = "H",
1623    .command = remote_thread_select },
1624  { .label   = "T",
1625    .command = remote_thread_alive },
1626  { .label   = "?",
1627    .command = remote_stop_reason },
1628  { .label   = "A",
1629    .command = remote_argc_argv },
1630  { .label   = "c",
1631    .command = remote_continue_at },
1632  { .label   = "g",
1633    .command = remote_read_general_regs },
1634  { .label   = "G",
1635    .command = remote_write_general_regs },
1636  { .label   = "p",
1637    .command = remote_read_reg },
1638  { .label   = "P",
1639    .command = remote_write_reg },
1640  { .label   = "m",
1641    .command = remote_read_memory },
1642  { .label   = "M",
1643    .command = remote_write_memory },
1644  { .label   = "s",
1645    .command = remote_single_step },
1646  { .label   = "Z",
1647    .command = remote_insert_breakpoint },
1648  { .label   = "z",
1649    .command = remote_remove_breakpoint },
1650  { .label   = "D",
1651    .command = remote_detach },
1652  { .label   = "k",
1653    .command = remote_v_kill },
1654  { .label   = "r",
1655    .command = remote_v_kill },
1656  { .label   = "R",
1657    .command = remote_v_kill },
1658  { .label   = "^C",
1659    .command = remote_break },
1660};
1661
1662#define REMOTE_PACKETS RTEMS_DEBUGGER_NUMOF(packets)
1663
1664static int
1665remote_packets(uint8_t* buffer, size_t size)
1666{
1667  return remote_packet_dispatch(packets, REMOTE_PACKETS,
1668                                buffer, size);
1669}
1670
1671static void
1672rtems_debugger_events(rtems_task_argument arg)
1673{
1674  int r;
1675
1676  if (rtems_debugger_verbose())
1677    rtems_debugger_printf("rtems-db: events running\n");
1678
1679  /*
1680   * Hold the lock until the thread blocks waiting for an event.
1681   */
1682  rtems_debugger_lock();
1683
1684  rtems_debugger_target_enable();
1685
1686  while (rtems_debugger_server_events_running()) {
1687    r = rtems_debugger_server_events_wait();
1688    if (r < 0)
1689      break;
1690    if (!rtems_debugger_server_events_running())
1691      break;
1692    r = rtems_debugger_thread_system_suspend();
1693    if (r < 0)
1694      break;
1695    r = remote_stop_reason(NULL, 0);
1696    if (r < 0)
1697      break;
1698  }
1699
1700  if (r < 0)
1701    rtems_debugger_printf("rtems-db: error in events\n");
1702
1703  rtems_debugger_target_disable();
1704
1705  rtems_debugger->events_running = false;
1706  rtems_debugger->events_finished = true;
1707
1708  rtems_debugger_unlock();
1709
1710  if (rtems_debugger_verbose())
1711    rtems_debugger_printf("rtems-db: events finishing\n");
1712
1713  rtems_task_delete(RTEMS_SELF);
1714}
1715
1716static int
1717rtems_debugger_session(void)
1718{
1719  int r;
1720  int rr;
1721
1722  if (rtems_debugger_verbose())
1723    rtems_debugger_printf("rtems-db: remote running\n");
1724
1725  /*
1726   * Hold the lock until the thread blocks on the remote input.
1727   */
1728  rtems_debugger_lock();
1729
1730  r = rtems_debugger_target_create();
1731  if (r < 0) {
1732    rtems_debugger_thread_destroy();
1733    rtems_debugger_unlock();
1734    return r;
1735  }
1736
1737  r = rtems_debugger_thread_create();
1738  if (r < 0) {
1739    rtems_debugger_unlock();
1740    return r;
1741  }
1742
1743  rtems_debugger->events_running = true;
1744  rtems_debugger->events_finished = false;
1745
1746  r = rtems_debugger_task_create("DBSe",
1747                                 rtems_debugger->priority,
1748                                 RTEMS_DEBUGGER_STACKSIZE,
1749                                 rtems_debugger_events,
1750                                 0,
1751                                 &rtems_debugger->events_task);
1752  if (r < 0) {
1753    rtems_debugger_target_destroy();
1754    rtems_debugger_thread_destroy();
1755    rtems_debugger_unlock();
1756    return r;
1757  }
1758
1759  while (rtems_debugger_server_running() &&
1760         rtems_debugger_connected()) {
1761    r = rtems_debugger_remote_packet_in();
1762    if (r < 0)
1763      break;
1764    if (r > 0) {
1765      remote_packets(&rtems_debugger->input[0], r);
1766    }
1767  }
1768
1769  rtems_debugger->events_running = false;
1770  rtems_debugger_server_events_wake();
1771
1772  rtems_debugger_unlock();
1773
1774  rr = rtems_debugger_task_destroy("DBSe",
1775                                   rtems_debugger->events_task,
1776                                   &rtems_debugger->events_finished,
1777                                   RTEMS_DEBUGGER_TIMEOUT_STOP);
1778  if (rr < 0 && r == 0)
1779    r = rr;
1780
1781  rtems_debugger_lock();
1782
1783  rr = rtems_debugger_target_destroy();
1784  if (rr < 0 && r == 0)
1785    r = rr;
1786
1787  rr = rtems_debugger_thread_destroy();
1788  if (rr < 0 && r == 0)
1789    r = rr;
1790
1791  if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_RESET)) {
1792    rtems_debugger_printf("rtems-db: shutdown\n");
1793    rtems_fatal_error_occurred(1122);
1794  }
1795
1796  rtems_debugger->flags = 0;
1797  rtems_debugger->ack_pending = false;
1798
1799  rtems_debugger_unlock();
1800
1801  if (rtems_debugger_verbose())
1802    rtems_debugger_printf("rtems-db: remote finishing\n");
1803
1804  return r;
1805}
1806
1807static int
1808rtems_debugger_create(const char*          remote,
1809                      const char*          device,
1810                      rtems_task_priority  priority,
1811                      int                  timeout,
1812                      const rtems_printer* printer)
1813{
1814  int r;
1815
1816  if (rtems_debugger != NULL) {
1817    rtems_printf(printer, "error: rtems-db: create: already active\n");
1818    errno = EEXIST;
1819    return -1;
1820  }
1821
1822  rtems_debugger = malloc(sizeof(rtems_debugger_server));
1823  if (rtems_debugger == NULL) {
1824    rtems_printf(printer, "error: rtems-db: create: no memory\n");
1825    errno = ENOMEM;
1826    return -1;
1827  }
1828
1829  memset(rtems_debugger, 0, sizeof(rtems_debugger_server));
1830
1831  /*
1832   * These do not change with a session.
1833   */
1834  rtems_debugger->priority = priority;
1835  rtems_debugger->timeout = timeout;
1836  rtems_debugger->printer = *printer;
1837  rtems_debugger->pid = getpid();
1838  rtems_debugger->remote_debug = false;
1839
1840  rtems_debugger->remote = rtems_debugger_remote_find(remote);
1841  if (rtems_debugger->remote== NULL) {
1842    rtems_printf(printer, "error: rtems-db: remote not found: %s\n", remote);
1843    free(rtems_debugger);
1844    rtems_debugger = NULL;
1845    return -1;
1846  }
1847
1848  r = rtems_debugger->remote->begin(rtems_debugger->remote, device);
1849  if (r < 0) {
1850    rtems_printf(printer, "error: rtems-db: remote begin: %s: %s\n",
1851                 rtems_debugger->remote->name, strerror(errno));
1852    free(rtems_debugger);
1853    rtems_debugger = NULL;
1854  }
1855
1856  /*
1857   * Reset at the end of the session.
1858   */
1859  rtems_debugger->flags = 0;
1860  rtems_debugger->ack_pending = false;
1861
1862  r = rtems_debugger_lock_create();
1863  if (r < 0) {
1864    free(rtems_debugger);
1865    rtems_debugger = NULL;
1866    return -1;
1867  }
1868
1869  return 0;
1870}
1871
1872static int
1873rtems_debugger_destroy(void)
1874{
1875  int r;
1876  int rr;
1877
1878  rtems_debugger_lock();
1879  rtems_debugger->server_running = false;
1880  rtems_debugger_unlock();
1881
1882  r = rtems_debugger_remote_disconnect();
1883
1884  rr = rtems_debugger->remote->end(rtems_debugger->remote);
1885  if (rr < 0 && r == 0)
1886    r = rr;
1887
1888  rr = rtems_debugger_task_destroy("DBSs",
1889                                   rtems_debugger->server_task,
1890                                   &rtems_debugger->server_finished,
1891                                   RTEMS_DEBUGGER_TIMEOUT_STOP);
1892  if (rr < 0 && r == 0)
1893    r = rr;
1894
1895  rr = rtems_debugger_lock_destroy();
1896  if (rr < 0 && r == 0)
1897    r = rr;
1898
1899  free(rtems_debugger);
1900  rtems_debugger = NULL;
1901
1902  return r;
1903}
1904
1905static void
1906rtems_debugger_main(rtems_task_argument arg)
1907{
1908  int r;
1909
1910
1911  rtems_debugger_lock();
1912  rtems_debugger->server_running = true;
1913  rtems_debugger->server_finished = false;
1914  rtems_debugger_unlock();
1915
1916  rtems_debugger_printf("rtems-db: remote running\n");
1917
1918  while (rtems_debugger_server_running()) {
1919    r = rtems_debugger_remote_connect();
1920    if (r < 0)
1921      break;
1922    rtems_debugger_session();
1923    rtems_debugger_remote_disconnect();
1924  }
1925
1926  rtems_debugger_printf("rtems-db: remote finishing\n");
1927
1928  rtems_debugger_lock();
1929  rtems_debugger->server_running = false;
1930  rtems_debugger->server_finished = true;
1931  rtems_debugger_unlock();
1932
1933  rtems_task_delete(RTEMS_SELF);
1934}
1935
1936int
1937rtems_debugger_start(const char*          remote,
1938                     const char*          device,
1939                     int                  timeout,
1940                     rtems_task_priority  priority,
1941                     const rtems_printer* printer)
1942{
1943  int r;
1944
1945  r = rtems_debugger_create(remote, device, priority, timeout, printer);
1946  if (r < 0)
1947    return -1;
1948
1949  rtems_debugger_lock();
1950  rtems_debugger->server_running = false;
1951  rtems_debugger->server_finished = true;
1952  rtems_debugger_unlock();
1953
1954  r = rtems_debugger_task_create("DBSs",
1955                                 priority,
1956                                 RTEMS_DEBUGGER_STACKSIZE,
1957                                 rtems_debugger_main,
1958                                 0,
1959                                 &rtems_debugger->server_task);
1960  if (r < 0) {
1961    rtems_debugger_destroy();
1962    return -1;
1963  }
1964
1965  return 0;
1966}
1967
1968int
1969rtems_debugger_stop(void)
1970{
1971  return rtems_debugger_destroy();
1972}
1973
1974bool
1975rtems_debugger_running(void)
1976{
1977  return rtems_debugger != NULL;
1978}
1979
1980void
1981rtems_debugger_set_verbose(bool on)
1982{
1983  if (rtems_debugger_running()) {
1984    if (on)
1985      rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_VERBOSE;
1986    else
1987      rtems_debugger->flags &= ~RTEMS_DEBUGGER_FLAG_VERBOSE;
1988  }
1989}
1990
1991int
1992rtems_debugger_remote_debug(bool state)
1993{
1994  rtems_debugger_lock();
1995  rtems_debugger->remote_debug = state;
1996  rtems_debugger_printf("rtems-db: remote-debug is %s\n",
1997                        rtems_debugger->remote_debug ? "on" : "off");
1998  rtems_debugger_unlock();
1999  return 0;
2000}
Note: See TracBrowser for help on using the repository browser.