| 167 | /* High-level send/receive functions. */ |
| 168 | |
| 169 | void gdb_get_command(struct gdb_message *command) |
| 170 | { |
| 171 | enum command_state { |
| 172 | STATE_WAITING, |
| 173 | STATE_COMMAND, |
| 174 | STATE_CHECKSUM0, |
| 175 | STATE_CHECKSUM1, |
| 176 | }; |
| 177 | |
| 178 | u8 checksum = 0; |
| 179 | u8 running_checksum = 0; |
| 180 | enum command_state state = STATE_WAITING; |
| 181 | |
| 182 | while (1) { |
| 183 | int c = gdb_raw_getchar(); |
| 184 | if (c < 0) { |
| 185 | /* |
| 186 | * Timeout waiting for a byte. Reset the |
| 187 | * state machine. |
| 188 | */ |
| 189 | state = STATE_WAITING; |
| 190 | continue; |
| 191 | } |
| 192 | |
| 193 | switch (state) { |
| 194 | case STATE_WAITING: |
| 195 | if (c == '$') { |
| 196 | running_checksum = 0; |
| 197 | command->used = 0; |
| 198 | state = STATE_COMMAND; |
| 199 | } |
| 200 | break; |
| 201 | case STATE_COMMAND: |
| 202 | if (c == '#') { |
| 203 | state = STATE_CHECKSUM0; |
| 204 | break; |
| 205 | } |
| 206 | die_if(command->used >= command->size, "GDB input buf" |
| 207 | "fer overrun (try increasing command.size)!\n"); |
| 208 | command->buf[command->used++] = c; |
| 209 | running_checksum += c; |
| 210 | break; |
| 211 | case STATE_CHECKSUM0: |
| 212 | checksum = from_hex(c) << 4; |
| 213 | state = STATE_CHECKSUM1; |
| 214 | break; |
| 215 | case STATE_CHECKSUM1: |
| 216 | checksum += from_hex(c); |
| 217 | if (running_checksum == checksum) { |
| 218 | gdb_raw_putchar('+'); |
| 219 | return; |
| 220 | } else { |
| 221 | state = STATE_WAITING; |
| 222 | gdb_raw_putchar('-'); |
| 223 | } |
| 224 | break; |
| 225 | } |
| 226 | } |
no test coverage detected