Rizin
unix-like reverse engineering framework and cli tools
packet.c File Reference
#include "packet.h"
#include "utils.h"

Go to the source code of this file.

Classes

struct  parse_ctx
 

Macros

#define READ_TIMEOUT   (250 * 1000)
 

Enumerations

enum  { HEADER = 1 << 0 , CHKSUM = 1 << 1 , DUP = 1 << 2 , ESC = 1 << 3 }
 

Functions

static bool append (libgdbr_t *g, const char ch)
 
static int unpack (libgdbr_t *g, struct parse_ctx *ctx, int len)
 
int read_packet (libgdbr_t *g, bool vcont)
 Function reads data from the established connection. More...
 
int send_packet (libgdbr_t *g)
 sends a packet sends a packet to the established connection More...
 
int pack (libgdbr_t *g, const char *msg)
 

Macro Definition Documentation

◆ READ_TIMEOUT

#define READ_TIMEOUT   (250 * 1000)

Definition at line 7 of file packet.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
HEADER 
CHKSUM 
DUP 
ESC 

Definition at line 9 of file packet.c.

9  {
10  HEADER = 1 << 0,
11  CHKSUM = 1 << 1,
12  DUP = 1 << 2,
13  ESC = 1 << 3,
14 };
@ CHKSUM
Definition: packet.c:11
@ HEADER
Definition: packet.c:10
@ DUP
Definition: packet.c:12
@ ESC
Definition: packet.c:13

Function Documentation

◆ append()

static bool append ( libgdbr_t g,
const char  ch 
)
static

Definition at line 23 of file packet.c.

23  {
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 }
struct @667 g
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
#define eprintf(x, y...)
Definition: rlcc.c:7

References eprintf, g, and realloc().

Referenced by unpack().

◆ pack()

int pack ( libgdbr_t g,
const char *  msg 
)

Definition at line 206 of file packet.c.

206  {
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 }
lzma_index * src
Definition: index.h:567
snprintf
Definition: kernel.h:364
static struct sockaddr static addrlen static backlog const void msg
Definition: sfsocketcall.h:119
uint8_t cmd_checksum(const char *command)
Definition: utils.c:16

References cmd_checksum(), eprintf, g, msg, snprintf, and src.

Referenced by send_msg(), xprint::to_x(), and xprint::to_x_32().

◆ read_packet()

int read_packet ( libgdbr_t g,
bool  vcont 
)

Function reads data from the established connection.

Parameters
gthe "instance" of the current libgdbr session
vcontwhether it's called to receive reply to a vcont packet
Returns
a failure code (currently -1) or 0 if call successfully

Definition at line 143 of file packet.c.

143  {
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 }
lzma_index ** i
Definition: index.h:629
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
#define READ_TIMEOUT
Definition: packet.c:7
static int unpack(libgdbr_t *g, struct parse_ctx *ctx, int len)
Definition: packet.c:43

References eprintf, g, i, READ_TIMEOUT, rz_socket_read(), rz_socket_ready(), and unpack().

Referenced by __system(), gdbr_attach(), gdbr_check_extended_mode(), gdbr_check_vcont(), gdbr_close_file(), gdbr_connect(), gdbr_connect_lldb(), gdbr_detach_pid(), gdbr_exec_file_read(), gdbr_get_baddr(), gdbr_is_thread_dead(), gdbr_kill_pid(), gdbr_open_file(), gdbr_pids_list(), gdbr_read_feature(), gdbr_read_file(), gdbr_read_memory_page(), gdbr_read_osdata(), gdbr_read_registers(), gdbr_read_registers_lldb(), gdbr_select(), gdbr_send_qRcmd(), gdbr_server_serve(), gdbr_stop_reason(), gdbr_threads_list(), gdbr_write_bin_registers(), gdbr_write_memory(), gdbr_write_register(), gdbr_write_registers(), remove_bp(), send_vcont(), set_bp(), and test_command().

◆ send_packet()

int send_packet ( libgdbr_t g)

sends a packet sends a packet to the established connection

Parameters
gthe "instance" of the current libgdbr session
Returns
a failure code (currently -1) or 0 if call successfully

Definition at line 193 of file packet.c.

193  {
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 }
RZ_API int rz_socket_write(RzSocket *s, void *buf, int len)
Definition: socket.c:724

References eprintf, g, and rz_socket_write().

Referenced by send_msg().

◆ unpack()

static int unpack ( libgdbr_t g,
struct parse_ctx ctx,
int  len 
)
static

Definition at line 43 of file packet.c.

43  {
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 }
size_t len
Definition: 6502dis.c:15
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
static bool append(libgdbr_t *g, const char ch)
Definition: packet.c:23
int hex2int(int ch)
Definition: utils.c:61

References append(), CHKSUM, DUP, eprintf, ESC, g, HEADER, hex2int(), i, len, and memcpy().

Referenced by read_packet(), objdump-m68k::s16(), and objdump-m68k::s8().