Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:15

0001 /*
0002  * Copyright (c) 2016-2019 Chris Johns <chrisj@rtems.org>.
0003  * All rights reserved.
0004  *
0005  * Redistribution and use in source and binary forms, with or without
0006  * modification, are permitted provided that the following conditions
0007  * are met:
0008  * 1. Redistributions of source code must retain the above copyright
0009  *    notice, this list of conditions and the following disclaimer.
0010  * 2. Redistributions in binary form must reproduce the above copyright
0011  *    notice, this list of conditions and the following disclaimer in the
0012  *    documentation and/or other materials provided with the distribution.
0013  *
0014  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
0015  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0016  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0017  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
0018  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0019  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0020  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0021  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0022  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0023  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0024  * SUCH DAMAGE.
0025  */
0026 
0027 #define RTEMS_DEBUGGER_VERBOSE_LOCK 0
0028 
0029 #include <errno.h>
0030 #include <inttypes.h>
0031 #include <stdlib.h>
0032 #include <unistd.h>
0033 
0034 #include <rtems/bspIo.h>
0035 #include <rtems/score/smp.h>
0036 
0037 #include <rtems/rtems-debugger.h>
0038 #include <rtems/debugger/rtems-debugger-server.h>
0039 #include <rtems/debugger/rtems-debugger-remote.h>
0040 
0041 #include "rtems-debugger-target.h"
0042 #include "rtems-debugger-threads.h"
0043 
0044 /*
0045  * GDB Debugger Remote Server for RTEMS.
0046  */
0047 
0048 /*
0049  * Command lookup table.
0050  */
0051 typedef int (*rtems_debugger_command)(uint8_t* buffer, int size);
0052 
0053 typedef struct rtems_debugger_packet
0054 {
0055   const char* const      label;
0056   rtems_debugger_command command;
0057 } rtems_debugger_packet;
0058 
0059 /**
0060  * Common error strings.
0061  */
0062 static const char* const r_OK = "OK";
0063 static const char* const r_E01 = "E01";
0064 
0065 /*
0066  * Global Debugger.
0067  *
0068  * The server instance is allocated on the heap so memory is only used then the
0069  * server is running. A global is used because:
0070  *
0071  *  1. There can only be a single instance at once.
0072  *  2. The backend's need access to the data and holding pointers in the TCB
0073  *     for each thread is mess.
0074  *  3. The code is smaller and faster.
0075  */
0076 rtems_debugger_server* rtems_debugger;
0077 
0078 /**
0079  * Print lock ot make the prints sequential. This is to debug the debugger in
0080  * SMP.
0081  */
0082 RTEMS_INTERRUPT_LOCK_DEFINE(static, printk_lock, "printk_lock")
0083 
0084 void
0085 rtems_debugger_printk_lock(rtems_interrupt_lock_context* lock_context)
0086 {
0087   rtems_interrupt_lock_acquire(&printk_lock, lock_context);
0088 }
0089 
0090 void
0091 rtems_debugger_printk_unlock(rtems_interrupt_lock_context* lock_context)
0092 {
0093   rtems_interrupt_lock_release(&printk_lock, lock_context);
0094 }
0095 
0096 int
0097 rtems_debugger_clean_printf(const char* format, ...)
0098 {
0099   rtems_interrupt_lock_context lock_context;
0100   int                          len;
0101   va_list                      ap;
0102   va_start(ap, format);
0103   rtems_debugger_printk_lock(&lock_context);
0104   len = vprintk(format, ap);
0105   rtems_debugger_printk_unlock(&lock_context);
0106   va_end(ap);
0107   return len;
0108 }
0109 
0110 int
0111 rtems_debugger_printf(const char* format, ...)
0112 {
0113   rtems_interrupt_lock_context lock_context;
0114   int                          len;
0115   va_list                      ap;
0116   va_start(ap, format);
0117   rtems_debugger_printk_lock(&lock_context);
0118   printk("[CPU:%d] ", (int) _SMP_Get_current_processor ());
0119   len = vprintk(format, ap);
0120   rtems_debugger_printk_unlock(&lock_context);
0121   va_end(ap);
0122   return len;
0123 }
0124 
0125 bool
0126 rtems_debugger_verbose(void)
0127 {
0128   return rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VERBOSE);
0129 }
0130 
0131 static inline int
0132 hex_decode(uint8_t ch)
0133 {
0134   int i;
0135   if (ch >= '0' && ch <= '9')
0136     i = (int) (ch - '0');
0137   else if (ch >= 'a' && ch <= 'f')
0138     i = (int) (ch - 'a') + 10;
0139   else if (ch >= 'A' && ch <= 'F')
0140     i = (int) (ch - 'A') + 10;
0141   else
0142     i = -1;
0143   return i;
0144 }
0145 
0146 static inline uint8_t
0147 hex_encode(int val)
0148 {
0149   return "0123456789abcdef"[val & 0xf];
0150 }
0151 
0152 static inline uintptr_t
0153 hex_decode_addr(const uint8_t* data)
0154 {
0155   uintptr_t ui = 0;
0156   size_t  i;
0157   if (data[0] == '-') {
0158     if (data[1] == '1')
0159       ui = (uintptr_t) -1;
0160   }
0161   else {
0162     for (i = 0; i < (sizeof(ui) * 2); ++i) {
0163       int v = hex_decode(data[i]);
0164       if (v < 0)
0165         break;
0166       ui = (ui << 4) | v;
0167     }
0168   }
0169   return ui;
0170 }
0171 
0172 static inline DB_UINT
0173 hex_decode_uint(const uint8_t* data)
0174 {
0175   DB_UINT ui = 0;
0176   size_t  i;
0177   if (data[0] == '-') {
0178     if (data[1] == '1')
0179       ui = (DB_UINT) -1;
0180   }
0181   else {
0182     for (i = 0; i < (sizeof(ui) * 2); ++i) {
0183       int v = hex_decode(data[i]);
0184       if (v < 0)
0185         break;
0186       ui = (ui << 4) | v;
0187     }
0188   }
0189   return ui;
0190 }
0191 
0192 static inline int
0193 hex_decode_int(const uint8_t* data)
0194 {
0195   return (int) hex_decode_uint(data);
0196 }
0197 
0198 static bool
0199 thread_id_decode(const char* data, DB_UINT* pid, DB_UINT* tid)
0200 {
0201   bool is_extended = false;
0202   if (*data == 'p') {
0203     is_extended = true;
0204     ++data;
0205   }
0206   *pid = *tid = hex_decode_uint((const uint8_t*) data);
0207   if (is_extended) {
0208     const char* stop = strchr(data, '.');
0209     if (stop != NULL) {
0210       *tid = hex_decode_uint((const uint8_t*) stop + 1);
0211     }
0212   }
0213   return is_extended;
0214 }
0215 
0216 static inline bool
0217 check_pid(DB_UINT pid)
0218 {
0219   return pid == 0 || rtems_debugger->pid == (pid_t) pid;
0220 }
0221 
0222 void
0223 rtems_debugger_lock(void)
0224 {
0225   _Mutex_recursive_Acquire(&rtems_debugger->lock);
0226 }
0227 
0228 void
0229 rtems_debugger_unlock(void)
0230 {
0231   _Mutex_recursive_Release(&rtems_debugger->lock);
0232 }
0233 
0234 static int
0235 rtems_debugger_lock_create(void)
0236 {
0237   _Mutex_recursive_Initialize_named(&rtems_debugger->lock, "DBlock");
0238   return 0;
0239 }
0240 
0241 static int
0242 rtems_debugger_lock_destroy(void)
0243 {
0244   return 0;
0245 }
0246 
0247 static int
0248 rtems_debugger_task_create(const char*         name,
0249                            rtems_task_priority priority,
0250                            size_t              stack_size,
0251                            rtems_task_entry    entry_point,
0252                            rtems_task_argument argument,
0253                            rtems_id*           id)
0254 {
0255   rtems_name        tname;
0256   rtems_status_code sc;
0257 
0258   tname = rtems_build_name(name[0], name[1], name[2], name[3]);
0259 
0260   sc = rtems_task_create (tname,
0261                           priority,
0262                           stack_size,
0263                           RTEMS_PREEMPT | RTEMS_NO_ASR,
0264                           RTEMS_LOCAL | RTEMS_FLOATING_POINT,
0265                           id);
0266   if (sc != RTEMS_SUCCESSFUL) {
0267     *id = 0;
0268     rtems_debugger_printf("error: rtems-db: thread create: %s: %s\n",
0269                           name, rtems_status_text(sc));
0270     errno = EIO;
0271     return -1;
0272   }
0273 
0274   sc = rtems_task_start(*id, entry_point, argument);
0275   if (sc != RTEMS_SUCCESSFUL) {
0276     rtems_debugger_printf("error: rtems-db: thread start: %s: %s\n",
0277                           name, rtems_status_text(sc));
0278     rtems_task_delete(*id);
0279     *id = 0;
0280     errno = EIO;
0281     return -1;
0282   }
0283 
0284   return 0;
0285 }
0286 
0287 static int
0288 rtems_debugger_task_destroy(const char*    name,
0289                             rtems_id       id,
0290                             volatile bool* finished,
0291                             int            timeout)
0292 {
0293   while (timeout) {
0294     bool has_finished;
0295 
0296     rtems_debugger_lock();
0297     has_finished = *finished;
0298     rtems_debugger_unlock();
0299 
0300     if (has_finished)
0301       break;
0302 
0303     usleep(RTEMS_DEBUGGER_POLL_WAIT);
0304     if (timeout < RTEMS_DEBUGGER_POLL_WAIT)
0305       timeout = 0;
0306     else
0307       timeout -= RTEMS_DEBUGGER_POLL_WAIT;
0308   }
0309 
0310   if (timeout == 0) {
0311     rtems_debugger_printf("rtems-db: %s not stopping, killing\n", name);
0312     rtems_task_delete(id);
0313   }
0314   return 0;
0315 }
0316 
0317 bool
0318 rtems_debugger_server_running(void)
0319 {
0320   bool running;
0321   rtems_debugger_lock();
0322   running = rtems_debugger->server_running;
0323   rtems_debugger_unlock();
0324   return running;
0325 }
0326 
0327 rtems_debugger_remote*
0328 rtems_debugger_remote_handle(void)
0329 {
0330   rtems_debugger_remote* remote;
0331   rtems_debugger_lock();
0332   remote = rtems_debugger->remote;
0333   rtems_debugger_unlock();
0334   return remote;
0335 }
0336 
0337 bool
0338 rtems_debugger_connected(void)
0339 {
0340   bool isconnected = false;
0341   rtems_debugger_lock();
0342   if (rtems_debugger->remote != NULL)
0343     isconnected = rtems_debugger->remote->isconnected(rtems_debugger->remote);
0344   rtems_debugger_unlock();
0345   return isconnected;
0346 }
0347 
0348 bool
0349 rtems_debugger_server_events_running(void)
0350 {
0351   return rtems_debugger->events_running;
0352 }
0353 
0354 void
0355 rtems_debugger_server_events_signal(void)
0356 {
0357   _Condition_Signal(&rtems_debugger->server_cond);
0358 }
0359 
0360 static void
0361 rtems_debugger_server_events_wait(void)
0362 {
0363   _Condition_Wait_recursive(&rtems_debugger->server_cond, &rtems_debugger->lock);
0364 }
0365 
0366 static int
0367 rtems_debugger_remote_connect(void)
0368 {
0369   rtems_debugger_remote* remote = rtems_debugger_remote_handle();
0370   if (remote != NULL) {
0371     if (!remote->isconnected(remote))
0372       return remote->connect(remote);
0373   }
0374   errno = EIO;
0375   return -1;
0376 }
0377 
0378 static int
0379 rtems_debugger_remote_disconnect(void)
0380 {
0381   rtems_debugger_remote* remote = rtems_debugger_remote_handle();
0382   if (remote != NULL) {
0383     if (remote->isconnected(remote))
0384       return remote->disconnect(remote);
0385   }
0386   errno = EIO;
0387   return -1;
0388 }
0389 
0390 static int
0391 rtems_debugger_remote_receive(uint8_t* buffer, size_t size)
0392 {
0393   rtems_debugger_remote* remote = rtems_debugger_remote_handle();
0394   ssize_t len = remote->read(remote, buffer, size);
0395   if (len < 0 && errno != EAGAIN)
0396     rtems_debugger_printf("rtems-db: read: (%d) %s\n",
0397                           errno, strerror(errno));
0398   return (int) len;
0399 }
0400 
0401 static int
0402 rtems_debugger_remote_send(void)
0403 {
0404   const uint8_t* buffer = rtems_debugger->output;
0405   ssize_t        size = rtems_debugger->output_level;
0406 
0407   if (rtems_debugger->output_level > RTEMS_DEBUGGER_BUFFER_SIZE) {
0408     rtems_debugger_printf("rtems-db: write too big: %d\n",
0409                           (int) rtems_debugger->output_level);
0410     return -1;
0411   }
0412 
0413   if (rtems_debugger->remote_debug) {
0414     size_t i = 0;
0415     rtems_debugger_printf("rtems-db: put:%4zu: ", rtems_debugger->output_level);
0416     while (i < rtems_debugger->output_level)
0417       rtems_debugger_clean_printf("%c", (char) rtems_debugger->output[i++]);
0418     rtems_debugger_clean_printf("\n");
0419   }
0420 
0421   while (size) {
0422     rtems_debugger_remote* remote = rtems_debugger_remote_handle();
0423     ssize_t                w;
0424     if (remote == NULL) {
0425       errno = EIO;
0426       return -1;
0427     }
0428     w = remote->write(remote, buffer, size);
0429     if (w < 0 && errno != EINTR) {
0430       rtems_debugger_printf("rtems-db: write: (%d) %s\n",
0431                             errno, strerror(errno));
0432       break;
0433     }
0434     else {
0435       size -= w;
0436       buffer += w;
0437     }
0438   }
0439 
0440   return (int) rtems_debugger->output_level;
0441 }
0442 
0443 static int
0444 rtems_debugger_remote_send_ack(void)
0445 {
0446   rtems_debugger->output[0] = '+';
0447   rtems_debugger->output_level = 1;
0448   return rtems_debugger_remote_send();
0449 }
0450 
0451 static int
0452 rtems_debugger_remote_send_nack(void)
0453 {
0454   rtems_debugger->output[0] = '-';
0455   rtems_debugger->output_level = 1;
0456   return rtems_debugger_remote_send();
0457 }
0458 
0459 static int
0460 rtems_debugger_remote_packet_in(void)
0461 {
0462   uint8_t buf[256];
0463   uint8_t state;
0464   int     in = 0;
0465   uint8_t csum = 0;
0466   uint8_t rx_csum = 0;
0467   bool    junk = false;
0468   bool    escaped = false;
0469   bool    remote_debug_header = true;
0470 
0471   /*
0472    * States:
0473    *  'H' : Looking for the start character '$', '-' or '+'.
0474    *  'P' : Looking for the checksum character '#' else buffer data.
0475    *  '1' : Looking for the first checksum character.
0476    *  '2' : Looking for the second checksum character.
0477    *  'F' : Finished.
0478    */
0479 
0480   state = 'H';
0481 
0482   while (state != 'F') {
0483     int r;
0484     int i;
0485 
0486     rtems_debugger_unlock();
0487 
0488     r = rtems_debugger_remote_receive(buf, sizeof(buf));
0489 
0490     rtems_debugger_lock();
0491 
0492     if (r <= 0) {
0493       /*
0494        * Timeout?
0495        */
0496       if (r < 0 && errno == EAGAIN) {
0497         if (rtems_debugger->ack_pending) {
0498           rtems_debugger_remote_send();
0499         }
0500         continue;
0501       }
0502       if (r == 0)
0503         rtems_debugger_printf("rtems-db: remote disconnected\n");
0504       return -1;
0505     }
0506 
0507     i = 0;
0508 
0509     while (i < r) {
0510       uint8_t c = buf[i++];
0511 
0512       if (rtems_debugger->remote_debug && remote_debug_header) {
0513         rtems_debugger_printf("rtems-db: get:%4d: ", r);
0514         remote_debug_header = false;
0515       }
0516 
0517       if (rtems_debugger->remote_debug)
0518         rtems_debugger_clean_printf("%c", c);
0519 
0520       switch (state) {
0521       case 'H':
0522         switch (c) {
0523         case '+':
0524           if (rtems_debugger->remote_debug) {
0525             rtems_debugger_clean_printf(" [[ACK%s]]\n",
0526                                   rtems_debugger->ack_pending ? "" : "?");
0527             remote_debug_header = true;
0528           }
0529           rtems_debugger->ack_pending = false;
0530           break;
0531         case '-':
0532           if (rtems_debugger->remote_debug) {
0533             rtems_debugger_clean_printf(" [[NACK]]\n");
0534             remote_debug_header = true;
0535           }
0536           /*
0537            * Resend.
0538            */
0539           rtems_debugger_remote_send();
0540           break;
0541         case '$':
0542           state = 'P';
0543           csum = 0;
0544           in = 0;
0545           if (junk && rtems_debugger->remote_debug) {
0546             rtems_debugger_clean_printf("\b [[junk dropped]]\nrtems-db: get:   : $");
0547             remote_debug_header = false;
0548           }
0549           break;
0550         case '\x3':
0551           if (rtems_debugger->remote_debug)
0552             rtems_debugger_clean_printf("^C [[BREAK]]\n");
0553           rtems_debugger->ack_pending = false;
0554           rtems_debugger->input[0] =  '^';
0555           rtems_debugger->input[1] =  'C';
0556           rtems_debugger->input[2] =  '\0';
0557           return 2;
0558         default:
0559           junk = true;
0560           break;
0561         }
0562         break;
0563       case 'P':
0564         if (c == '{' && !escaped) {
0565           escaped = true;
0566         }
0567         else if (c == '$' && !escaped) {
0568           csum = 0;
0569           in = 0;
0570           if (rtems_debugger->remote_debug) {
0571             rtems_debugger_clean_printf("\n");
0572             remote_debug_header = true;
0573           }
0574         }
0575         else if (c == '#' && !escaped) {
0576           rtems_debugger->input[in] = '\0';
0577           rx_csum = 0;
0578           state = '1';
0579         }
0580         else {
0581           if (in >= (RTEMS_DEBUGGER_BUFFER_SIZE - 1)) {
0582             rtems_debugger_printf("rtems-db: input buffer overflow\n");
0583             return -1;
0584           }
0585           csum += c;
0586           rtems_debugger->input[in++] = c;
0587         }
0588         break;
0589       case '1':
0590         rx_csum = (rx_csum << 4) | (uint8_t) hex_decode(c);
0591         state = '2';
0592         break;
0593       case '2':
0594         rx_csum = (rx_csum << 4) | (uint8_t) hex_decode(c);
0595         if (csum == rx_csum) {
0596           state = 'F';
0597           if (rtems_debugger->remote_debug)
0598             rtems_debugger_clean_printf("\n");
0599           rtems_debugger_remote_send_ack();
0600         }
0601         else {
0602           if (rtems_debugger->remote_debug) {
0603             rtems_debugger_clean_printf(" [[invalid checksum]]\n");
0604             remote_debug_header = true;
0605             rtems_debugger_remote_send_nack();
0606           }
0607           state = 'H';
0608         }
0609         break;
0610       case 'F':
0611           if (rtems_debugger->remote_debug)
0612             rtems_debugger_clean_printf(" [[extra data: 0x%02x]]", (int) c);
0613         break;
0614       default:
0615         rtems_debugger_printf("rtems-db: bad state\n");
0616         rtems_debugger_remote_send_nack();
0617         return -1;
0618       }
0619     }
0620   }
0621 
0622   return in;
0623 }
0624 
0625 static int
0626 rtems_debugger_remote_packet_in_hex(uint8_t*    addr,
0627                                     const char* data,
0628                                     size_t      size)
0629 {
0630   size_t i;
0631   for (i = 0; i < size; ++i) {
0632     *addr = (hex_decode(*data++) << 4);
0633     *addr++ |= hex_decode(*data++);
0634   }
0635   return 0;
0636 }
0637 
0638 #if KEEP_INCASE
0639 static void
0640 remote_packet_out_rewind(size_t size)
0641 {
0642   size_t i = 0;
0643   while (rtems_debugger->output_level > 0 && i < size) {
0644     if (rtems_debugger->output_level > 1) {
0645       if (rtems_debugger->output[rtems_debugger->output_level - 1] == '}') {
0646         --rtems_debugger->output_level;
0647       }
0648     }
0649     --rtems_debugger->output_level;
0650     --i;
0651   }
0652 }
0653 #endif
0654 
0655 static int
0656 remote_packet_out_append_buffer(const char* buffer, size_t size)
0657 {
0658   size_t ol = rtems_debugger->output_level;
0659   size_t i = 0;
0660   while (i < size) {
0661     char c = buffer[i++];
0662     if (c == '#' || c == '$') {
0663       if (rtems_debugger->output_level >= (RTEMS_DEBUGGER_BUFFER_SIZE - 1)) {
0664         rtems_debugger->output_level = ol;
0665         rtems_debugger_printf("rtems-db: output overflow\n");
0666         return -1;
0667       }
0668       rtems_debugger->output[rtems_debugger->output_level++] = '}';
0669       c ^= 0x20;
0670     }
0671     if (rtems_debugger->output_level >= (RTEMS_DEBUGGER_BUFFER_SIZE - 1)) {
0672       rtems_debugger->output_level = ol;
0673       rtems_debugger_printf("rtems-db: output overflow\n");
0674       return -1;
0675     }
0676     rtems_debugger->output[rtems_debugger->output_level++] = c;
0677   }
0678   return 0;
0679 }
0680 
0681 static int
0682 remote_packet_out_append_hex(const uint8_t* data, size_t size)
0683 {
0684   size_t ol = rtems_debugger->output_level;
0685   size_t i = 0;
0686   while (i < size) {
0687     uint8_t byte = data[i++];
0688     if (rtems_debugger->output_level >= (RTEMS_DEBUGGER_BUFFER_SIZE - 2)) {
0689       rtems_debugger->output_level = ol;
0690       rtems_debugger_printf("rtems-db: output overflow\n");
0691       return -1;
0692     }
0693     rtems_debugger->output[rtems_debugger->output_level++] = hex_encode(byte >> 4);
0694     rtems_debugger->output[rtems_debugger->output_level++] = hex_encode(byte);
0695   }
0696   return 0;
0697 }
0698 
0699 static int
0700 remote_packet_out_append_str(const char* str)
0701 {
0702   return remote_packet_out_append_buffer(str, strlen(str));
0703 }
0704 
0705 static int
0706 remote_packet_out_append_vprintf(const char* fmt, va_list ap)
0707 {
0708   int  len;
0709   char buffer[64];
0710   len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
0711   return remote_packet_out_append_buffer(buffer, len);
0712 }
0713 
0714 static int
0715 remote_packet_out_append(const char* fmt, ...)
0716 {
0717   va_list ap;
0718   int     r;
0719   va_start(ap, fmt);
0720   r = remote_packet_out_append_vprintf(fmt, ap);
0721   va_end(ap);
0722   return r;
0723 }
0724 
0725 static void
0726 remote_packet_out_reset(void)
0727 {
0728   rtems_debugger->output_level = 1;
0729   rtems_debugger->output[0] = '$';
0730 }
0731 
0732 static int
0733 remote_packet_out_buffer(const char* buffer, size_t size)
0734 {
0735   remote_packet_out_reset();
0736   return remote_packet_out_append_buffer(buffer, size);
0737 }
0738 
0739 static int
0740 remote_packet_out_str(const char* str)
0741 {
0742   remote_packet_out_reset();
0743   return remote_packet_out_append_buffer(str, strlen(str));
0744 }
0745 
0746 static int
0747 remote_packet_out(const char* fmt, ...)
0748 {
0749   va_list ap;
0750   int     r;
0751   va_start(ap, fmt);
0752   remote_packet_out_reset();
0753   r = remote_packet_out_append_vprintf(fmt, ap);
0754   va_end(ap);
0755   return r;
0756 }
0757 
0758 static int
0759 remote_packet_out_send(void)
0760 {
0761   uint8_t csum = 0;
0762   size_t  i = 1;
0763 
0764   if (rtems_debugger->output_level >= (RTEMS_DEBUGGER_BUFFER_SIZE - 3)) {
0765     rtems_debugger_printf("rtems-db: output overflow\n");
0766     return -1;
0767   }
0768 
0769   while (i < rtems_debugger->output_level) {
0770     csum += rtems_debugger->output[i++];
0771   }
0772 
0773   rtems_debugger->output[rtems_debugger->output_level++] = '#';
0774   rtems_debugger->output[rtems_debugger->output_level++] = hex_encode((csum >> 4) & 0xf);
0775   rtems_debugger->output[rtems_debugger->output_level++] = hex_encode(csum & 0xf);
0776 
0777   rtems_debugger->ack_pending = true;;
0778 
0779   return rtems_debugger_remote_send();
0780 }
0781 
0782 static int
0783 remote_packet_dispatch(const rtems_debugger_packet* packet,
0784                        size_t                       packets,
0785                        uint8_t*                     buffer,
0786                        int                          size)
0787 {
0788   const rtems_debugger_packet* p;
0789   size_t                       i;
0790   int                          r = -1;
0791   for (i = 0, p = &packet[0]; i < packets; ++i, ++p) {
0792     if (strncmp(p->label,
0793                 (const char*) &buffer[0],
0794                 strlen(p->label)) == 0) {
0795       if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VERBOSE_CMDS))
0796         rtems_debugger_printf("rtems-db: cmd: %s [%d] '%s'\n",
0797                               p->label, size, (const char*) buffer);
0798       r = p->command(buffer, size);
0799       break;
0800     }
0801   }
0802   if (r < 0) {
0803     remote_packet_out_buffer("", 0);
0804     remote_packet_out_send();
0805   }
0806   return 0;
0807 }
0808 
0809 static int
0810 remote_detach(uint8_t* buffer, int size)
0811 {
0812   remote_packet_out_str(r_OK);
0813   remote_packet_out_send();
0814   rtems_debugger_remote_disconnect();
0815   return 0;
0816 }
0817 
0818 static int
0819 remote_ut_features(uint8_t* buffer, int size)
0820 {
0821   return -1;
0822 }
0823 
0824 static int
0825 remote_ut_osdata(uint8_t* buffer, int size)
0826 {
0827   return -1;
0828 }
0829 
0830 static const rtems_debugger_packet uninterpreted_transfer[] = {
0831   { .label   = "qXfer:features",
0832     .command = remote_ut_features },
0833   { .label   = "qXfer:osdata",
0834     .command = remote_ut_osdata },
0835 };
0836 
0837 #define REMOTE_UNINTERPRETED_TRANSFERS \
0838   RTEMS_DEBUGGER_NUMOF(uninterpreted_transfer)
0839 
0840 static int
0841 remote_gq_uninterpreted_transfer(uint8_t* buffer, int size)
0842 {
0843   return remote_packet_dispatch(uninterpreted_transfer,
0844                                 REMOTE_UNINTERPRETED_TRANSFERS,
0845                                 buffer, size);
0846 }
0847 
0848 static int
0849 remote_gq_thread_info_subsequent(uint8_t* buffer, int size)
0850 {
0851   rtems_debugger_threads* threads = rtems_debugger->threads;
0852   if (threads->next >= threads->current.level)
0853     remote_packet_out_str("l");
0854   else {
0855     rtems_debugger_thread* current;
0856     const char*            format = "p%d.%08lx";
0857     current = rtems_debugger_thread_current(threads);
0858     remote_packet_out_str("m");
0859     while (threads->next < threads->current.level) {
0860       int r;
0861       r = remote_packet_out_append(format,
0862                                    rtems_debugger->pid,
0863                                    current[threads->next].id);
0864       if (r < 0)
0865         break;
0866       format = ",p%d.%08lx";
0867       ++threads->next;
0868     }
0869   }
0870   remote_packet_out_send();
0871   return 0;
0872 }
0873 
0874 static int
0875 remote_gq_thread_info_first(uint8_t* buffer, int size)
0876 {
0877   rtems_debugger->threads->next = 0;
0878   return remote_gq_thread_info_subsequent(buffer, size);
0879 }
0880 
0881 static int
0882 remote_gq_thread_extra_info(uint8_t* buffer, int size)
0883 {
0884   const char* comma;
0885   remote_packet_out_reset();
0886   comma = strchr((const char*) buffer, ',');
0887   if (comma != NULL) {
0888     DB_UINT pid = 0;
0889     DB_UINT tid = 0;
0890     bool    extended;
0891     extended = thread_id_decode(comma + 1, &pid, &tid);
0892     if (extended || check_pid(pid)) {
0893       int r;
0894       r = rtems_debugger_thread_find_index(tid);
0895       if (r >= 0) {
0896         rtems_debugger_threads* threads = rtems_debugger->threads;
0897         rtems_debugger_thread*  current;
0898         rtems_debugger_thread*  thread;
0899         char                    buf[128];
0900         char                    str[32];
0901         size_t                  l;
0902         current = rtems_debugger_thread_current(threads);
0903         thread = &current[r];
0904         l = snprintf(buf, sizeof(buf),
0905                      "%4s (%08" PRIx32 "), ", thread->name, thread->id);
0906         remote_packet_out_append_hex((const uint8_t*) buf, l);
0907         l = snprintf(buf, sizeof(buf),
0908                      "priority(c:%3d r:%3d), ",
0909                      rtems_debugger_thread_current_priority(thread),
0910                      rtems_debugger_thread_real_priority(thread));
0911         remote_packet_out_append_hex((const uint8_t*) buf, l);
0912         l = snprintf(buf, sizeof(buf),
0913                      "stack(s:%6lu a:%p), ",
0914                      rtems_debugger_thread_stack_size(thread),
0915                      rtems_debugger_thread_stack_area(thread));
0916         remote_packet_out_append_hex((const uint8_t*) buf, l);
0917         rtems_debugger_thread_state_str(thread, str, sizeof(str));
0918         l = snprintf(buf, sizeof(buf), "state(%s)", str);
0919         remote_packet_out_append_hex((const uint8_t*) buf, l);
0920       }
0921     }
0922   }
0923   remote_packet_out_send();
0924   return 0;
0925 }
0926 
0927 static int
0928 remote_gq_supported(uint8_t* buffer, int size)
0929 {
0930   uint32_t    capabilities = rtems_debugger_target_capabilities();
0931   const char* p;
0932   bool        swbreak = false;
0933   bool        hwbreak = false;
0934   bool        vCont = false;
0935   bool        no_resumed = false;
0936   bool        multiprocess = false;
0937   remote_packet_out("qSupported:PacketSize=%d;QNonStop-",
0938                     RTEMS_DEBUGGER_BUFFER_SIZE);
0939   p = strchr((const char*) buffer, ':');
0940   if (p != NULL)
0941     ++p;
0942   while (p != NULL && *p != '\0') {
0943     bool  echo = false;
0944     char* sc;
0945     sc = strchr(p, ';');
0946     if (sc != NULL) {
0947       *sc++ = '\0';
0948     }
0949     if (strcmp(p, "swbreak+") == 0 &&
0950         !swbreak && (capabilities & RTEMS_DEBUGGER_TARGET_CAP_SWBREAK) != 0) {
0951       swbreak = true;
0952       echo = true;
0953     }
0954     if (strcmp(p, "hwbreak+") == 0 &&
0955         !hwbreak && (capabilities & RTEMS_DEBUGGER_TARGET_CAP_HWBREAK) != 0) {
0956       hwbreak = true;
0957       echo = true;
0958     }
0959     if (!vCont && strcmp(p, "vContSupported+") == 0) {
0960       rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_VCONT;
0961       vCont = true;
0962       echo = true;
0963     }
0964     if (!no_resumed && strcmp(p, "no-resumed+") == 0) {
0965       no_resumed = true;
0966       echo = true;
0967     }
0968     if (!multiprocess && strcmp(p, "multiprocess+") == 0) {
0969       rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_MULTIPROCESS;
0970       multiprocess = true;
0971       echo = true;
0972     }
0973 
0974     if (echo) {
0975       remote_packet_out_append_str(";");
0976       remote_packet_out_append_str(p);
0977     }
0978     else if (strncmp(p, "xmlRegisters", sizeof("xmlRegisters") - 1) == 0) {
0979       /* ignore */
0980     }
0981     else {
0982       remote_packet_out_append_str(";");
0983       remote_packet_out_append_buffer(p, strlen(p) - 1);
0984       remote_packet_out_append_str("-");
0985     }
0986     p = sc;
0987   }
0988   if (!swbreak && (capabilities & RTEMS_DEBUGGER_TARGET_CAP_SWBREAK) != 0) {
0989     remote_packet_out_append_str("swbreak+;");
0990   }
0991   if (!hwbreak && (capabilities & RTEMS_DEBUGGER_TARGET_CAP_HWBREAK) != 0) {
0992     remote_packet_out_append_str("hwbreak+;");
0993   }
0994   if (!vCont) {
0995     remote_packet_out_append_str("vContSupported+;");
0996   }
0997   if (!no_resumed) {
0998     remote_packet_out_append_str("no-resumed+;");
0999   }
1000   if (!multiprocess) {
1001     remote_packet_out_append_str("multiprocess+;");
1002   }
1003   remote_packet_out_send();
1004   return 0;
1005 }
1006 
1007 static int
1008 remote_gq_attached(uint8_t* buffer, int size)
1009 {
1010   const char* response = "1";
1011   const char* colon = strchr((const char*) buffer, ':');
1012   if (colon != NULL) {
1013     DB_UINT pid = hex_decode_uint((const uint8_t*) colon + 1);
1014     if ((pid_t) pid != rtems_debugger->pid)
1015       response = r_E01;
1016   }
1017   remote_packet_out_str(response);
1018   remote_packet_out_send();
1019   return 0;
1020 }
1021 
1022 static const rtems_debugger_packet general_query[] = {
1023   { .label   = "qfThreadInfo",
1024     .command = remote_gq_thread_info_first },
1025   { .label   = "qsThreadInfo",
1026     .command = remote_gq_thread_info_subsequent },
1027   { .label   = "qThreadExtraInfo",
1028     .command = remote_gq_thread_extra_info },
1029   { .label   = "qSupported",
1030     .command = remote_gq_supported },
1031   { .label   = "qAttached",
1032     .command = remote_gq_attached },
1033   { .label   = "qXfer",
1034     .command = remote_gq_uninterpreted_transfer },
1035 };
1036 
1037 #define REMOTE_GENERAL_QUERIES RTEMS_DEBUGGER_NUMOF(general_query)
1038 
1039 static int
1040 remote_general_query(uint8_t* buffer, int size)
1041 {
1042   return remote_packet_dispatch(general_query, REMOTE_GENERAL_QUERIES,
1043                                 buffer, size);
1044 }
1045 
1046 static int
1047 remote_gs_non_stop(uint8_t* buffer, int size)
1048 {
1049   const char* response = r_E01;
1050   char*       p = strchr((char*) buffer, ':');
1051   if (p != NULL) {
1052     ++p;
1053     response = r_OK;
1054     if (*p == '0') {
1055       rtems_debugger->flags &= ~RTEMS_DEBUGGER_FLAG_NON_STOP;
1056     }
1057     else if (*p == '1') {
1058       rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_NON_STOP;
1059     }
1060     else
1061       response = r_E01;
1062   }
1063   remote_packet_out_str(response);
1064   remote_packet_out_send();
1065   return 0;
1066 }
1067 
1068 static const rtems_debugger_packet general_set[] = {
1069   { .label   = "QNonStop",
1070     .command = remote_gs_non_stop },
1071 };
1072 
1073 #define REMOTE_GENERAL_SETS RTEMS_DEBUGGER_NUMOF(general_set)
1074 
1075 static int
1076 remote_general_set(uint8_t* buffer, int size)
1077 {
1078   return remote_packet_dispatch(general_set, REMOTE_GENERAL_SETS,
1079                                 buffer, size);
1080 }
1081 
1082 static int
1083 remote_v_stopped(uint8_t* buffer, int size)
1084 {
1085   rtems_debugger_threads* threads = rtems_debugger->threads;
1086   if (threads->next >= threads->stopped.level)
1087     remote_packet_out_str(r_OK);
1088   else {
1089     rtems_id* stopped;
1090     remote_packet_out("T%02x", rtems_debugger->signal);
1091     stopped = rtems_debugger_thread_stopped(threads);
1092     while (threads->next < threads->stopped.level) {
1093       int r;
1094       r = remote_packet_out_append("thread:p%d.%08lx;",
1095                                    rtems_debugger->pid,
1096                                    stopped[threads->next]);
1097       if (r < 0)
1098         break;
1099       ++threads->next;
1100     }
1101   }
1102   remote_packet_out_send();
1103   return 0;
1104 }
1105 
1106 static int
1107 remote_stop_reason(uint8_t* buffer, int size)
1108 {
1109   rtems_debugger->threads->next = 0;
1110   return remote_v_stopped(buffer, size);
1111 }
1112 
1113 static int
1114 remote_v_continue(uint8_t* buffer, int size)
1115 {
1116   buffer += 5;
1117 
1118   if (buffer[0] == '?') {
1119     /*
1120      * You need to supply 'c' and 'C' or GDB says vCont is not supported. As
1121      * Sammy-J says "Silly GDB".
1122      */
1123     remote_packet_out_str("vCont;c;C;s;r;");
1124   }
1125   else {
1126     const char* semi = (const char*) &buffer[0];
1127     bool        resume = false;
1128     bool        ok = true;
1129     while (ok && semi != NULL) {
1130       const char* colon = strchr(semi + 1, ':');
1131       const char  action = *(semi + 1);
1132       DB_UINT     pid = 0;
1133       DB_UINT     tid = 0;
1134       bool        extended;
1135       if (colon != NULL) {
1136         int r = -1;
1137         extended = thread_id_decode(colon + 1, &pid, &tid);
1138         if (extended || check_pid(pid)) {
1139           rtems_debugger_threads* threads = rtems_debugger->threads;
1140           rtems_debugger_thread*  thread = NULL;
1141           int                     index = 0;
1142           if (tid != (DB_UINT) -1) {
1143             rtems_debugger_thread* current;
1144             current = rtems_debugger_thread_current(threads);
1145             index = rtems_debugger_thread_find_index(tid);
1146             if (index >= 0)
1147               thread = &current[index];
1148           }
1149           switch (action) {
1150           case 'c':
1151           case 'C':
1152             if (tid == (DB_UINT) -1) {
1153               r = rtems_debugger_thread_continue_all();
1154             }
1155             else if (thread != NULL) {
1156               r = rtems_debugger_thread_continue(thread);
1157             }
1158             if (r == 0)
1159               resume = true;
1160             break;
1161           case 'S':
1162           case 's':
1163             if (thread != NULL) {
1164               r = rtems_debugger_thread_step(thread);
1165               if (r == 0)
1166                 resume = true;
1167             }
1168             break;
1169           case 'r':
1170             /*
1171              * Range to step around inside: `r start,end`.
1172              */
1173             if (thread != NULL) {
1174               const char* comma;
1175               comma = strchr(semi + 2, ',');
1176               if (comma != NULL) {
1177                 DB_UINT start;
1178                 DB_UINT end;
1179                 start = hex_decode_uint((const uint8_t*) semi + 2);
1180                 end = hex_decode_uint((const uint8_t*) comma + 1);
1181                 r = rtems_debugger_thread_stepping(thread, start, end);
1182                 if (r == 0)
1183                   resume = true;
1184               }
1185               else {
1186                 ok = false;
1187               }
1188             }
1189             break;
1190           default:
1191             rtems_debugger_printf("rtems-db: vCont: unkown action: %c\n", action);
1192             ok = false;
1193             break;
1194           }
1195           if (r < 0)
1196             ok = false;
1197         }
1198       }
1199       else {
1200         rtems_debugger_printf("rtems-db: vCont: no colon\n");
1201         ok = false;
1202       }
1203       semi = strchr(semi + 1, ';');
1204     }
1205 
1206     if (ok)
1207       remote_packet_out_str(r_OK);
1208     else
1209       remote_packet_out_str(r_E01);
1210 
1211     if (resume)
1212       rtems_debugger_thread_system_resume(false);
1213   }
1214 
1215   remote_packet_out_send();
1216 
1217   return 0;
1218 }
1219 
1220 static int
1221 remote_v_kill(uint8_t* buffer, int size)
1222 {
1223   rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_RESET;
1224   return remote_detach(buffer, size);
1225 }
1226 
1227 static const rtems_debugger_packet v_packets[] = {
1228   { .label   = "vCont",
1229     .command = remote_v_continue },
1230   { .label   = "vStopped",
1231     .command = remote_v_stopped },
1232   { .label   = "vKill",
1233     .command = remote_v_kill },
1234 };
1235 
1236 #define REMOTE_V_PACKETS RTEMS_DEBUGGER_NUMOF(v_packets)
1237 
1238 static int
1239 remote_v_packets(uint8_t* buffer, int size)
1240 {
1241   return remote_packet_dispatch(v_packets, REMOTE_V_PACKETS,
1242                                 buffer, size);
1243 }
1244 
1245 static int
1246 remote_thread_select(uint8_t* buffer, int size)
1247 {
1248   const char* response = r_OK;
1249   int*        index = NULL;
1250 
1251   if (buffer[1] == 'g')
1252     index = &rtems_debugger->threads->selector_gen;
1253   else if (buffer[1] == 'c')
1254     index = &rtems_debugger->threads->selector_cont;
1255   else
1256     response = r_E01;
1257 
1258   if (index != NULL) {
1259     DB_UINT pid = 0;
1260     DB_UINT tid = 0;
1261     bool    extended;
1262     extended = thread_id_decode((const char*) &buffer[2], &pid, &tid);
1263     if (extended && !check_pid(pid)) {
1264       response = r_E01;
1265     }
1266     else {
1267       if (tid == 0 || tid == (DB_UINT) -1)
1268         *index = (int) tid;
1269       else {
1270         int r;
1271         r = rtems_debugger_thread_find_index(tid);
1272         if (r < 0) {
1273           response = r_E01;
1274           *index = -1;
1275         }
1276         else
1277           *index = r;
1278       }
1279     }
1280   }
1281 
1282   remote_packet_out_str(response);
1283   remote_packet_out_send();
1284   return 0;
1285 }
1286 
1287 static int
1288 remote_thread_alive(uint8_t* buffer, int size)
1289 {
1290   const char* response = r_E01;
1291   DB_UINT     pid = 0;
1292   DB_UINT     tid = 0;
1293   bool        extended;
1294   extended = thread_id_decode((const char*) &buffer[1], &pid, &tid);
1295   if (!extended || (extended && check_pid(pid))) {
1296     int r;
1297     r = rtems_debugger_thread_find_index(tid);
1298     if (r >= 0)
1299       response = r_OK;
1300   }
1301   remote_packet_out_str(response);
1302   remote_packet_out_send();
1303   return 0;
1304 }
1305 
1306 static int
1307 remote_argc_argv(uint8_t* buffer, int size)
1308 {
1309   return -1;
1310 }
1311 
1312 static int
1313 remote_continue_at(uint8_t* buffer, int size)
1314 {
1315   if (!rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VCONT)) {
1316     char* vCont_c = "vCont;c:p1.-1";
1317     return remote_v_continue((uint8_t*) vCont_c, strlen(vCont_c));
1318   }
1319   return -1;
1320 }
1321 
1322 static int
1323 remote_read_general_regs(uint8_t* buffer, int size)
1324 {
1325   rtems_debugger_threads* threads = rtems_debugger->threads;
1326   bool                    ok = false;
1327   int                     r;
1328   if (threads->selector_gen >= 0 &&
1329       threads->selector_gen < (int) threads->current.level) {
1330     rtems_debugger_thread* current;
1331     rtems_debugger_thread* thread;
1332     current = rtems_debugger_thread_current(threads);
1333     thread = &current[threads->selector_gen];
1334     r = rtems_debugger_target_read_regs(thread);
1335     if (r >= 0) {
1336       remote_packet_out_reset();
1337       r = remote_packet_out_append_hex((const uint8_t*) &thread->registers[0],
1338                                        rtems_debugger_target_reg_table_size());
1339       if (r >= 0)
1340         ok = true;
1341     }
1342   }
1343   if (!ok)
1344     remote_packet_out_str(r_E01);
1345   remote_packet_out_send();
1346   return 0;
1347 }
1348 
1349 static int
1350 remote_write_general_regs(uint8_t* buffer, int size)
1351 {
1352   rtems_debugger_threads* threads = rtems_debugger->threads;
1353   size_t                  reg_table_size = rtems_debugger_target_reg_table_size();
1354   bool                    ok = false;
1355   int                     r;
1356   if (threads->selector_gen >= 0 &&
1357       threads->selector_gen < (int) threads->current.level &&
1358       ((size - 1) / 2) == (int) reg_table_size) {
1359     rtems_debugger_thread* current;
1360     rtems_debugger_thread* thread;
1361     current = rtems_debugger_thread_current(threads);
1362     thread = &current[threads->selector_gen];
1363     r = rtems_debugger_target_read_regs(thread);
1364     if (r >= 0) {
1365       r = rtems_debugger_remote_packet_in_hex((uint8_t*) &thread->registers[0],
1366                                               (const char*) &buffer[1],
1367                                               reg_table_size);
1368       if (r >= 0) {
1369         thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
1370         ok = true;
1371       }
1372     }
1373   }
1374   if (!ok)
1375     remote_packet_out_str(r_E01);
1376   remote_packet_out_send();
1377   return 0;
1378 }
1379 
1380 static int
1381 remote_read_reg(uint8_t* buffer, int size)
1382 {
1383   rtems_debugger_threads* threads = rtems_debugger->threads;
1384   bool                    ok = false;
1385   int                     r;
1386   if (threads->selector_gen >= 0
1387       && threads->selector_gen < (int) threads->current.level) {
1388     size_t reg = hex_decode_int(&buffer[1]);
1389     if (reg < rtems_debugger_target_reg_num()) {
1390       rtems_debugger_thread* current;
1391       rtems_debugger_thread* thread;
1392       current = rtems_debugger_thread_current(threads);
1393       thread = &current[threads->selector_gen];
1394       r = rtems_debugger_target_read_regs(thread);
1395       if (r >= 0) {
1396         const size_t   reg_size = rtems_debugger_target_reg_size(reg);
1397         const size_t   reg_offset = rtems_debugger_target_reg_offset(reg);
1398         const uint8_t* addr = &thread->registers[reg_offset];
1399         remote_packet_out_reset();
1400         r = remote_packet_out_append_hex(addr, reg_size);
1401         if (r >= 0)
1402           ok = true;
1403       }
1404     }
1405   }
1406   if (!ok)
1407     remote_packet_out_str(r_E01);
1408   remote_packet_out_send();
1409   return 0;
1410 }
1411 
1412 static int
1413 remote_write_reg(uint8_t* buffer, int size)
1414 {
1415   rtems_debugger_threads* threads = rtems_debugger->threads;
1416   const char*             response = r_E01;
1417   if (threads->selector_gen >= 0
1418       && threads->selector_gen < (int) threads->current.level) {
1419     const char* equals;
1420     equals = strchr((const char*) buffer, '=');
1421     if (equals != NULL) {
1422       size_t reg = hex_decode_int(&buffer[1]);
1423       if (reg < rtems_debugger_target_reg_num()) {
1424         rtems_debugger_thread* current;
1425         rtems_debugger_thread* thread;
1426         int                    r;
1427         current = rtems_debugger_thread_current(threads);
1428         thread = &current[threads->selector_gen];
1429         r = rtems_debugger_target_read_regs(thread);
1430         if (r >= 0) {
1431           const size_t reg_size = rtems_debugger_target_reg_size(reg);
1432           const size_t reg_offset = rtems_debugger_target_reg_offset(reg);
1433           uint8_t*     addr = &thread->registers[reg_offset];
1434           r = rtems_debugger_remote_packet_in_hex(addr, equals + 1, reg_size);
1435           if (r == 0) {
1436             thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_REG_DIRTY;
1437             response = r_OK;
1438           }
1439         }
1440       }
1441     }
1442   }
1443   remote_packet_out_str(response);
1444   remote_packet_out_send();
1445   return 0;
1446 }
1447 
1448 static int
1449 remote_read_memory(uint8_t* buffer, int size)
1450 {
1451   const char* comma;
1452   comma = strchr((const char*) buffer, ',');
1453   if (comma == NULL)
1454     remote_packet_out_str(r_E01);
1455   else {
1456     uintptr_t addr;
1457     DB_UINT length;
1458     int     r;
1459     addr = hex_decode_addr(&buffer[1]);
1460     length = hex_decode_uint((const uint8_t*) comma + 1);
1461     remote_packet_out_reset();
1462     r = rtems_debugger_target_start_memory_access();
1463     if (r == 0) {
1464       /*
1465        * There should be specific target access for 8, 16, 32 and 64 bit reads.
1466        */
1467       r = remote_packet_out_append_hex((const uint8_t*) addr, length);
1468     }
1469     rtems_debugger_target_end_memory_access();
1470     if (r < 0)
1471       remote_packet_out_str(r_E01);
1472   }
1473   remote_packet_out_send();
1474   return 0;
1475 }
1476 
1477 static int
1478 remote_write_memory(uint8_t* buffer, int size)
1479 {
1480   const char* response = r_E01;
1481   const char* comma;
1482   const char* colon;
1483   comma = strchr((const char*) buffer, ',');
1484   colon = strchr((const char*) buffer, ':');
1485   if (comma != NULL && colon != NULL) {
1486     uintptr_t addr;
1487     DB_UINT length;
1488     int     r;
1489     addr = hex_decode_addr(&buffer[1]);
1490     length = hex_decode_uint((const uint8_t*) comma + 1);
1491     r = rtems_debugger_target_start_memory_access();
1492     if (r == 0) {
1493       r = rtems_debugger_remote_packet_in_hex((uint8_t*) addr,
1494                                               colon + 1,
1495                                               length);
1496     }
1497     rtems_debugger_target_end_memory_access();
1498     if (r == 0)
1499       response = r_OK;
1500   }
1501   remote_packet_out_str(response);
1502   remote_packet_out_send();
1503   return 0;
1504 }
1505 
1506 static int
1507 remote_single_step(uint8_t* buffer, int size)
1508 {
1509   if (!rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VCONT)) {
1510     rtems_debugger_threads* threads = rtems_debugger->threads;
1511     if (threads != NULL && rtems_debugger_thread_current(threads) != NULL) {
1512       rtems_debugger_thread* current;
1513       char                   vCont_s[32];
1514       current = rtems_debugger_thread_current(threads);
1515       snprintf(vCont_s, sizeof(vCont_s), "vCont;s:p1.%08" PRIx32 ";c:p1.-1",
1516                current[threads->selector_cont].id);
1517       return remote_v_continue((uint8_t*) vCont_s, strlen(vCont_s));
1518     }
1519     remote_packet_out_str(r_E01);
1520     remote_packet_out_send();
1521     return 0;
1522   }
1523   return -1;
1524 }
1525 
1526 static int
1527 remote_breakpoints(bool insert, uint8_t* buffer, int size)
1528 {
1529   const char* comma1;
1530   int         r = -1;
1531   comma1 = strchr((const char*) buffer, ',');
1532   if (comma1 != NULL) {
1533     const char* comma2;
1534     comma2 = strchr(comma1 + 1, ',');
1535     if (comma2 != NULL) {
1536       uint32_t  capabilities;
1537       uintptr_t addr;
1538       DB_UINT   kind;
1539       addr = hex_decode_addr((const uint8_t*) comma1 + 1);
1540       kind = hex_decode_uint((const uint8_t*) comma2 + 1);
1541       capabilities = rtems_debugger_target_capabilities();
1542       switch (buffer[1]) {
1543       case '0':
1544         if ((capabilities & RTEMS_DEBUGGER_TARGET_CAP_SWBREAK) != 0) {
1545           r = rtems_debugger_target_swbreak_control(insert, addr, kind);
1546         }
1547         break;
1548       case '1': /* execute */
1549       case '2': /* write */
1550       case '3': /* read */
1551       case '4': /* access */
1552         if ((capabilities & RTEMS_DEBUGGER_TARGET_CAP_HWWATCH) != 0) {
1553           rtems_debugger_target_watchpoint type;
1554           switch (buffer[1]) {
1555           case '1':
1556             type = rtems_debugger_target_hw_execute;
1557             break;
1558           case '2':
1559             type = rtems_debugger_target_hw_write;
1560             break;
1561           case '3':
1562             type = rtems_debugger_target_hw_read;
1563             break;
1564           case '4':
1565           default:
1566             type = rtems_debugger_target_hw_read_write;
1567             break;
1568           }
1569           r = rtems_debugger_target_hwbreak_control(type, insert, addr, kind);
1570         }
1571         break;
1572       default:
1573         break;
1574       }
1575     }
1576   }
1577   remote_packet_out_str(r < 0 ?  r_E01 : r_OK);
1578   remote_packet_out_send();
1579   return 0;
1580 }
1581 
1582 static int
1583 remote_insert_breakpoint(uint8_t* buffer, int size)
1584 {
1585   return remote_breakpoints(true, buffer, size);
1586 }
1587 
1588 static int
1589 remote_remove_breakpoint(uint8_t* buffer, int size)
1590 {
1591   return remote_breakpoints(false, buffer, size);
1592 }
1593 
1594 static int
1595 remote_break(uint8_t* buffer, int size)
1596 {
1597   int r;
1598   r = rtems_debugger_thread_system_suspend();
1599   if (r < 0) {
1600     rtems_debugger_printf("error: rtems-db: suspend all on break\n");
1601   }
1602   return remote_stop_reason(buffer, size);
1603 }
1604 
1605 static const rtems_debugger_packet packets[] = {
1606   { .label   = "q",
1607     .command = remote_general_query },
1608   { .label   = "Q",
1609     .command = remote_general_set },
1610   { .label   = "v",
1611     .command = remote_v_packets },
1612   { .label   = "H",
1613     .command = remote_thread_select },
1614   { .label   = "T",
1615     .command = remote_thread_alive },
1616   { .label   = "?",
1617     .command = remote_stop_reason },
1618   { .label   = "A",
1619     .command = remote_argc_argv },
1620   { .label   = "c",
1621     .command = remote_continue_at },
1622   { .label   = "g",
1623     .command = remote_read_general_regs },
1624   { .label   = "G",
1625     .command = remote_write_general_regs },
1626   { .label   = "p",
1627     .command = remote_read_reg },
1628   { .label   = "P",
1629     .command = remote_write_reg },
1630   { .label   = "m",
1631     .command = remote_read_memory },
1632   { .label   = "M",
1633     .command = remote_write_memory },
1634   { .label   = "s",
1635     .command = remote_single_step },
1636   { .label   = "Z",
1637     .command = remote_insert_breakpoint },
1638   { .label   = "z",
1639     .command = remote_remove_breakpoint },
1640   { .label   = "D",
1641     .command = remote_detach },
1642   { .label   = "k",
1643     .command = remote_v_kill },
1644   { .label   = "r",
1645     .command = remote_v_kill },
1646   { .label   = "R",
1647     .command = remote_v_kill },
1648   { .label   = "^C",
1649     .command = remote_break },
1650 };
1651 
1652 #define REMOTE_PACKETS RTEMS_DEBUGGER_NUMOF(packets)
1653 
1654 static int
1655 remote_packets(uint8_t* buffer, size_t size)
1656 {
1657   return remote_packet_dispatch(packets, REMOTE_PACKETS,
1658                                 buffer, size);
1659 }
1660 
1661 static void
1662 rtems_debugger_events(rtems_task_argument arg)
1663 {
1664   int r = 0;
1665 
1666   if (rtems_debugger_verbose())
1667     rtems_debugger_printf("rtems-db: events running\n");
1668 
1669   /*
1670    * Hold the lock until the thread blocks waiting for an event.
1671    */
1672   rtems_debugger_lock();
1673 
1674   rtems_debugger_target_enable();
1675 
1676   if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_BREAK_WAITER)) {
1677     rtems_debugger->flags &= ~RTEMS_DEBUGGER_FLAG_BREAK_WAITER;
1678     r = rtems_debugger_thread_system_suspend();
1679     if (rtems_debugger_verbose())
1680       rtems_debugger_printf("rtems-db: break waiter\n");
1681     rtems_debugger_server_events_signal();
1682     if (rtems_debugger_verbose())
1683       rtems_debugger_printf("rtems-db: break waiter: signalled\n");
1684   }
1685 
1686   if (r == 0) {
1687     while (rtems_debugger_server_events_running()) {
1688       rtems_debugger_server_events_wait();
1689       if (rtems_debugger_verbose())
1690         rtems_debugger_printf("rtems-db: event woken\n");
1691       if (!rtems_debugger_server_events_running())
1692         break;
1693       r = rtems_debugger_thread_system_suspend();
1694       if (r < 0)
1695         break;
1696       r = remote_stop_reason(NULL, 0);
1697       if (r < 0)
1698         break;
1699     }
1700   }
1701 
1702   if (r < 0)
1703     rtems_debugger_printf("rtems-db: error in events\n");
1704 
1705   rtems_debugger_target_disable();
1706 
1707   rtems_debugger->events_running = false;
1708   rtems_debugger->events_finished = true;
1709 
1710   rtems_debugger_unlock();
1711 
1712   if (rtems_debugger_verbose())
1713     rtems_debugger_printf("rtems-db: events finishing\n");
1714 
1715   rtems_task_exit();
1716 }
1717 
1718 static int
1719 rtems_debugger_session(void)
1720 {
1721   int r;
1722   int rr;
1723 
1724   if (rtems_debugger_verbose())
1725     rtems_debugger_printf("rtems-db: remote running\n");
1726 
1727   /*
1728    * Hold the lock until the thread blocks on the remote input.
1729    */
1730   rtems_debugger_lock();
1731 
1732   r = rtems_debugger_target_create();
1733   if (r < 0) {
1734     rtems_debugger_unlock();
1735     return r;
1736   }
1737 
1738   r = rtems_debugger_thread_create();
1739   if (r < 0) {
1740     rtems_debugger_target_destroy();
1741     rtems_debugger_unlock();
1742     return r;
1743   }
1744 
1745   rtems_debugger->events_running = true;
1746   rtems_debugger->events_finished = false;
1747 
1748   r = rtems_debugger_task_create("DBSe",
1749                                  rtems_debugger->priority,
1750                                  RTEMS_DEBUGGER_STACKSIZE,
1751                                  rtems_debugger_events,
1752                                  0,
1753                                  &rtems_debugger->events_task);
1754   if (r < 0) {
1755     rtems_debugger_thread_destroy();
1756     rtems_debugger_target_destroy();
1757     rtems_debugger_unlock();
1758     return r;
1759   }
1760 
1761   while (rtems_debugger_server_running() &&
1762          rtems_debugger_connected()) {
1763     r = rtems_debugger_remote_packet_in();
1764     if (r < 0)
1765       break;
1766     if (r > 0) {
1767       remote_packets(&rtems_debugger->input[0], r);
1768     }
1769   }
1770 
1771   rtems_debugger->events_running = false;
1772   rtems_debugger_server_events_signal();
1773 
1774   rtems_debugger_unlock();
1775 
1776   rr = rtems_debugger_task_destroy("DBSe",
1777                                    rtems_debugger->events_task,
1778                                    &rtems_debugger->events_finished,
1779                                    RTEMS_DEBUGGER_TIMEOUT_STOP);
1780   if (rr < 0 && r == 0)
1781     r = rr;
1782 
1783   rtems_debugger_lock();
1784 
1785   rr = rtems_debugger_target_destroy();
1786   if (rr < 0 && r == 0)
1787     r = rr;
1788 
1789   rr = rtems_debugger_thread_destroy();
1790   if (rr < 0 && r == 0)
1791     r = rr;
1792 
1793   if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_RESET)) {
1794     rtems_debugger_printf("rtems-db: shutdown\n");
1795     /*
1796      * Wait a moment to let any disconnection protocol a transport has
1797      * complete. The legacy stack needs this to close the connection
1798      * to GDB and clean up.
1799      */
1800     sleep(2);
1801     /*
1802      * No special exit code, the user will asked GDB to kill the
1803      * target
1804      */
1805     rtems_fatal_error_occurred(1122);
1806   }
1807 
1808   rtems_debugger->flags = 0;
1809   rtems_debugger->ack_pending = false;
1810 
1811   rtems_debugger_unlock();
1812 
1813   if (rtems_debugger_verbose())
1814     rtems_debugger_printf("rtems-db: remote finishing\n");
1815 
1816   return r;
1817 }
1818 
1819 static int
1820 rtems_debugger_create(const char*          remote,
1821                       const char*          device,
1822                       rtems_task_priority  priority,
1823                       int                  timeout,
1824                       const rtems_printer* printer)
1825 {
1826   int r;
1827 
1828   if (rtems_debugger != NULL) {
1829     rtems_printf(printer, "error: rtems-db: create: already active\n");
1830     errno = EEXIST;
1831     return -1;
1832   }
1833 
1834   rtems_debugger = malloc(sizeof(rtems_debugger_server));
1835   if (rtems_debugger == NULL) {
1836     rtems_printf(printer, "error: rtems-db: create: no memory\n");
1837     errno = ENOMEM;
1838     return -1;
1839   }
1840 
1841   memset(rtems_debugger, 0, sizeof(rtems_debugger_server));
1842 
1843   /*
1844    * These do not change with a session.
1845    */
1846   rtems_debugger->priority = priority;
1847   rtems_debugger->timeout = timeout;
1848   rtems_debugger->printer = *printer;
1849   rtems_debugger->pid = getpid();
1850   rtems_debugger->remote_debug = false;
1851 
1852   rtems_chain_initialize_empty(&rtems_debugger->exception_threads);
1853 
1854   rtems_debugger->remote = rtems_debugger_remote_find(remote);
1855   if (rtems_debugger->remote== NULL) {
1856     rtems_printf(printer, "error: rtems-db: remote not found: %s\n", remote);
1857     free(rtems_debugger);
1858     rtems_debugger = NULL;
1859     return -1;
1860   }
1861 
1862   r = rtems_debugger->remote->begin(rtems_debugger->remote, device);
1863   if (r < 0) {
1864     rtems_printf(printer, "error: rtems-db: remote begin: %s: %s\n",
1865                  rtems_debugger->remote->name, strerror(errno));
1866     free(rtems_debugger);
1867     rtems_debugger = NULL;
1868     return -1;
1869   }
1870 
1871   /*
1872    * Reset at the end of the session.
1873    */
1874   rtems_debugger->flags = 0;
1875   rtems_debugger->ack_pending = false;
1876 
1877   r = rtems_debugger_lock_create();
1878   if (r < 0) {
1879     free(rtems_debugger);
1880     rtems_debugger = NULL;
1881     return -1;
1882   }
1883 
1884   return 0;
1885 }
1886 
1887 static int
1888 rtems_debugger_destroy(void)
1889 {
1890   int r;
1891   int rr;
1892 
1893   rtems_debugger_lock();
1894   rtems_debugger->server_running = false;
1895   rtems_debugger_unlock();
1896 
1897   r = rtems_debugger_remote_disconnect();
1898 
1899   rr = rtems_debugger->remote->end(rtems_debugger->remote);
1900   if (rr < 0 && r == 0)
1901     r = rr;
1902 
1903   rr = rtems_debugger_task_destroy("DBSs",
1904                                    rtems_debugger->server_task,
1905                                    &rtems_debugger->server_finished,
1906                                    RTEMS_DEBUGGER_TIMEOUT_STOP);
1907   if (rr < 0 && r == 0)
1908     r = rr;
1909 
1910   rr = rtems_debugger_lock_destroy();
1911   if (rr < 0 && r == 0)
1912     r = rr;
1913 
1914   free(rtems_debugger);
1915   rtems_debugger = NULL;
1916 
1917   return r;
1918 }
1919 
1920 static void
1921 rtems_debugger_main(rtems_task_argument arg)
1922 {
1923   int r;
1924 
1925   rtems_debugger_lock();
1926   rtems_debugger->server_running = true;
1927   rtems_debugger->server_finished = false;
1928   rtems_debugger_unlock();
1929 
1930   rtems_debugger_printf("rtems-db: remote running\n");
1931 
1932   while (rtems_debugger_server_running()) {
1933     r = rtems_debugger_remote_connect();
1934     if (r < 0)
1935       break;
1936     rtems_debugger_session();
1937     rtems_debugger_remote_disconnect();
1938   }
1939 
1940   rtems_debugger_printf("rtems-db: remote finishing\n");
1941 
1942   rtems_debugger_lock();
1943   rtems_debugger->server_running = false;
1944   rtems_debugger->server_finished = true;
1945   rtems_debugger_unlock();
1946 
1947   rtems_task_exit();
1948 }
1949 
1950 int
1951 rtems_debugger_start(const char*          remote,
1952                      const char*          device,
1953                      int                  timeout,
1954                      rtems_task_priority  priority,
1955                      const rtems_printer* printer)
1956 {
1957   int r;
1958 
1959   r = rtems_debugger_create(remote, device, priority, timeout, printer);
1960   if (r < 0)
1961     return -1;
1962 
1963   rtems_debugger_lock();
1964   rtems_debugger->server_running = false;
1965   rtems_debugger->server_finished = true;
1966   _Condition_Initialize_named(&rtems_debugger->server_cond, "DBserver");
1967   rtems_debugger_unlock();
1968 
1969   r = rtems_debugger_task_create("DBSs",
1970                                  priority,
1971                                  RTEMS_DEBUGGER_STACKSIZE,
1972                                  rtems_debugger_main,
1973                                  0,
1974                                  &rtems_debugger->server_task);
1975   if (r < 0) {
1976     rtems_debugger_destroy();
1977     return -1;
1978   }
1979 
1980   return 0;
1981 }
1982 
1983 void
1984 rtems_debugger_server_crash(void)
1985 {
1986   rtems_debugger_lock();
1987   rtems_debugger->server_running = false;
1988   rtems_debugger_unlock();
1989   rtems_debugger->remote->end(rtems_debugger->remote);
1990 }
1991 
1992 int
1993 rtems_debugger_break(bool wait)
1994 {
1995   int r = 0;
1996   if (!rtems_debugger_running()) {
1997     errno = EIO;
1998     r = -1;
1999   } else {
2000     rtems_debugger_lock();
2001     if (rtems_debugger_server_events_running()) {
2002       rtems_debugger_server_events_signal();
2003     } else if (
2004       wait && !rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_BREAK_WAITER)) {
2005       rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_BREAK_WAITER;
2006       rtems_debugger_server_events_wait();
2007     } else {
2008       errno = EIO;
2009       r = -1;
2010     }
2011     rtems_debugger_unlock();
2012   }
2013   return r;
2014 }
2015 
2016 int
2017 rtems_debugger_stop(void)
2018 {
2019   return rtems_debugger_destroy();
2020 }
2021 
2022 bool
2023 rtems_debugger_running(void)
2024 {
2025   return rtems_debugger != NULL;
2026 }
2027 
2028 void
2029 rtems_debugger_set_verbose(bool on)
2030 {
2031   if (rtems_debugger_running()) {
2032     if (on)
2033       rtems_debugger->flags |= RTEMS_DEBUGGER_FLAG_VERBOSE;
2034     else
2035       rtems_debugger->flags &= ~RTEMS_DEBUGGER_FLAG_VERBOSE;
2036   }
2037 }
2038 
2039 int
2040 rtems_debugger_remote_debug(bool state)
2041 {
2042   if (rtems_debugger_running()) {
2043     rtems_debugger_lock();
2044     rtems_debugger->remote_debug = state;
2045     rtems_debugger_printf("rtems-db: remote-debug is %s\n",
2046                           rtems_debugger->remote_debug ? "on" : "off");
2047     rtems_debugger_unlock();
2048   } else {
2049     rtems_debugger_printf("rtems-db: debug server not running\n");
2050   }
2051   return 0;
2052 }