source: rtems/cpukit/libdebugger/rtems-debugger-remote-tcp.c @ 6ad3f471

5
Last change on this file since 6ad3f471 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: 8.5 KB
Line 
1/*
2 * Copyright (c) 2016 Chris Johns <chrisj@rtems.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <errno.h>
28#include <stdlib.h>
29#include <unistd.h>
30
31#include <arpa/inet.h>
32#include <netinet/in.h>
33#include <netinet/tcp.h>
34#include <sys/types.h>
35#include <sys/socket.h>
36
37#include <rtems/rtems-debugger.h>
38#include <rtems/debugger/rtems-debugger-server.h>
39#include <rtems/debugger/rtems-debugger-remote.h>
40
41#include "rtems-debugger-remote-tcp.h"
42
43/**
44 * Debugger default server port. 'RT' as ASCII.
45 */
46#define RTEMS_DB_PORT_DEFAULT (8284)
47
48/**
49 * TCP Remote data.
50 */
51typedef struct
52{
53  int fd;
54  int port;
55} rtems_debugger_remote_tcp;
56
57static rtems_debugger_remote_tcp*
58tcp_remote(rtems_debugger_remote* remote)
59{
60  rtems_debugger_remote_tcp* tcp = NULL;
61  rtems_debugger_lock();
62  if (remote != NULL && remote->data != NULL)
63      tcp = (rtems_debugger_remote_tcp*) remote->data;
64  rtems_debugger_unlock();
65  return tcp;
66}
67
68static int
69tcp_remote_begin(rtems_debugger_remote* remote, const char* device)
70{
71  rtems_debugger_remote_tcp* tcp;
72  int                        port;
73  char*                      end;
74
75  rtems_debugger_lock();
76
77  /*
78   * Parse the port number.
79   */
80  port = strtoul(device, &end, 10);
81  if (port == 0 || *end != '\0') {
82    rtems_debugger_printf("error: rtems-db: tcp remote: invalid port: %s\n", device);
83    return -1;
84  }
85
86  tcp = malloc(sizeof(rtems_debugger_remote_tcp));
87  if (tcp == NULL) {
88    errno = ENOMEM;
89    return -1;
90  }
91
92  remote->data = tcp;
93
94  tcp->fd = -1;
95  tcp->port = port;
96
97  rtems_debugger_unlock();
98
99  return 0;
100}
101
102static int
103tcp_remote_end(rtems_debugger_remote* remote)
104{
105  rtems_debugger_lock();
106
107  if (remote != NULL && remote->data != NULL) {
108    rtems_debugger_remote_tcp* tcp = (rtems_debugger_remote_tcp*) remote->data;
109    if (tcp != NULL) {
110      if (tcp->fd >= 0)
111        close(tcp->fd);
112      free(tcp);
113      remote->data = NULL;
114    }
115  }
116
117  rtems_debugger_unlock();
118
119  return 0;
120}
121
122static int
123tcp_remote_connect(rtems_debugger_remote* remote)
124{
125  int                        ld;
126  struct sockaddr_in         addr;
127  socklen_t                  opt;
128  socklen_t                  len;
129  bool                       running;
130  struct timeval             timeout;
131  rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
132  int                        r;
133
134  if (rtems_debugger_verbose())
135    rtems_debugger_printf("error: rtems-db: tcp remote: connect\n");
136
137  ld = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
138  if (ld < 0) {
139    rtems_debugger_printf("error: rtems-db: tcp remote: socket: (%d) %s\n",
140                          errno, strerror(errno));
141    return -1;
142  }
143
144  opt = 1;
145  r = setsockopt(ld,
146                 SOL_SOCKET,
147                 SO_REUSEADDR,
148                 (char *) &opt,
149                 sizeof(opt));
150  if (r < 0) {
151    close(ld);
152    rtems_debugger_printf("error: rtems-db: tcp remote: setsocket: reuseaddr: (%d) %s\n",
153                          errno, strerror(errno));
154    return -1;
155  }
156
157  addr.sin_family = PF_INET;
158  addr.sin_port = htons(tcp->port);
159  addr.sin_addr.s_addr = INADDR_ANY;
160
161  r = bind(ld, (struct sockaddr *) &addr, sizeof(addr));
162  if (r < 0) {
163    close(ld);
164    rtems_debugger_printf("error: rtems-db: tcp remote: bind: (%d) %s\n",
165                          errno, strerror(errno));
166    return -1;
167  }
168
169  /*
170   * Backlog of 1 connection.
171   */
172  r = listen(ld, 1);
173  if (r < 0) {
174    close(ld);
175    rtems_debugger_printf("error: rtems-db: tcp remote: listen: (%d) %s\n",
176                          errno, strerror(errno));
177    return -1;
178  }
179
180  /*
181   * Use a random port if the port is 0.
182   */
183  if (tcp->port == 0) {
184    len = sizeof(addr);
185    r = getsockname(ld, (struct sockaddr *) &addr, &len);
186    if (r < 0 || len < sizeof(addr)) {
187      close(ld);
188      rtems_debugger_printf("error: rtems-db: tcp remote: getsockname: (%d) %s\n",
189                            errno, strerror(errno));
190      return -1;
191    }
192    tcp->port = ntohs(addr.sin_port);
193  }
194
195  rtems_debugger_printf("rtems-db: tcp remote: listing on port: %d\n",
196                        tcp->port);
197
198  len = sizeof(addr);
199  tcp->fd = accept(ld, (struct sockaddr *) &addr, &len);
200
201  running = rtems_debugger_server_running();
202
203  close(ld);
204
205  if (tcp->fd < 0) {
206    /*
207     * EBADF means the socket has been closed, ignore it.
208     */
209    if (errno != EBADF)
210      rtems_debugger_printf("error: rtems-db: accept: (%d) %s\n",
211                            errno, strerror(errno));
212    return -1;
213  }
214
215  if (!running) {
216    close(tcp->fd);
217    errno = EIO;
218    return -1;
219  }
220
221  opt = 1;
222  r = setsockopt(tcp->fd,
223                 SOL_SOCKET, SO_KEEPALIVE,
224                 (char*) &opt,
225                 sizeof(opt));
226  if (r < 0) {
227    int errno_ = errno;
228    close(tcp->fd);
229    rtems_debugger_printf("error: rtems-db: tcp remote: set keepalive: (%d) %s\n",
230                          errno, strerror(errno));
231    errno = errno_;
232    return -1;
233  }
234
235  opt = 1;
236  r = setsockopt(tcp->fd,
237                 IPPROTO_TCP, TCP_NODELAY,
238                 (char*) &opt, sizeof(opt));
239  if (r < 0) {
240    int errno_ = errno;
241    close(tcp->fd);
242    rtems_debugger_printf("error: rtems-db: tcp remote: set no-delay: (%d) %s\n",
243                          errno, strerror(errno));
244    errno = errno_;
245    return -1;
246  }
247
248  timeout.tv_sec = rtems_debugger->timeout;
249  timeout.tv_usec = 0;
250
251  r = setsockopt(tcp->fd,
252                 SOL_SOCKET, SO_RCVTIMEO,
253                 (char*) &timeout, sizeof(timeout));
254  if (r < 0) {
255    int errno_ = errno;
256    close(tcp->fd);
257    rtems_debugger_printf("error: rtems-db: tcp remote: set rcv-timeout: (%d) %s\n",
258                          errno, strerror(errno));
259    errno = errno_;
260    return -1;
261  }
262
263  rtems_debugger_printf("rtems-db: tcp remote: connect host: %s\n",
264                        inet_ntoa(addr.sin_addr));
265
266  return 0;
267}
268
269static int
270tcp_remote_disconnect(rtems_debugger_remote* remote)
271{
272  rtems_debugger_remote_tcp* tcp;
273
274  rtems_debugger_lock();
275
276  rtems_debugger_printf("rtems-db: tcp remote: disconnect host\n");
277
278  tcp = (rtems_debugger_remote_tcp*) remote->data;
279  close(tcp->fd);
280
281  rtems_debugger_unlock();
282
283  return 0;
284}
285
286static bool
287tcp_remote_isconnected(rtems_debugger_remote* remote)
288{
289  rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
290  return tcp != NULL && tcp->fd >= 0;
291}
292
293static ssize_t
294tcp_remote_receive(rtems_debugger_remote* remote,
295                   void*                  buf,
296                   size_t                 nbytes)
297{
298  rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
299  ssize_t                    len;
300  if (tcp != NULL) {
301    len = read(tcp->fd, buf, nbytes);
302  }
303  else {
304    errno = EIO;
305    len = -1;
306  }
307  return len;
308}
309
310static ssize_t
311tcp_remote_send(rtems_debugger_remote* remote,
312                const void*            buf,
313                size_t                 nbytes)
314{
315  rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
316  ssize_t                    len;
317  if (tcp != NULL) {
318    len = write(tcp->fd, buf, nbytes);
319  }
320  else {
321    errno = EIO;
322    len = -1;
323  }
324  return len;
325}
326
327static rtems_debugger_remote remote_tcp =
328{
329  .name = "tcp",
330  .begin = tcp_remote_begin,
331  .end = tcp_remote_end,
332  .connect = tcp_remote_connect,
333  .disconnect = tcp_remote_disconnect,
334  .isconnected = tcp_remote_isconnected,
335  .read = tcp_remote_receive,
336  .write = tcp_remote_send
337};
338
339int
340rtems_debugger_register_tcp_remote(void)
341{
342  return rtems_debugger_remote_register(&remote_tcp);
343}
Note: See TracBrowser for help on using the repository browser.