Skip to content

Commit 10fb959

Browse files
committed
OSD-GDB server: Adds following features
(1) Connect to GDB over TCP (2) Send and Recieve data to/from the client (3) Receive RSP packet from the client (4) Validate the obtained packet using checksum (5) Send RSP packet to the client
1 parent 59de556 commit 10fb959

3 files changed

Lines changed: 457 additions & 1 deletion

File tree

src/libosd/gdbserver.c

Lines changed: 359 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
/* Copyright 2018 The Open SoC Debug Project
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
#include <osd/module.h>
17+
#include <osd/osd.h>
18+
#include <osd/reg.h>
19+
#include "osd-private.h"
20+
21+
#include <arpa/inet.h>
22+
#include <assert.h>
23+
#include <fcntl.h>
24+
#include <gelf.h>
25+
#include <netinet/in.h>
26+
#include <stdio.h>
27+
#include <stdlib.h>
28+
#include <string.h>
29+
#include <sys/errno.h>
30+
#include <sys/socket.h>
31+
#include <sys/wait.h>
32+
#include <unistd.h>
33+
34+
/**
35+
* OSD-GDB server context
36+
*/
37+
struct osd_gdbserver_ctx {
38+
struct osd_hostmod_ctx *hostmod_ctx;
39+
struct osd_log_ctx *log_ctx;
40+
int fd;
41+
char *name;
42+
char *port;
43+
struct sockaddr_in sin;
44+
char buffer[OSD_GDBSERVER_BUFF_SIZE];
45+
int buf_cnt;
46+
char *buf_p;
47+
int closed;
48+
int client_fd;
49+
};
50+
51+
API_EXPORT
52+
osd_result osd_gdbserver_new(struct osd_gdbserver_ctx **ctx,
53+
struct osd_log_ctx *log_ctx,
54+
const char *host_controller_address)
55+
{
56+
osd_result rv;
57+
58+
struct osd_gdbserver_ctx *c = calloc(1, sizeof(struct osd_gdbserver_ctx));
59+
assert(c);
60+
61+
c->log_ctx = log_ctx;
62+
63+
struct osd_hostmod_ctx *hostmod_ctx;
64+
rv = osd_hostmod_new(&hostmod_ctx, log_ctx, host_controller_address, NULL,
65+
NULL);
66+
assert(OSD_SUCCEEDED(rv));
67+
c->hostmod_ctx = hostmod_ctx;
68+
69+
*ctx = c;
70+
71+
return OSD_OK;
72+
}
73+
74+
API_EXPORT
75+
osd_result osd_gdbserver_connect(struct osd_gdbserver_ctx *ctx, char *name,
76+
char *port)
77+
{
78+
rv = osd_hostmod_connect(ctx->hostmod_ctx);
79+
if (OSD_FAILED(rv)) {
80+
return rv;
81+
}
82+
83+
int sockoptval = 1;
84+
85+
ctx->name = strdup(name);
86+
ctx->port = strdup(port);
87+
ctx->fd = socket(AF_INET, SOCK_STREAM, 0);
88+
89+
if (OSD_FAILED(ctx->fd)) {
90+
free_service(ctx);
91+
return OSD_ERROR_CONNECTION_FAILED;
92+
}
93+
94+
setsockopt(ctx->fd, SOL_SOCKET, SO_REUSEADDR, &sockoptval, sizeof(int));
95+
96+
memset(&ctx->sin, 0, sizeof(ctx->sin));
97+
ctx->sin.sin_family = AF_INET;
98+
ctx->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
99+
ctx->sin.sin_port = htons(OSD_GDBSERVER_PORT);
100+
101+
if (OSD_FAILED(
102+
bind(ctx->fd, (struct sockaddr *)&ctx->sin, sizeof(ctx->sin)))) {
103+
close(ctx->fd);
104+
free_service(ctx);
105+
return OSD_ERROR_CONNECTION_FAILED;
106+
}
107+
108+
if (OSD_FAILED(listen(ctx->fd, 1))) {
109+
close(ctx->fd);
110+
free_service(ctx);
111+
return OSD_ERROR_CONNECTION_FAILED;
112+
}
113+
114+
struct sockaddr_in addr_in;
115+
addr_in.sin_port = 0;
116+
socklen_t addr_in_size = sizeof(addr_in);
117+
118+
getsockname(ctx->fd, (struct sockaddr *)&addr_in, &addr_in_size);
119+
printf("server started on %s, listening on port %d\n", name,
120+
ntohs(addr_in.sin_port));
121+
122+
while (1) {
123+
ctx->client_fd =
124+
accept(ctx->fd, (struct sockaddr *)&addr_in, &addr_in_size);
125+
if (OSD_FAILED(ctx->client_fd)) {
126+
osd_result rv = close(ctx->client_fd);
127+
if (OSD_SUCCEEDED(rv)) {
128+
break;
129+
}
130+
}
131+
printf("Server got connection from client %s\n",
132+
inet_ntoa(addr_in.sin_addr));
133+
134+
if (OSD_SUCCEEDED(close(ctx->client_fd))) {
135+
break;
136+
}
137+
}
138+
139+
close(ctx->fd);
140+
141+
return OSD_OK;
142+
}
143+
144+
API_EXPORT
145+
osd_result osd_gdbserver_disconnect(struct osd_gdbserver_ctx *ctx)
146+
{
147+
return osd_hostmod_disconnect(ctx->hostmod_ctx);
148+
}
149+
150+
API_EXPORT
151+
bool osd_gdbserver_is_connected(struct osd_gdbserver_ctx *ctx)
152+
{
153+
return osd_hostmod_is_connected(ctx->hostmod_ctx);
154+
}
155+
156+
API_EXPORT
157+
void osd_gdbserver_free(struct osd_gdbserver_ctx **ctx_p)
158+
{
159+
assert(ctx_p);
160+
struct osd_gdbserver_ctx *ctx = *ctx_p;
161+
if (!ctx) {
162+
return;
163+
}
164+
165+
osd_hostmod_free(&ctx->hostmod_ctx);
166+
167+
free(ctx);
168+
*ctx_p = NULL;
169+
}
170+
171+
API_EXPORT
172+
osd_result osd_gdbserver_read_data(struct osd_gdbserver_ctx *ctx)
173+
{
174+
memset(ctx->buffer, 0, sizeof ctx->buffer);
175+
ctx->buf_cnt = read(ctx->client_fd, ctx->buffer, OSD_GDBSERVER_BUFF_SIZE);
176+
177+
if (OSD_FAILED(ctx->buf_cnt)) {
178+
return OSD_ERROR_CONNECTION_FAILED;
179+
} else {
180+
if (ctx->buf_cnt > 0) {
181+
printf("Server:Packet Received %s\n", ctx->buffer);
182+
printf("Size of Packet:%d\n", ctx->buf_cnt);
183+
return OSD_OK;
184+
}
185+
if (ctx->buf_cnt == 0) {
186+
ctx->closed = 1;
187+
return OSD_ERROR_FAILURE;
188+
}
189+
}
190+
191+
return OSD_OK;
192+
}
193+
194+
API_EXPORT
195+
osd_result osd_gdbserver_write_data(struct osd_gdbserver_ctx *ctx, char *data,
196+
int len)
197+
{
198+
if (ctx->closed == 1) {
199+
return OSD_ERROR_NOT_CONNECTED;
200+
}
201+
int wlen = write(ctx->client_fd, data, len);
202+
if (wlen == len) {
203+
return OSD_OK;
204+
}
205+
206+
return OSD_ERROR_NOT_CONNECTED;
207+
}
208+
209+
static osd_result get_char(struct osd_gdbserver_ctx *ctx, int *ch)
210+
{
211+
osd_result rv;
212+
213+
ctx->buf_p = ctx->buffer;
214+
ctx->buf_cnt--;
215+
if (OSD_FAILED(ctx->buf_cnt)) {
216+
return OSD_ERROR_FAILURE;
217+
}
218+
*ch = *(ctx->buf_p++);
219+
220+
return OSD_OK;
221+
}
222+
223+
static osd_result validate_rsp_packet(struct osd_gdbserver_ctx *ctx,
224+
bool *ver_checksum, int *len,
225+
char *buffer)
226+
{
227+
unsigned char val_checksum = 0;
228+
char packet_checksum[3];
229+
int packet_char;
230+
int cnt = 0;
231+
osd_result rv;
232+
233+
char *buf_p = ctx->buf_p;
234+
int buf_cnt = ctx->buf_cnt;
235+
236+
// packet-format: $packet-data#checksum
237+
int i = 0;
238+
char *buf = buf_p;
239+
int done = 0;
240+
// traversing through the obtained packet till we obtained '#'
241+
while (1) {
242+
packet_char = *buf++;
243+
i++;
244+
245+
if (packet_char == '#') {
246+
done = 1;
247+
break;
248+
}
249+
/*Any escaped byte (here, '}') is transmitted as the escape
250+
* character followed by the original character XORed with 0x20.
251+
*/
252+
if (packet_char == '}') {
253+
val_checksum += packet_char & 0xff;
254+
packet_char = *buf++;
255+
i++;
256+
val_checksum += packet_char & 0xff;
257+
buffer[cnt++] = (packet_char ^ 0x20) & 0xff;
258+
} else {
259+
val_checksum += packet_char & 0xff;
260+
buffer[cnt++] = packet_char & 0xff;
261+
}
262+
}
263+
264+
*len = cnt;
265+
packet_char = *buf++;
266+
packet_checksum[0] = packet_char;
267+
packet_char = *buf;
268+
packet_checksum[1] = packet_char;
269+
packet_checksum[2] = 0;
270+
*ver_checksum = (val_checksum == strtoul(packet_checksum, NULL, 16));
271+
272+
return OSD_OK;
273+
}
274+
275+
static osd_result receive_rsp_packet(struct osd_gdbserver_ctx *ctx,
276+
char *buffer, int *len)
277+
{
278+
int packet_char;
279+
osd_result rv;
280+
281+
do {
282+
rv = get_char(ctx, &packet_char);
283+
if (OSD_FAILED(rv)) {
284+
return rv;
285+
}
286+
} while (packet_char != '$');
287+
288+
bool ver_checksum = 0;
289+
rv = validate_rsp_packet(ctx, &ver_checksum, len, buffer);
290+
291+
if (OSD_FAILED(rv)) {
292+
return rv;
293+
} else {
294+
if (ver_checksum == 1) {
295+
rv = osd_gdbserver_write_data(ctx, "+", 1);
296+
} else {
297+
rv = osd_gdbserver_write_data(ctx, "-", 1);
298+
}
299+
if (OSD_FAILED(rv)) {
300+
return rv;
301+
}
302+
}
303+
return OSD_OK;
304+
}
305+
306+
static osd_result send_rsp_packet(struct osd_gdbserver_ctx *ctx, char *buffer,
307+
int len)
308+
{
309+
char packet_buffer[len + 3];
310+
int packet_checksum = 0;
311+
osd_result rv;
312+
313+
while (1) {
314+
packet_buffer[0] = '$';
315+
memcpy(packet_buffer + 1, buffer, len);
316+
int j = len + 1;
317+
packet_buffer[j++] = '#';
318+
for (int i = 0; i < len; i++) {
319+
packet_checksum += buffer[i];
320+
}
321+
packet_buffer[j++] = dectohex((packet_checksum >> 4) & 0xf);
322+
packet_buffer[j] = dectohex(packet_checksum & 0xf);
323+
324+
rv = osd_gdbserver_write_data(ctx, packet_buffer, len + 4);
325+
if (OSD_FAILED(rv)) {
326+
return OSD_ERROR_FAILURE;
327+
}
328+
329+
rv = osd_gdbserver_read_data(ctx);
330+
if (OSD_FAILED(rv)) {
331+
return OSD_ERROR_FAILURE;
332+
}
333+
334+
char reply = ctx->buffer[0];
335+
if (reply == '+') {
336+
break;
337+
} else {
338+
return OSD_ERROR_FAILURE;
339+
}
340+
}
341+
342+
return OSD_OK;
343+
}
344+
345+
static int dectohex(int packet_char)
346+
{
347+
if (packet_char < 10) {
348+
return packet_char + '0';
349+
} else {
350+
return packet_char - 10 + 'a';
351+
}
352+
}
353+
354+
static void free_service(struct osd_gdbserver_ctx *ctx)
355+
{
356+
free(ctx->name);
357+
free(ctx->port);
358+
free(ctx);
359+
}

0 commit comments

Comments
 (0)