Reindent all source files
[fw/stlink] / gdbserver / gdb-remote.c
1 /*
2  * Copyright (C)  2011 Peter Zotov <whitequark@whitequark.org>
3  * Use of this source code is governed by a BSD-style
4  * license that can be found in the LICENSE file.
5  */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdint.h>
12 #ifdef __MINGW32__
13 #include "mingw.h"
14 #else
15 #include <sys/poll.h>
16 #endif
17
18 static const char hex[] = "0123456789abcdef";
19
20 int gdb_send_packet(int fd, char* data) {
21     int length = strlen(data) + 5;
22     char* packet = malloc(length); /* '$' data (hex) '#' cksum (hex) */
23
24     memset(packet, 0, length);
25
26     packet[0] = '$';
27
28     uint8_t cksum = 0;
29     for(unsigned int i = 0; i < strlen(data); i++) {
30         packet[i + 1] = data[i];
31         cksum += data[i];
32     }
33
34     packet[length - 4] = '#';
35     packet[length - 3] = hex[cksum >> 4];
36     packet[length - 2] = hex[cksum & 0xf];
37
38     while(1) {
39         if(write(fd, packet, length) != length) {
40             free(packet);
41             return -2;
42         }
43
44         char ack;
45         if(read(fd, &ack, 1) != 1) {
46             free(packet);
47             return -2;
48         }
49
50         if(ack == '+') {
51             free(packet);
52             return 0;
53         }
54     }
55 }
56
57 #define ALLOC_STEP 1024
58
59 int gdb_recv_packet(int fd, char** buffer) {
60     unsigned packet_size = ALLOC_STEP + 1, packet_idx = 0;
61     uint8_t cksum = 0;
62     char recv_cksum[3] = {0};
63     char* packet_buffer = malloc(packet_size);
64     unsigned state;
65
66 start:
67     state = 0;
68     /*
69      * 0: waiting $
70      * 1: data, waiting #
71      * 2: cksum 1
72      * 3: cksum 2
73      * 4: fin
74      */
75
76     char c;
77     while(state != 4) {
78         if(read(fd, &c, 1) != 1) {
79             return -2;
80         }
81
82         switch(state) {
83         case 0:
84             if(c != '$') {
85                 // ignore
86             } else {
87                 state = 1;
88             }
89             break;
90
91         case 1:
92             if(c == '#') {
93                 state = 2;
94             } else {
95                 packet_buffer[packet_idx++] = c;
96                 cksum += c;
97
98                 if(packet_idx == packet_size) {
99                     packet_size += ALLOC_STEP;
100                     packet_buffer = realloc(packet_buffer, packet_size);
101                 }
102             }
103             break;
104
105         case 2:
106             recv_cksum[0] = c;
107             state = 3;
108             break;
109
110         case 3:
111             recv_cksum[1] = c;
112             state = 4;
113             break;
114         }
115     }
116
117     uint8_t recv_cksum_int = strtoul(recv_cksum, NULL, 16);
118     if(recv_cksum_int != cksum) {
119         char nack = '-';
120         if(write(fd, &nack, 1) != 1) {
121             return -2;
122         }
123
124         goto start;
125     } else {
126         char ack = '+';
127         if(write(fd, &ack, 1) != 1) {
128             return -2;
129         }
130     }
131
132     packet_buffer[packet_idx] = 0;
133     *buffer = packet_buffer;
134
135     return packet_idx;
136 }
137
138 // Here we skip any characters which are not \x03, GDB interrupt.
139 // As we use the mode with ACK, in a (very unlikely) situation of a packet
140 // lost because of this skipping, it will be resent anyway.
141 int gdb_check_for_interrupt(int fd) {
142     struct pollfd pfd;
143     pfd.fd = fd;
144     pfd.events = POLLIN;
145
146     if(poll(&pfd, 1, 0) != 0) {
147         char c;
148
149         if(read(fd, &c, 1) != 1)
150             return -2;
151
152         if(c == '\x03') // ^C
153             return 1;
154     }
155
156     return 0;
157 }
158