Align loader to 32-bit boundary
[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     unsigned int data_length = strlen(data);
22     int length = data_length + 4;
23     char* packet = malloc(length); /* '$' data (hex) '#' cksum (hex) */
24
25     memset(packet, 0, length);
26
27     packet[0] = '$';
28
29     uint8_t cksum = 0;
30     for(unsigned int i = 0; i < data_length; i++) {
31         packet[i + 1] = data[i];
32         cksum += data[i];
33     }
34
35     packet[length - 3] = '#';
36     packet[length - 2] = hex[cksum >> 4];
37     packet[length - 1] = hex[cksum & 0xf];
38
39     while(1) {
40         if(write(fd, packet, length) != length) {
41             free(packet);
42             return -2;
43         }
44
45         char ack;
46         if(read(fd, &ack, 1) != 1) {
47             free(packet);
48             return -2;
49         }
50
51         if(ack == '+') {
52             free(packet);
53             return 0;
54         }
55     }
56 }
57
58 #define ALLOC_STEP 1024
59
60 int gdb_recv_packet(int fd, char** buffer) {
61     unsigned packet_size = ALLOC_STEP + 1, packet_idx = 0;
62     uint8_t cksum = 0;
63     char recv_cksum[3] = {0};
64     char* packet_buffer = malloc(packet_size);
65     unsigned state;
66
67 start:
68     state = 0;
69     /*
70      * 0: waiting $
71      * 1: data, waiting #
72      * 2: cksum 1
73      * 3: cksum 2
74      * 4: fin
75      */
76
77     char c;
78     while(state != 4) {
79         if(read(fd, &c, 1) != 1) {
80             return -2;
81         }
82
83         switch(state) {
84         case 0:
85             if(c != '$') {
86                 // ignore
87             } else {
88                 state = 1;
89             }
90             break;
91
92         case 1:
93             if(c == '#') {
94                 state = 2;
95             } else {
96                 packet_buffer[packet_idx++] = c;
97                 cksum += c;
98
99                 if(packet_idx == packet_size) {
100                     packet_size += ALLOC_STEP;
101                     packet_buffer = realloc(packet_buffer, packet_size);
102                 }
103             }
104             break;
105
106         case 2:
107             recv_cksum[0] = c;
108             state = 3;
109             break;
110
111         case 3:
112             recv_cksum[1] = c;
113             state = 4;
114             break;
115         }
116     }
117
118     uint8_t recv_cksum_int = strtoul(recv_cksum, NULL, 16);
119     if(recv_cksum_int != cksum) {
120         char nack = '-';
121         if(write(fd, &nack, 1) != 1) {
122             return -2;
123         }
124
125         goto start;
126     } else {
127         char ack = '+';
128         if(write(fd, &ack, 1) != 1) {
129             return -2;
130         }
131     }
132
133     packet_buffer[packet_idx] = 0;
134     *buffer = packet_buffer;
135
136     return packet_idx;
137 }
138
139 // Here we skip any characters which are not \x03, GDB interrupt.
140 // As we use the mode with ACK, in a (very unlikely) situation of a packet
141 // lost because of this skipping, it will be resent anyway.
142 int gdb_check_for_interrupt(int fd) {
143     struct pollfd pfd;
144     pfd.fd = fd;
145     pfd.events = POLLIN;
146
147     if(poll(&pfd, 1, 0) != 0) {
148         char c;
149
150         if(read(fd, &c, 1) != 1)
151             return -2;
152
153         if(c == '\x03') // ^C
154             return 1;
155     }
156
157     return 0;
158 }
159