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

5
Last change on this file since e629076 was a0d4e99, checked in by Chris Johns <chrisj@…>, on 11/25/16 at 04:13:36

cpukit: Add libdebugger, a remote debugger agent for GDB.

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