Rizin
unix-like reverse engineering framework and cli tools
packet.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2014-2016 defragger <rlaemmert@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include "packet.h"
5 #include "utils.h"
6 
7 #define READ_TIMEOUT (250 * 1000)
8 
9 enum {
10  HEADER = 1 << 0,
11  CHKSUM = 1 << 1,
12  DUP = 1 << 2,
13  ESC = 1 << 3,
14 };
15 
16 struct parse_ctx {
21 };
22 
23 static bool append(libgdbr_t *g, const char ch) {
24  char *ptr;
25  if (g->data_len == g->data_max - 1) {
26  int newsize = g->data_max * 2;
27  if (newsize < 1) {
28  return false;
29  }
30  ptr = realloc(g->data, newsize);
31  if (!ptr) {
32  eprintf("%s: Failed to reallocate buffer\n",
33  __func__);
34  return false;
35  }
36  g->data = ptr;
37  g->data_max = newsize;
38  }
39  g->data[g->data_len++] = ch;
40  return true;
41 }
42 
43 static int unpack(libgdbr_t *g, struct parse_ctx *ctx, int len) {
44  int i = 0;
45  int j = 0;
46  bool first = true;
47  g->read_buff[len] = '\0';
48  for (i = 0; i < len; i++) {
49  char cur = g->read_buff[i];
50  if (ctx->flags & CHKSUM) {
51  ctx->sum -= hex2int(cur) << (ctx->chksum_nibble * 4);
52  if (!--ctx->chksum_nibble) {
53  continue;
54  }
55  if (ctx->sum != '#') {
56  eprintf("%s: Invalid checksum\n", __func__);
57  return -1;
58  }
59  if (i != len - 1) {
60  if (g->read_buff[i + 1] == '$' ||
61  (g->read_buff[i + 1] == '+' && g->read_buff[i + 2] == '$')) {
62  // Packets clubbed together
63  g->read_len = len - i - 1;
64  memcpy(g->read_buff, g->read_buff + i + 1, g->read_len);
65  g->read_buff[g->read_len] = '\0';
66  return 0;
67  }
68  eprintf("%s: Garbage at end of packet: %s (%s)\n",
69  __func__, g->read_buff + i + 1, g->read_buff + i + 1);
70  }
71  g->read_len = 0;
72  return 0;
73  }
74  ctx->sum += cur;
75  if (ctx->flags & ESC) {
76  if (!append(g, cur ^ 0x20)) {
77  return -1;
78  }
79  ctx->flags &= ~ESC;
80  continue;
81  }
82  if (ctx->flags & DUP) {
83  if (cur < 32 || cur > 126) {
84  eprintf("%s: Invalid repeat count: %d\n",
85  __func__, cur);
86  return -1;
87  }
88  for (j = cur - 29; j > 0; j--) {
89  if (!append(g, ctx->last)) {
90  return -1;
91  }
92  }
93  ctx->last = 0;
94  ctx->flags &= ~DUP;
95  continue;
96  }
97  switch (cur) {
98  case '$':
99  if (ctx->flags & HEADER) {
100  eprintf("%s: More than one $\n", __func__);
101  return -1;
102  }
103  ctx->flags |= HEADER;
104  /* Disregard any characters preceding $ */
105  ctx->sum = 0;
106  break;
107  case '#':
108  ctx->flags |= CHKSUM;
109  ctx->chksum_nibble = 1;
110  break;
111  case '}':
112  ctx->flags |= ESC;
113  break;
114  case '*':
115  if (first) {
116  eprintf("%s: Invalid repeat\n", __func__);
117  return -1;
118  }
119  ctx->flags |= DUP;
120  break;
121  case '+':
122  case '-':
123  if (!(ctx->flags & HEADER)) {
124  /* TODO: Handle acks/nacks */
125  if (g->server_debug && !g->no_ack) {
126  eprintf("[received '%c' (0x%x)]\n", cur,
127  (int)cur);
128  }
129  break;
130  }
131  /* Fall-through */
132  default:
133  first = false;
134  if (!append(g, cur)) {
135  return -1;
136  }
137  ctx->last = cur;
138  }
139  }
140  return 1;
141 }
142 
143 int read_packet(libgdbr_t *g, bool vcont) {
144  struct parse_ctx ctx = { 0 };
145  int ret, i;
146  if (!g) {
147  eprintf("Initialize libgdbr_t first\n");
148  return -1;
149  }
150  g->data_len = 0;
151  if (g->read_len > 0) {
152  if (unpack(g, &ctx, g->read_len) == 0) {
153  // TODO: Evaluate if partial packets are clubbed
154  g->data[g->data_len] = '\0';
155  if (g->server_debug) {
156  eprintf("getpkt (\"%s\"); %s\n", g->data,
157  g->no_ack ? "[no ack sent]" : "[sending ack]");
158  }
159  return 0;
160  }
161  }
162  g->data_len = 0;
163  for (i = 0; i < g->num_retries && !g->isbreaked; vcont ? 0 : i++) {
164  ret = rz_socket_ready(g->sock, 0, READ_TIMEOUT);
165  if (ret == 0 && !vcont) {
166  continue;
167  }
168  if (ret <= 0) {
169  return -1;
170  }
171  int sz = rz_socket_read(g->sock, (void *)g->read_buff, g->read_max - 1);
172  if (sz <= 0) {
173  eprintf("%s: read failed\n", __func__);
174  return -1;
175  }
176  ret = unpack(g, &ctx, sz);
177  if (ret < 0) {
178  eprintf("%s: unpack failed\n", __func__);
179  return -1;
180  }
181  if (!ret) {
182  g->data[g->data_len] = '\0';
183  if (g->server_debug) {
184  eprintf("getpkt (\"%s\"); %s\n", g->data,
185  g->no_ack ? "[no ack sent]" : "[sending ack]");
186  }
187  return 0;
188  }
189  }
190  return -1;
191 }
192 
194  if (!g) {
195  eprintf("Initialize libgdbr_t first\n");
196  return -1;
197  }
198  if (g->server_debug) {
199  g->send_buff[g->send_len] = '\0';
200  eprintf("putpkt (\"%s\"); %s\n", g->send_buff,
201  g->no_ack ? "[noack mode]" : "[looking for ack]");
202  }
203  return rz_socket_write(g->sock, g->send_buff, g->send_len);
204 }
205 
206 int pack(libgdbr_t *g, const char *msg) {
207  int run_len;
208  size_t msg_len;
209  const char *src;
210  char prev;
211  if (!g || !msg) {
212  return -1;
213  }
214  msg_len = strlen(msg);
215  if (msg_len > g->send_max + 5) {
216  eprintf("%s: message too long: %s", __func__, msg);
217  return -1;
218  }
219  if (!g->send_buff) {
220  return -1;
221  }
222  g->send_buff[0] = '$';
223  g->send_len = 1;
224  src = msg;
225  while (*src) {
226  if (*src == '#' || *src == '$' || *src == '}') {
227  msg_len += 1;
228  if (msg_len > g->send_max + 5) {
229  eprintf("%s: message too long: %s", __func__, msg);
230  return -1;
231  }
232  g->send_buff[g->send_len++] = '}';
233  g->send_buff[g->send_len++] = *src++ ^ 0x20;
234  continue;
235  }
236  g->send_buff[g->send_len++] = *src++;
237  if (!g->is_server) {
238  continue;
239  }
240  prev = *(src - 1);
241  run_len = 0;
242  while (src[run_len] == prev) {
243  run_len++;
244  }
245  if (run_len < 3) { // 3 specified in RSP documentation
246  while (run_len--) {
247  g->send_buff[g->send_len++] = *src++;
248  }
249  continue;
250  }
251  run_len += 29; // Encode as printable character
252  if (run_len == 35 || run_len == 36) { // Cannot use '$' or '#'
253  run_len = 34;
254  } else if (run_len > 126) { // Max printable ascii value
255  run_len = 126;
256  }
257  g->send_buff[g->send_len++] = '*';
258  g->send_buff[g->send_len++] = run_len;
259  msg_len -= run_len - 27; // 2 chars to encode run length
260  src += run_len - 29;
261  }
262  g->send_buff[g->send_len] = '\0';
263  snprintf(g->send_buff + g->send_len, 4, "#%.2x", cmd_checksum(g->send_buff + 1));
264  g->send_len += 3;
265  return g->send_len;
266 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
lzma_index * src
Definition: index.h:567
uint32_t ut32
struct @667 g
snprintf
Definition: kernel.h:364
uint8_t ut8
Definition: lh5801.h:11
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
#define eprintf(x, y...)
Definition: rlcc.c:7
RZ_API int rz_socket_ready(RzSocket *s, int secs, int usecs)
Definition: socket.c:688
RZ_API void RZ_API int rz_socket_read(RzSocket *s, ut8 *read, int len)
Definition: socket.c:783
RZ_API int rz_socket_write(RzSocket *s, void *buf, int len)
Definition: socket.c:724
#define READ_TIMEOUT
Definition: packet.c:7
int read_packet(libgdbr_t *g, bool vcont)
Function reads data from the established connection.
Definition: packet.c:143
int send_packet(libgdbr_t *g)
sends a packet sends a packet to the established connection
Definition: packet.c:193
int pack(libgdbr_t *g, const char *msg)
Definition: packet.c:206
@ CHKSUM
Definition: packet.c:11
@ HEADER
Definition: packet.c:10
@ DUP
Definition: packet.c:12
@ ESC
Definition: packet.c:13
static bool append(libgdbr_t *g, const char ch)
Definition: packet.c:23
static int unpack(libgdbr_t *g, struct parse_ctx *ctx, int len)
Definition: packet.c:43
static struct sockaddr static addrlen static backlog const void msg
Definition: sfsocketcall.h:119
ut32 flags
Definition: packet.c:17
int chksum_nibble
Definition: packet.c:20
ut8 last
Definition: packet.c:18
ut8 sum
Definition: packet.c:19
uint8_t cmd_checksum(const char *command)
Definition: utils.c:16
int hex2int(int ch)
Definition: utils.c:61