Rizin
unix-like reverse engineering framework and cli tools
xml.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2017-2018 srimanta.barua1 <srimanta.barua1@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include "gdbclient/xml.h"
5 #include "gdbclient/commands.h"
6 #include "gdbclient/core.h"
7 #include "arch.h"
8 #include "gdbr_common.h"
9 #include "packet.h"
10 #include <rz_util.h>
11 #include <rz_debug.h>
12 
13 #define MAX_PID_CHARS (5)
14 
15 static char *gdbr_read_feature(libgdbr_t *g, const char *file, ut64 *tot_len) {
16  ut64 retlen = 0, retmax = 0, off = 0, len = g->stub_features.pkt_sz - 2,
17  blksz = g->data_max, subret_space = 0, subret_len = 0;
18  char *tmp, *tmp2, *tmp3, *ret = NULL, *subret = NULL, msg[128] = { 0 },
19  status, tmpchar;
20  while (1) {
21  snprintf(msg, sizeof(msg), "qXfer:features:read:%s:%" PFMT64x ",%" PFMT64x, file, off, len);
22  if (send_msg(g, msg) < 0 || read_packet(g, false) < 0 || send_ack(g) < 0) {
23  goto exit_err;
24  }
25  if (g->data_len == 0) {
26  goto exit_err;
27  }
28  if (g->data_len == 1 && g->data[0] == 'l') {
29  break;
30  }
31  status = g->data[0];
32  if (retmax - retlen < g->data_len) {
33  if (!(tmp = realloc(ret, retmax + blksz))) {
34  goto exit_err;
35  }
36  retmax += blksz;
37  ret = tmp;
38  }
39  strcpy(ret + retlen, g->data + 1);
40  retlen += g->data_len - 1;
41  off = retlen;
42  if (status == 'l') {
43  break;
44  }
45  if (status != 'm') {
46  goto exit_err;
47  }
48  }
49  if (!ret) {
50  *tot_len = 0;
51  return NULL;
52  }
53  tmp = strstr(ret, "<xi:include");
54  while (tmp) {
55  // inclusion
56  if (!(tmp2 = strstr(tmp, "/>"))) {
57  goto exit_err;
58  }
59  subret_space = tmp2 + 2 - tmp;
60  if (!(tmp2 = strstr(tmp, "href="))) {
61  goto exit_err;
62  }
63  tmp2 += 6;
64  if (!(tmp3 = strchr(tmp2, '"'))) {
65  goto exit_err;
66  }
67  tmpchar = *tmp3;
68  *tmp3 = '\0';
69  subret = gdbr_read_feature(g, tmp2, &subret_len);
70  *tmp3 = tmpchar;
71  if (subret) {
72  if (subret_len <= subret_space) {
73  memcpy(tmp, subret, subret_len);
74  memcpy(tmp + subret_len, tmp + subret_space,
75  retlen - (tmp + subret_space - ret));
76  retlen -= subret_space - subret_len;
77  ret[retlen] = '\0';
78  tmp = strstr(tmp3, "<xi:include");
79  free(subret);
80  continue;
81  }
82  if (subret_len > retmax - retlen - 1) {
83  tmp3 = NULL;
84  if (!(tmp3 = realloc(ret, retmax + subret_len))) {
85  free(subret);
86  goto exit_err;
87  }
88  tmp = tmp3 + (tmp - ret);
89  ret = tmp3;
90  retmax += subret_len + 1;
91  }
92  memmove(tmp + subret_len, tmp + subret_space,
93  retlen - (tmp + subret_space - ret));
94  memcpy(tmp, subret, subret_len);
95  retlen += subret_len - subret_space;
96  ret[retlen] = '\0';
97  free(subret);
98  }
99  tmp = strstr(tmp3, "<xi:include");
100  }
101  *tot_len = retlen;
102  return ret;
103 exit_err:
104  free(ret);
105  *tot_len = 0;
106  return NULL;
107 }
108 
109 static char *gdbr_read_osdata(libgdbr_t *g, const char *file, ut64 *tot_len) {
110  ut64 retlen = 0, retmax = 0, off = 0, len = g->stub_features.pkt_sz - 2,
111  blksz = g->data_max;
112  char *tmp, *ret = NULL, msg[128] = { 0 }, status;
113  while (1) {
114  snprintf(msg, sizeof(msg), "qXfer:osdata:read:%s:%" PFMT64x ",%" PFMT64x, file, off, len);
115  if (send_msg(g, msg) < 0 || read_packet(g, false) < 0 || send_ack(g) < 0) {
116  goto exit_err;
117  }
118  if (g->data_len == 0) {
119  goto exit_err;
120  }
121  if (g->data_len == 1 && g->data[0] == 'l') {
122  break;
123  }
124  status = g->data[0];
125  if (retmax - retlen < g->data_len) {
126  if (!(tmp = realloc(ret, retmax + blksz))) {
127  goto exit_err;
128  }
129  retmax += blksz;
130  ret = tmp;
131  }
132  strcpy(ret + retlen, g->data + 1);
133  retlen += g->data_len - 1;
134  off = retlen;
135  if (status == 'l') {
136  break;
137  }
138  }
139  if (!ret) {
140  *tot_len = 0;
141  return NULL;
142  }
143  *tot_len = retlen;
144  return ret;
145 exit_err:
146  free(ret);
147  *tot_len = 0;
148  return NULL;
149 }
150 
151 typedef struct {
152  char type[32];
153  struct {
154  char name[32];
156  ut32 sz; // size in bits
157  } fields[64];
161 
162 typedef struct {
163  char name[32];
164  char type[8];
168 
169 static void _write_flag_bits(char *buf, const gdbr_xml_flags_t *flags);
170 static int _resolve_arch(libgdbr_t *g, char *xml_data);
171 static RzList *_extract_flags(char *flagstr);
172 static RzList *_extract_regs(char *regstr, RzList *flags, char *pc_alias);
173 static RzDebugPid *_extract_pid_info(const char *info, const char *path, int tid);
174 
175 static int gdbr_parse_target_xml(libgdbr_t *g, char *xml_data, ut64 len) {
176  char *regstr, *flagstr, *tmp, *profile = NULL, pc_alias[64], flag_bits[65];
177  RzList *flags, *regs;
178  RzListIter *iter;
179  gdbr_xml_flags_t *tmpflag;
180  gdbr_xml_reg_t *tmpreg;
181  int packed_size = 0;
182  ut64 profile_len = 0, profile_max_len, regnum = 0, regoff = 0;
183  pc_alias[0] = '\0';
184  gdb_reg_t *arch_regs = NULL;
185  if (_resolve_arch(g, xml_data) < 0) {
186  return -1;
187  }
188  if (!(flagstr = strstr(xml_data, "<feature"))) {
189  return -1;
190  }
191  regstr = flagstr;
192  if (!(flags = _extract_flags(flagstr))) {
193  return -1;
194  }
195  if (!(regs = _extract_regs(regstr, flags, pc_alias))) {
197  return -1;
198  }
199  if (!(arch_regs = malloc(sizeof(gdb_reg_t) * (rz_list_length(regs) + 1)))) {
200  goto exit_err;
201  }
202  // approximate per-reg size estimates
203  profile_max_len = rz_list_length(regs) * 128 + rz_list_length(flags) * 128;
204  if (!(profile = malloc(profile_max_len))) {
205  goto exit_err;
206  }
207  rz_list_foreach (regs, iter, tmpreg) {
208  if (!tmpreg) {
209  continue;
210  }
211  memcpy(arch_regs[regnum].name, tmpreg->name, sizeof(tmpreg->name));
212  arch_regs[regnum].size = tmpreg->size;
213  arch_regs[regnum].offset = regoff;
214  if (profile_len + 128 >= profile_max_len) {
215  if (!(tmp = realloc(profile, profile_max_len + 512))) {
216  goto exit_err;
217  }
218  profile = tmp;
219  profile_max_len += 512;
220  }
221  flag_bits[0] = '\0';
222  tmpflag = NULL;
223  if (tmpreg->flagnum < rz_list_length(flags)) {
224  tmpflag = rz_list_get_n(flags, tmpreg->flagnum);
225  _write_flag_bits(flag_bits, tmpflag);
226  }
227  packed_size = 0;
228  if (tmpreg->size >= 64 &&
229  (strstr(tmpreg->type, "fpu") ||
230  strstr(tmpreg->type, "mmx") ||
231  strstr(tmpreg->type, "xmm") ||
232  strstr(tmpreg->type, "ymm"))) {
233  packed_size = tmpreg->size / 8;
234  }
235  profile_len += snprintf(profile + profile_len, 128,
236  "%s\t%s\t.%u\t.%" PFMT64d "\t%d\t%s\n", tmpreg->type,
237  tmpreg->name, tmpreg->size, regoff,
238  packed_size,
239  flag_bits);
240  // TODO write flag subregisters
241  if (tmpflag) {
242  int i;
243  for (i = 0; i < tmpflag->num_fields; i++) {
244  if (profile_len + 128 >= profile_max_len) {
245  if (!(tmp = realloc(profile, profile_max_len + 512))) {
246  goto exit_err;
247  }
248  profile = tmp;
249  profile_max_len += 512;
250  }
251  profile_len += snprintf(profile + profile_len, 128, "gpr\t%s\t"
252  ".%u\t.%" PFMT64d "\t0\n",
253  tmpflag->fields[i].name,
254  tmpflag->fields[i].sz, tmpflag->fields[i].bit_num + regoff);
255  }
256  }
257  regnum++;
258  regoff += tmpreg->size;
259  }
260  // Difficult to parse these out from xml. So manually added from gdb's xml files
261  switch (g->target.arch) {
262  case RZ_SYS_ARCH_ARM:
263  switch (g->target.bits) {
264  case 32:
265  if (!(profile = rz_str_prepend(profile,
266  "=PC pc\n"
267  "=SP sp\n" // XXX
268  "=A0 r0\n"
269  "=A1 r1\n"
270  "=A2 r2\n"
271  "=A3 r3\n"))) {
272  goto exit_err;
273  }
274  break;
275  case 64:
276  if (!(profile = rz_str_prepend(profile,
277  "=PC pc\n"
278  "=SP sp\n"
279  "=BP x29\n"
280  "=A0 x0\n"
281  "=A1 x1\n"
282  "=A2 x2\n"
283  "=A3 x3\n"
284  "=ZF zf\n"
285  "=SF nf\n"
286  "=OF vf\n"
287  "=CF cf\n"
288  "=SN x8\n"))) {
289  goto exit_err;
290  }
291  }
292  break;
293  case RZ_SYS_ARCH_X86:
294  switch (g->target.bits) {
295  case 32:
296  if (!(profile = rz_str_prepend(profile,
297  "=PC eip\n"
298  "=SP esp\n"
299  "=BP ebp\n"))) {
300  goto exit_err;
301  }
302  break;
303  case 64:
304  if (!(profile = rz_str_prepend(profile,
305  "=PC rip\n"
306  "=SP rsp\n"
307  "=BP rbp\n"))) {
308  goto exit_err;
309  }
310  }
311  break;
312  case RZ_SYS_ARCH_MIPS:
313  if (!(profile = rz_str_prepend(profile,
314  "=PC pc\n"
315  "=SP r29\n"))) {
316  goto exit_err;
317  }
318  break;
319  default:
320  // TODO others
321  if (*pc_alias) {
322  if (!(profile = rz_str_prepend(profile, pc_alias))) {
323  goto exit_err;
324  }
325  }
326  }
327  // Special case for MIPS, since profile doesn't separate 32/64 bit MIPS
328  if (g->target.arch == RZ_SYS_ARCH_MIPS) {
329  if (arch_regs && arch_regs[0].size == 8) {
330  g->target.bits = 64;
331  }
332  }
335  RZ_FREE(g->target.regprofile);
336  if (profile) {
337  g->target.regprofile = strdup(profile);
338  free(profile);
339  }
340  g->target.valid = true;
341  g->registers = arch_regs;
342  return 0;
343 
344 exit_err:
347  free(profile);
348  free(arch_regs);
349  return -1;
350 }
351 
352 /* Reference:
353 <osdata type="processes">
354 <item>
355 <column name="pid">1</column>
356 <column name="user">root</column>
357 <column name="command">/sbin/init maybe-ubiquity </column>
358 <column name="cores">0</column>
359 </item>
360 </osdata>
361 */
362 static int gdbr_parse_processes_xml(libgdbr_t *g, char *xml_data, ut64 len, int pid, RzList *list) {
363  char pidstr[MAX_PID_CHARS + 1], status[1024], cmdline[1024];
364  char *itemstr, *column, *column_end, *proc_filename;
365  int ret = -1, ipid, column_data_len;
366  RzDebugPid *pid_info = NULL;
367 
368  // Make sure the given xml is valid
369  if (!rz_str_startswith(xml_data, "<osdata type=\"processes\">")) {
370  ret = -1;
371  goto end;
372  }
373 
374  column = xml_data;
375  while ((itemstr = strstr(column, "<item>"))) {
376  if (!strstr(itemstr, "</item>")) {
377  ret = -1;
378  goto end;
379  }
380  // Get PID
381  if (!(column = strstr(itemstr, "<column name=\"pid\">"))) {
382  ret = -1;
383  goto end;
384  }
385  if (!(column_end = strstr(column, "</column>"))) {
386  ret = -1;
387  goto end;
388  }
389 
390  column += sizeof("<column name=\"pid\">") - 1;
391  column_data_len = column_end - column;
392 
393  memcpy(pidstr, column, column_data_len);
394  pidstr[column_data_len] = '\0';
395 
396  ipid = atoi(pidstr);
397 
398  // Get cmdline
399  if (!(column = strstr(itemstr, "<column name=\"command\">"))) {
400  ret = -1;
401  goto end;
402  }
403  if (!(column_end = strstr(column, "</column>"))) {
404  ret = -1;
405  goto end;
406  }
407 
408  column += sizeof("<column name=\"command\">") - 1;
409  column_data_len = column_end - column;
410 
411  memcpy(cmdline, column, column_data_len);
412  cmdline[column_data_len] = '\0';
413 
414  // Attempt to read the pid's info from /proc. Non UNIX systems will have the
415  // correct pid and cmdline from the xml with everything else set to default
416  proc_filename = rz_str_newf("/proc/%d/status", ipid);
417  if (gdbr_open_file(g, proc_filename, O_RDONLY, 0) == 0) {
418  if (gdbr_read_file(g, (unsigned char *)status, sizeof(status)) != -1) {
419  pid_info = _extract_pid_info(status, cmdline, ipid);
420  } else {
421  eprintf("Failed to read from data from procfs file of pid (%d)\n", ipid);
422  }
423  if (gdbr_close_file(g) != 0) {
424  eprintf("Failed to close procfs file of pid (%d)\n", ipid);
425  }
426  } else {
427  eprintf("Failed to open procfs file of pid (%d)\n", ipid);
428  if (!(pid_info = RZ_NEW0(RzDebugPid)) || !(pid_info->path = strdup(cmdline))) {
429  ret = -1;
430  goto end;
431  }
432  pid_info->pid = ipid;
433  pid_info->ppid = 0;
434  pid_info->uid = pid_info->gid = -1;
435  pid_info->runnable = true;
436  pid_info->status = RZ_DBG_PROC_STOP;
437  }
438  // Unless pid 0 is requested, only add the requested pid and it's child processes
439  if (0 == pid || ipid == pid || pid_info->ppid == pid) {
440  rz_list_append(list, pid_info);
441  } else {
442  if (pid_info) {
443  free(pid_info);
444  pid_info = NULL;
445  }
446  }
447  }
448 
449  ret = 0;
450 end:
451  if (ret != 0) {
452  if (pid_info) {
453  free(pid_info);
454  }
455  }
456  return ret;
457 }
458 
459 // If xml target description is supported, read it
461  if (!g->stub_features.qXfer_features_read) {
462  return -1;
463  }
464  char *data;
465  ut64 len;
466  if (!(data = gdbr_read_feature(g, "target.xml", &len))) {
467  return -1;
468  }
469  gdbr_parse_target_xml(g, data, len);
470  free(data);
471  return 0;
472 }
473 
475  if (!g->stub_features.qXfer_features_read) {
476  return -1;
477  }
478  ut64 len;
479  int ret = -1;
480  char *data;
481 
482  if (!(data = gdbr_read_osdata(g, "processes", &len))) {
483  ret = -1;
484  goto end;
485  }
486 
487  if (gdbr_parse_processes_xml(g, data, len, pid, list) != 0) {
488  ret = -1;
489  goto end;
490  }
491 
492  ret = 0;
493 end:
494  if (data) {
495  free(data);
496  }
497  return ret;
498 }
499 
500 // sizeof (buf) needs to be atleast flags->num_bits + 1
501 static void _write_flag_bits(char *buf, const gdbr_xml_flags_t *flags) {
502  bool fc[26] = { false };
503  ut32 i, c;
504  memset(buf, '.', flags->num_bits);
505  buf[flags->num_bits] = '\0';
506  for (i = 0; i < flags->num_fields; i++) {
507  // How do we show multi-bit flags?
508  if (flags->fields[i].sz != 1) {
509  continue;
510  }
511  // To avoid duplicates. This skips flags if first char is same. i.e.
512  // for x86_64, it will skip VIF because VM already occurred. This is
513  // same as default reg-profiles in r2
514  c = tolower(flags->fields[i].name[0]) - 'a';
515  if (fc[c]) {
516  continue;
517  }
518  fc[c] = true;
519  buf[flags->fields[i].bit_num] = 'a' + c;
520  }
521 }
522 
523 static int _resolve_arch(libgdbr_t *g, char *xml_data) {
524  char *arch;
525  // Find architecture
526  g->target.arch = RZ_SYS_ARCH_NONE;
527  if ((arch = strstr(xml_data, "<architecture"))) {
528  if (!(arch = strchr(arch, '>'))) {
529  return -1;
530  }
531  arch++;
532  if (rz_str_startswith(arch, "i386")) {
533  g->target.arch = RZ_SYS_ARCH_X86;
534  g->target.bits = 32;
535  arch += 4;
536  if (rz_str_startswith(arch, ":x86-64")) {
537  g->target.bits = 64;
538  }
539  } else if (rz_str_startswith(arch, "aarch64")) {
540  g->target.arch = RZ_SYS_ARCH_ARM;
541  g->target.bits = 64;
542  } else if (rz_str_startswith(arch, "arm")) {
543  g->target.arch = RZ_SYS_ARCH_ARM;
544  g->target.bits = 32;
545  } else if (rz_str_startswith(arch, "mips")) {
546  g->target.arch = RZ_SYS_ARCH_MIPS;
547  g->target.bits = 32;
548  }
549  // TODO others
550  } else {
551  // apple's debugserver on ios9
552  if (strstr(xml_data, "com.apple.debugserver.arm64")) {
553  g->target.arch = RZ_SYS_ARCH_ARM;
554  g->target.bits = 64;
555  } else if (strstr(xml_data, "org.gnu.gdb.riscv")) {
556  g->target.arch = RZ_SYS_ARCH_RISCV;
557  g->target.bits = 64;
558  } else if (strstr(xml_data, "org.gnu.gdb.mips")) {
559  // openocd mips?
560  g->target.arch = RZ_SYS_ARCH_MIPS;
561  g->target.bits = 32;
562  } else if (strstr(xml_data, "com.apple.debugserver.x86_64")) {
563  g->target.arch = RZ_SYS_ARCH_X86;
564  g->target.bits = 64;
565  } else {
566  eprintf("Warning: Unknown architecture parsing XML (%s)\n", xml_data);
567  }
568  }
569  return 0;
570 }
571 
572 static RzList *_extract_flags(char *flagstr) {
573  char *tmp1, *tmp2, *flagsend, *field_start, *field_end;
574  ut64 num_fields, type_sz, name_sz;
575  gdbr_xml_flags_t *tmpflag = NULL;
576  RzList *flags;
577  if (!(flags = rz_list_new())) {
578  return NULL;
579  }
580  flags->free = free;
581  while ((flagstr = strstr(flagstr, "<flags"))) {
582  if (!(flagsend = strstr(flagstr, "</flags>"))) {
583  goto exit_err;
584  }
585  *flagsend = '\0';
586  if (!(tmpflag = calloc(1, sizeof(gdbr_xml_flags_t)))) {
587  goto exit_err;
588  }
589  // Get id
590  if (!(tmp1 = strstr(flagstr, "id="))) {
591  goto exit_err;
592  }
593  tmp1 += 4;
594  if (!(tmp2 = strchr(tmp1, '"'))) {
595  goto exit_err;
596  }
597  *tmp2 = '\0';
598  type_sz = sizeof(tmpflag->type);
599  strncpy(tmpflag->type, tmp1, type_sz - 1);
600  tmpflag->type[type_sz - 1] = '\0';
601  *tmp2 = '"';
602  // Get size of flags register
603  if (!(tmp1 = strstr(flagstr, "size="))) {
604  goto exit_err;
605  }
606  tmp1 += 6;
607  if (!(tmpflag->num_bits = (ut32)strtoul(tmp1, NULL, 10))) {
608  goto exit_err;
609  }
610  tmpflag->num_bits *= 8;
611  // Get fields
612  num_fields = 0;
613  field_start = flagstr;
614  while ((field_start = strstr(field_start, "<field"))) {
615  // Max 64 fields
616  if (num_fields >= 64) {
617  break;
618  }
619  if (!(field_end = strstr(field_start, "/>"))) {
620  goto exit_err;
621  }
622  *field_end = '\0';
623  // Get name
624  if (!(tmp1 = strstr(field_start, "name="))) {
625  goto exit_err;
626  }
627  tmp1 += 6;
628  if (!(tmp2 = strchr(tmp1, '"'))) {
629  goto exit_err;
630  }
631  // If name length is 0, it is a 1 field. Don't include
632  if (tmp2 - tmp1 <= 1) {
633  *field_end = '/';
634  field_start = field_end + 1;
635  continue;
636  }
637  *tmp2 = '\0';
638  name_sz = sizeof(tmpflag->fields[num_fields].name);
639  strncpy(tmpflag->fields[num_fields].name, tmp1, name_sz - 1);
640  tmpflag->fields[num_fields].name[name_sz - 1] = '\0';
641  *tmp2 = '"';
642  // Get offset
643  if (!(tmp1 = strstr(field_start, "start="))) {
644  goto exit_err;
645  }
646  tmp1 += 7;
647  if (!isdigit(*tmp1)) {
648  goto exit_err;
649  }
650  tmpflag->fields[num_fields].bit_num = (ut32)strtoul(tmp1, NULL, 10);
651  // Get end
652  if (!(tmp1 = strstr(field_start, "end="))) {
653  goto exit_err;
654  }
655  tmp1 += 5;
656  if (!isdigit(*tmp1)) {
657  goto exit_err;
658  }
659  tmpflag->fields[num_fields].sz = (ut32)strtoul(tmp1, NULL, 10) + 1;
660  tmpflag->fields[num_fields].sz -= tmpflag->fields[num_fields].bit_num;
661  num_fields++;
662  *field_end = '/';
663  field_start = field_end + 1;
664  }
665  tmpflag->num_fields = num_fields;
666  rz_list_push(flags, tmpflag);
667  *flagsend = '<';
668  flagstr = flagsend + 1;
669  }
670  return flags;
671 exit_err:
672  if (flags) {
674  }
675  free(tmpflag);
676  return NULL;
677 }
678 
679 static RzDebugPid *_extract_pid_info(const char *info, const char *path, int tid) {
680  RzDebugPid *pid_info = RZ_NEW0(RzDebugPid);
681  if (!pid_info) {
682  return NULL;
683  }
684  char *ptr = strstr(info, "State:");
685  if (ptr) {
686  switch (*(ptr + 7)) {
687  case 'R':
688  pid_info->status = RZ_DBG_PROC_RUN;
689  break;
690  case 'S':
691  pid_info->status = RZ_DBG_PROC_SLEEP;
692  break;
693  case 'T':
694  case 't':
695  pid_info->status = RZ_DBG_PROC_STOP;
696  break;
697  case 'Z':
698  pid_info->status = RZ_DBG_PROC_ZOMBIE;
699  break;
700  case 'X':
701  pid_info->status = RZ_DBG_PROC_DEAD;
702  break;
703  default:
704  pid_info->status = RZ_DBG_PROC_SLEEP;
705  break;
706  }
707  }
708  ptr = strstr(info, "PPid:");
709  if (ptr) {
710  pid_info->ppid = atoi(ptr + 5);
711  }
712  ptr = strstr(info, "Uid:");
713  if (ptr) {
714  pid_info->uid = atoi(ptr + 5);
715  }
716  ptr = strstr(info, "Gid:");
717  if (ptr) {
718  pid_info->gid = atoi(ptr + 5);
719  }
720  pid_info->pid = tid;
721  pid_info->path = path ? strdup(path) : NULL;
722  pid_info->runnable = true;
723  pid_info->pc = 0;
724  return pid_info;
725 }
726 
727 static RzList *_extract_regs(char *regstr, RzList *flags, char *pc_alias) {
728  char *regstr_end, *regname, *regtype, *tmp1, *tmpregstr, *feature_end, *typegroup, *feature_start;
729  ut32 flagnum, regname_len, regsize, regnum;
730  RzList *regs;
731  RzListIter *iter;
732  gdbr_xml_reg_t *tmpreg;
733  gdbr_xml_flags_t *tmpflag;
734  if (!(regs = rz_list_new())) {
735  return NULL;
736  }
737  // Set gpr as the default register type for all of the following registers until `feature` is found
738  typegroup = "gpr";
739  while ((tmpregstr = strstr(regstr, "<reg"))) {
740  if (!(regstr_end = strchr(tmpregstr, '/'))) {
741  goto exit_err;
742  }
743  // Most regs don't have group/type params, attempt to get the type from `feature`.
744  // Multiple registers can be wrapped with a certain feature so this typegroup
745  // applies on all of the following registers until </feature>
746  if ((feature_start = strstr(regstr, "<feature")) && feature_start < tmpregstr) {
747  // Verify that we found the feature in the current node
748  regstr = feature_start;
749  feature_end = strchr(regstr, '>');
750  // To parse features of other architectures refer to:
751  // https://sourceware.org/gdb/onlinedocs/gdb/Standard-Target-Features.html#Standard-Target-Features
752  // - x86
753  if ((tmp1 = strstr(regstr, "core")) != NULL && tmp1 < feature_end) {
754  typegroup = "gpr";
755  } else if ((tmp1 = strstr(regstr, "segments")) != NULL && tmp1 < feature_end) {
756  typegroup = "seg";
757  } else if ((tmp1 = strstr(regstr, "linux")) != NULL && tmp1 < feature_end) {
758  typegroup = "gpr";
759  // Includes avx.512
760  } else if ((tmp1 = strstr(regstr, "avx")) != NULL && tmp1 < feature_end) {
761  typegroup = "ymm";
762  } else if ((tmp1 = strstr(regstr, "mpx")) != NULL && tmp1 < feature_end) {
763  typegroup = "seg";
764  // - arm
765  } else if ((tmp1 = strstr(regstr, "m-profile")) != NULL && tmp1 < feature_end) {
766  typegroup = "gpr";
767  } else if ((tmp1 = strstr(regstr, "pfe")) != NULL && tmp1 < feature_end) {
768  typegroup = "fpu";
769  } else if ((tmp1 = strstr(regstr, "vfp")) != NULL && tmp1 < feature_end) {
770  typegroup = "fpu";
771  } else if ((tmp1 = strstr(regstr, "iwmmxt")) != NULL && tmp1 < feature_end) {
772  typegroup = "xmm";
773  // -- Aarch64
774  } else if ((tmp1 = strstr(regstr, "sve")) != NULL && tmp1 < feature_end) {
775  typegroup = "ymm";
776  } else if ((tmp1 = strstr(regstr, "pauth")) != NULL && tmp1 < feature_end) {
777  typegroup = "sec";
778  } else if ((tmp1 = strstr(regstr, "qemu")) != NULL && tmp1 < feature_end) {
779  // - QEMU server registers
780  typegroup = "sys";
781  } else {
782  typegroup = "gpr";
783  }
784  }
785  // Reset to typegroup in case the previous register had a group/type parameter
786  // that indicated it's specific type which doesn't correspond to type defined by
787  // the parent feature tag
788  regtype = typegroup;
789  regstr = tmpregstr;
790  *regstr_end = '\0';
791  // name
792  if (!(regname = strstr(regstr, "name="))) {
793  goto exit_err;
794  }
795  regname += 6;
796  if (!(tmp1 = strchr(regname, '"'))) {
797  goto exit_err;
798  }
799  regname_len = tmp1 - regname;
800  // size
801  if (!(tmp1 = strstr(regstr, "bitsize="))) {
802  goto exit_err;
803  }
804  tmp1 += 9;
805  if (!isdigit(*tmp1)) {
806  goto exit_err;
807  }
808  regsize = strtoul(tmp1, NULL, 10);
809  // regnum
810  regnum = UINT32_MAX;
811  if ((tmp1 = strstr(regstr, "regnum="))) {
812  tmp1 += 8;
813  if (!isdigit(*tmp1)) {
814  goto exit_err;
815  }
816  regnum = strtoul(tmp1, NULL, 10);
817  }
818  flagnum = rz_list_length(flags);
819  if ((tmp1 = strstr(regstr, "group="))) {
820  tmp1 += 7;
821  if (rz_str_startswith(tmp1, "float")) {
822  regtype = "fpu";
823  } else if (rz_str_startswith(tmp1, "mmx")) {
824  regtype = "mmx";
825  } else if (rz_str_startswith(tmp1, "sse")) {
826  regtype = "xmm";
827  } else if (rz_str_startswith(tmp1, "vector")) {
828  regtype = "ymm";
829  } else if (rz_str_startswith(tmp1, "system")) {
830  regtype = "seg";
831  }
832  // We need type information in r2 register profiles
833  }
834  if ((tmp1 = strstr(regstr, "type="))) {
835  tmp1 += 6;
836  if (rz_str_startswith(tmp1, "vec") || rz_str_startswith(tmp1, "i387_ext") || rz_str_startswith(tmp1, "ieee_single") || rz_str_startswith(tmp1, "ieee_double")) {
837  regtype = "fpu";
838  } else if (rz_str_startswith(tmp1, "code_ptr")) {
839  strcpy(pc_alias, "=PC ");
840  strncpy(pc_alias + 4, regname, regname_len);
841  strcpy(pc_alias + 4 + regname_len, "\n");
842  } else {
843  // Check all flags. If reg is a flag, write flag data
844  flagnum = 0;
845  rz_list_foreach (flags, iter, tmpflag) {
846  if (rz_str_startswith(tmp1, tmpflag->type)) {
847  // Max 64-bit :/
848  if (tmpflag->num_bits <= 64) {
849  break;
850  }
851  }
852  flagnum++;
853  }
854  }
855  // We need type information in r2 register profiles
856  }
857  // Move unidentified vector/large registers from gpr to xmm since r2 set/get
858  // registers doesn't support >64bit registers atm(but it's still possible to
859  // read them using gdbr's implementation through dr/drt)
860  if (regsize > 64 && !strcmp(regtype, "gpr")) {
861  regtype = "xmm";
862  }
863  // Move appropriately sized unidentified xmm registers from fpu to xmm
864  if (regsize == 128 && !strcmp(regtype, "fpu")) {
865  regtype = "xmm";
866  }
867  if (!(tmpreg = calloc(1, sizeof(gdbr_xml_reg_t)))) {
868  goto exit_err;
869  }
870  regname[regname_len] = '\0';
871  if (regname_len > sizeof(tmpreg->name) - 1) {
872  eprintf("Register name too long: %s\n", regname);
873  }
874  strncpy(tmpreg->name, regname, sizeof(tmpreg->name) - 1);
875  tmpreg->name[sizeof(tmpreg->name) - 1] = '\0';
876  regname[regname_len] = '"';
877  strncpy(tmpreg->type, regtype, sizeof(tmpreg->type) - 1);
878  tmpreg->type[sizeof(tmpreg->type) - 1] = '\0';
879  tmpreg->size = regsize;
880  tmpreg->flagnum = flagnum;
881  if (regnum == UINT32_MAX) {
882  rz_list_push(regs, tmpreg);
883  } else if (regnum >= rz_list_length(regs)) {
884  int i;
885  for (i = regnum - rz_list_length(regs); i > 0; i--) {
886  // temporary placeholder reg. we trust the xml is correct and this will be replaced.
887  rz_list_push(regs, tmpreg);
888  rz_list_tail(regs)->data = NULL;
889  }
890  rz_list_push(regs, tmpreg);
891  } else {
892  // this is where we replace those placeholder regs
893  rz_list_set_n(regs, regnum, tmpreg);
894  }
895  *regstr_end = '/';
896  regstr = regstr_end + 3;
897  if (rz_str_startswith(regstr, "</feature>")) {
898  regstr += sizeof("</feature>");
899  // Revert to default
900  typegroup = "gpr";
901  }
902  }
903  regs->free = free;
904  return regs;
905 exit_err:
906  if (regs) {
907  regs->free = free;
909  }
910  return NULL;
911 }
size_t len
Definition: 6502dis.c:15
const aarch64_field fields[]
Definition: aarch64-opc.c:205
static char * regs[]
Definition: analysis_sh.c:203
lzma_index ** i
Definition: index.h:629
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
int gdbr_open_file(libgdbr_t *g, const char *filename, int flags, int mode)
Definition: core.c:1445
int gdbr_read_file(libgdbr_t *g, ut8 *buf, ut64 max_len)
Definition: core.c:1485
int gdbr_close_file(libgdbr_t *g)
Definition: core.c:1539
#define NULL
Definition: cris-opc.c:27
cs_arch arch
Definition: cstool.c:13
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
uint32_t ut32
struct @667 g
int send_ack(libgdbr_t *g)
Functions sends a single ack ('+')
Definition: common.c:130
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
int read_packet(libgdbr_t *instance, bool vcont)
Definition: packet.c:143
int send_msg(libgdbr_t *g, const char *command)
Definition: common.c:146
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
return memset(p, 0, total)
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
static void list(RzEgg *egg)
Definition: rz-gg.c:52
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API ut32 rz_list_set_n(RZ_NONNULL RzList *list, ut32 n, void *p)
Sets the N-th element of the list.
Definition: list.c:552
RZ_API RZ_BORROW void * rz_list_get_n(RZ_NONNULL const RzList *list, ut32 n)
Returns the N-th element of the list.
Definition: list.c:574
RZ_API RZ_BORROW RzListIter * rz_list_push(RZ_NONNULL RzList *list, void *item)
Alias for rz_list_append.
Definition: list.c:60
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc pid
Definition: sflib.h:64
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
static const char struct stat static buf struct stat static buf static vhangup int status
Definition: sflib.h:145
int type
Definition: mipsasm.c:17
int off
Definition: pal.c:13
#define eprintf(x, y...)
Definition: rlcc.c:7
@ RZ_DBG_PROC_RUN
Definition: rz_debug.h:61
@ RZ_DBG_PROC_STOP
Definition: rz_debug.h:60
@ RZ_DBG_PROC_ZOMBIE
Definition: rz_debug.h:63
@ RZ_DBG_PROC_DEAD
Definition: rz_debug.h:64
@ RZ_DBG_PROC_SLEEP
Definition: rz_debug.h:62
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_prepend(char *ptr, const char *string)
Definition: str.c:1027
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case sensitive)
Definition: str.c:3286
#define PFMT64d
Definition: rz_types.h:394
#define RZ_NEW0(x)
Definition: rz_types.h:284
@ RZ_SYS_ARCH_MIPS
Definition: rz_types.h:537
@ RZ_SYS_ARCH_NONE
Definition: rz_types.h:531
@ RZ_SYS_ARCH_RISCV
Definition: rz_types.h:564
@ RZ_SYS_ARCH_X86
Definition: rz_types.h:532
@ RZ_SYS_ARCH_ARM
Definition: rz_types.h:533
#define RZ_FREE(x)
Definition: rz_types.h:369
#define PFMT64x
Definition: rz_types.h:393
#define tolower(c)
Definition: safe-ctype.h:149
#define isdigit(c)
Definition: safe-ctype.h:131
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
static struct sockaddr static addrlen static backlog const void msg
Definition: sfsocketcall.h:119
#define O_RDONLY
Definition: sftypes.h:486
#define c(i)
Definition: sha256.c:43
#define UINT32_MAX
Definition: gzappend.c:170
Definition: arch.h:13
uint64_t offset
Definition: arch.h:15
uint64_t size
Definition: arch.h:16
char type[32]
Definition: xml.c:152
ut32 num_bits
Definition: xml.c:158
ut32 num_fields
Definition: xml.c:159
char name[32]
Definition: xml.c:154
ut32 bit_num
Definition: xml.c:155
struct gdbr_xml_flags_t::@444 fields[64]
ut32 flagnum
Definition: xml.c:166
ut32 size
Definition: xml.c:165
char type[8]
Definition: xml.c:164
char name[32]
Definition: xml.c:163
Definition: z80asm.h:102
char * path
Definition: rz_debug.h:414
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static char * regname(int reg)
Definition: dis.c:71
static RzDebugPid * _extract_pid_info(const char *info, const char *path, int tid)
Definition: xml.c:679
static RzList * _extract_flags(char *flagstr)
Definition: xml.c:572
int gdbr_read_processes_xml(libgdbr_t *g, int pid, RzList *list)
Definition: xml.c:474
int gdbr_read_target_xml(libgdbr_t *g)
Definition: xml.c:460
static void _write_flag_bits(char *buf, const gdbr_xml_flags_t *flags)
Definition: xml.c:501
static char * gdbr_read_osdata(libgdbr_t *g, const char *file, ut64 *tot_len)
Definition: xml.c:109
#define MAX_PID_CHARS
Definition: xml.c:13
static char * gdbr_read_feature(libgdbr_t *g, const char *file, ut64 *tot_len)
Definition: xml.c:15
static int gdbr_parse_target_xml(libgdbr_t *g, char *xml_data, ut64 len)
Definition: xml.c:175
static int _resolve_arch(libgdbr_t *g, char *xml_data)
Definition: xml.c:523
static RzList * _extract_regs(char *regstr, RzList *flags, char *pc_alias)
Definition: xml.c:727
static int gdbr_parse_processes_xml(libgdbr_t *g, char *xml_data, ut64 len, int pid, RzList *list)
Definition: xml.c:362