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

5
Last change on this file since b2353ed9 was b2353ed9, checked in by Chris Johns <chrisj@…>, on 07/16/17 at 23:53:11

libdebugger: Fixes to debugging, ARM support, locking, and gcc-7.1 warnings.

  • Add printk support to aid multi-core debugging.
  • Add lock trace to aid lock debugging.
  • Fixes to gcc-7.1 warnings.
  • Fixes from ticket #2879.
  • Add verbose command controls.
  • Change using the RTEMS sys/lock.h API to manage exception threads.
  • ARM hardware breakpoint fixes. Support for SMP stepping is not implemented, this requires use of the context id register.

Closes #2879.

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