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

Last change on this file was cb1e8497, checked in by Chris Johns <chrisj@…>, on Jun 25, 2019 at 11:07:40 AM

libdebugger: ARM fixes for Cortex-A8 and ARM mode.

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