6 #include <sys/socket.h>
14 #include "gdbserver.h"
17 unsigned int circular_buffer_t
<T
>::size() const
22 return end
+ capacity
- start
;
26 void circular_buffer_t
<T
>::consume(unsigned int bytes
)
28 start
= (start
+ bytes
) % capacity
;
32 unsigned int circular_buffer_t
<T
>::contiguous_space() const
36 return capacity
- end
- 1;
38 return capacity
- end
;
40 return start
- end
- 1;
44 void circular_buffer_t
<T
>::data_added(unsigned int bytes
)
47 assert(end
<= capacity
);
53 void circular_buffer_t
<T
>::reset()
59 // Code inspired by/copied from OpenOCD server/server.c.
61 gdbserver_t::gdbserver_t(uint16_t port
) :
63 send_start(0), send_end(0)
65 socket_fd
= socket(AF_INET
, SOCK_STREAM
, 0);
66 if (socket_fd
== -1) {
67 fprintf(stderr
, "error creating socket: %s\n", strerror(errno
));
71 int so_reuseaddr_option
= 1;
75 (void *)&so_reuseaddr_option
,
78 int oldopts
= fcntl(socket_fd
, F_GETFL
, 0);
79 fcntl(socket_fd
, F_SETFL
, oldopts
| O_NONBLOCK
);
81 struct sockaddr_in sin
;
82 memset(&sin
, 0, sizeof(sin
));
83 sin
.sin_family
= AF_INET
;
84 sin
.sin_addr
.s_addr
= INADDR_ANY
;
85 sin
.sin_port
= htons(port
);
87 if (bind(socket_fd
, (struct sockaddr
*)&sin
, sizeof(sin
)) == -1) {
88 fprintf(stderr
, "couldn't bind to socket: %s\n", strerror(errno
));
92 /* These setsockopt()s must happen before the listen() */
93 int window_size
= 128 * 1024;
94 setsockopt(socket_fd
, SOL_SOCKET
, SO_SNDBUF
,
95 (char *)&window_size
, sizeof(window_size
));
96 setsockopt(socket_fd
, SOL_SOCKET
, SO_RCVBUF
,
97 (char *)&window_size
, sizeof(window_size
));
99 if (listen(socket_fd
, 1) == -1) {
100 fprintf(stderr
, "couldn't listen on socket: %s\n", strerror(errno
));
105 void gdbserver_t::accept()
107 struct sockaddr client_addr
;
108 socklen_t address_size
= sizeof(client_addr
);
109 client_fd
= ::accept(socket_fd
, &client_addr
, &address_size
);
110 if (client_fd
== -1) {
111 if (errno
== EAGAIN
) {
112 // We'll try again in the next call.
114 fprintf(stderr
, "failed to accept on socket: %s (%d)\n", strerror(errno
), errno
);
118 int oldopts
= fcntl(client_fd
, F_GETFL
, 0);
119 fcntl(client_fd
, F_SETFL
, oldopts
| O_NONBLOCK
);
124 void gdbserver_t::read()
126 // Reading from a non-blocking socket still blocks if there is no data
129 size_t count
= recv_buf
.contiguous_space();
131 ssize_t bytes
= ::read(client_fd
, recv_buf
.contiguous_data(), count
);
133 if (errno
== EAGAIN
) {
134 // We'll try again the next call.
136 fprintf(stderr
, "failed to read on socket: %s (%d)\n", strerror(errno
), errno
);
139 } else if (bytes
== 0) {
140 // The remote disconnected.
146 printf("read %ld bytes\n", bytes
);
147 recv_buf
.data_added(bytes
);
151 void print_packet(const std::vector
<uint8_t> &packet
)
153 for (uint8_t c
: packet
) {
154 fprintf(stderr
, "%c", c
);
156 fprintf(stderr
, "\n");
159 uint8_t compute_checksum(const std::vector
<uint8_t> &packet
)
161 uint8_t checksum
= 0;
162 for (auto i
= packet
.begin() + 1; i
!= packet
.end() - 3; i
++ ) {
168 uint8_t character_hex_value(uint8_t character
)
170 if (character
>= '0' && character
<= '9')
171 return character
- '0';
172 if (character
>= 'a' && character
<= 'f')
173 return 10 + character
- 'a';
174 if (character
>= 'A' && character
<= 'F')
175 return 10 + character
- 'A';
179 uint8_t extract_checksum(const std::vector
<uint8_t> &packet
)
181 return character_hex_value(*(packet
.end() - 1)) +
182 16 * character_hex_value(*(packet
.end() - 2));
185 void gdbserver_t::process_requests()
187 // See https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html
189 while (!recv_buf
.empty()) {
190 std::vector
<uint8_t> packet
;
191 for (unsigned int i
= 0; i
< recv_buf
.size(); i
++) {
192 uint8_t b
= recv_buf
[i
];
194 // Start of new packet.
195 if (!packet
.empty()) {
196 fprintf(stderr
, "Received malformed %ld-byte packet from debug client\n", packet
.size());
197 print_packet(packet
);
205 // Packets consist of $<packet-data>#<checksum>
206 // where <checksum> is
207 if (packet
.size() >= 4 &&
208 packet
[packet
.size()-3] == '#') {
209 if (compute_checksum(packet
) == extract_checksum(packet
)) {
210 handle_packet(packet
);
212 fprintf(stderr
, "Received %ld-byte packet with invalid checksum\n", packet
.size());
213 fprintf(stderr
, "Computed checksum: %x\n", compute_checksum(packet
));
214 print_packet(packet
);
217 recv_buf
.consume(i
+1);
221 // There's a partial packet in the buffer. Wait until we get more data to
228 void gdbserver_t::handle_packet(const std::vector
<uint8_t> &packet
)
230 fprintf(stderr
, "Received %ld-byte packet from debug client\n", packet
.size());
231 print_packet(packet
);
235 void gdbserver_t::handle()
244 this->process_requests();
247 void gdbserver_t::send(const char* msg
)
249 unsigned int length
= strlen(msg
);