Rizin
unix-like reverse engineering framework and cli tools
linux_coredump.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2016 Oscar Salvador <osalvador.vilardaga@gmail.com>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_debug.h>
5 
6 #if __x86_64__ || __i386__ || __arm__ || __arm64__
7 #include <sys/uio.h>
8 #include <sys/ptrace.h>
9 #include <asm/ptrace.h>
10 #include "linux_coredump.h"
11 #include "linux_ptrace.h"
12 
13 /* For compatibility */
14 #if __x86_64__ || __arm64__
15 typedef Elf64_auxv_t elf_auxv_t;
16 typedef Elf64_Ehdr elf_hdr_t;
17 typedef Elf64_Phdr elf_phdr_t;
18 typedef Elf64_Shdr elf_shdr_t;
19 typedef Elf64_Nhdr elf_nhdr_t;
20 typedef ut32 elf_offset_t;
21 #elif __i386__ || __arm__
22 typedef Elf32_auxv_t elf_auxv_t;
23 typedef Elf32_Ehdr elf_hdr_t;
24 typedef Elf32_Phdr elf_phdr_t;
25 typedef Elf32_Shdr elf_shdr_t;
26 typedef Elf32_Nhdr elf_nhdr_t;
27 typedef ut64 elf_offset_t;
28 #endif
29 
30 #define fmt_addr "%08lx-%08lx"
31 #define ELF_HDR_SIZE sizeof(elf_hdr_t)
32 
33 /*Some fields from note section must be padded to 4 or 8 bytes*/
34 #define round_up(a) ((((a) + (4) - (1)) / (4)) * (4))
35 #define sizeof_round_up(b) round_up(sizeof(b))
36 
37 static map_file_t mapping_file = { 0, 0 };
38 static note_info_t note_info[NT_LENGHT_T];
39 
40 static bool is_a_kernel_mapping(const char *name) {
41  return !(name && strcmp(name, "[vdso]") && strcmp(name, "[vsyscall]") && strcmp(name, "[vvar]") && strcmp(name, "[heap]") && strcmp(name, "[vectors]") && strncmp(name, "[stack", strlen("[stack")));
42 }
43 
44 static char *prpsinfo_get_psargs(char *buffer, int len) {
45  char paux[ELF_PRARGSZ];
46  int i, bytes_left;
47  char *p = rz_mem_dup(buffer, len);
48  if (!p) {
49  return NULL;
50  }
51  bytes_left = strlen(buffer);
52  buffer = strchr(buffer, '\0');
53  if (!buffer) {
54  free(p);
55  return NULL;
56  }
57 
58  for (i = 0; i + bytes_left < len && i + bytes_left < ELF_PRARGSZ - 1; i++) {
59  if (!buffer[i]) {
60  buffer[i] = ' ';
61  }
62  paux[i] = buffer[i];
63  }
64  paux[i] = '\0';
65  strncat(p, paux, len - bytes_left - 1);
66  return p;
67 }
68 
69 static prpsinfo_t *linux_get_prpsinfo(RzDebug *dbg, proc_per_process_t *proc_data) {
70  const char *prog_states = "RSDTZW"; /* fs/binfmt_elf.c from kernel */
71  const char *basename = NULL;
72  char *buffer, *pfname = NULL, *ppsargs = NULL, *file = NULL;
73  prpsinfo_t *p;
74  pid_t mypid;
75  size_t len;
76 
77  p = RZ_NEW0(prpsinfo_t);
78  if (!p) {
79  eprintf("Couldn't allocate memory for prpsinfo_t\n");
80  return NULL;
81  }
82 
83  p->pr_pid = mypid = dbg->pid;
84  /* Start filling pr_fname and pr_psargs */
85  file = sdb_fmt("/proc/%d/cmdline", mypid);
87  if (!buffer) {
88  eprintf("buffer NULL\n");
89  goto error;
90  }
91  buffer[len] = 0;
92  pfname = strdup(buffer);
93  if (!pfname) {
94  goto error;
95  }
96  basename = rz_file_basename(pfname);
97  strncpy(p->pr_fname, basename, sizeof(p->pr_fname) - 1);
98  p->pr_fname[sizeof(p->pr_fname) - 1] = 0;
99  ppsargs = prpsinfo_get_psargs(buffer, (int)len);
100  if (!ppsargs) {
101  goto error;
102  }
103 
104  strncpy(p->pr_psargs, ppsargs, sizeof(p->pr_psargs) - 1);
105  p->pr_psargs[sizeof(p->pr_psargs) - 1] = 0;
106  free(buffer);
107  free(ppsargs);
108  free(pfname);
109  p->pr_sname = proc_data->s_name;
110  p->pr_zomb = (p->pr_sname == 'Z') ? 1 : 0;
111  p->pr_state = strchr(prog_states, p->pr_sname) - prog_states;
112  p->pr_ppid = proc_data->ppid;
113  p->pr_pgrp = proc_data->pgrp;
114  p->pr_sid = proc_data->sid;
115  p->pr_flag = proc_data->flag;
116  p->pr_nice = proc_data->nice;
117  p->pr_uid = proc_data->uid;
118  p->pr_gid = proc_data->gid;
119  return p;
120 error:
121  free(p);
122  free(buffer);
123  free(pfname);
124  free(ppsargs);
125  return NULL;
126 }
127 
128 static proc_per_thread_t *get_proc_thread_content(int pid, int tid) {
129  char *temp_p_sigpend, *temp_p_sighold, *p_sigpend, *p_sighold;
130  size_t size;
131  const char *file = sdb_fmt("/proc/%d/task/%d/stat", pid, tid);
132 
133  char *buff = rz_file_slurp(file, &size);
134  if (!buff) {
135  return NULL;
136  }
137 
139  if (!t) {
140  free(buff);
141  return NULL;
142  }
143  {
144  char no_str[128];
145  long unsigned int no_lui;
146  int no_num;
147  char no_char;
148  ut32 no_ui;
149  sscanf(buff, "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu"
150  "%" PFMT64x " %" PFMT64x " %ld %lu",
151  &no_num, no_str, &no_char, &no_num, &no_num, &no_num,
152  &no_num, &no_num, &no_ui, &no_lui, &no_lui, &no_lui,
153  &no_lui, &t->utime, &t->stime, &t->cutime, &t->cstime);
154  free(buff);
155  }
156 
157  /* /proc/[pid]/status for uid, gid, sigpend and sighold */
158  file = sdb_fmt("/proc/%d/task/%d/status", pid, tid);
159  buff = rz_file_slurp(file, &size);
160  if (!buff) {
161  free(t);
162  return NULL;
163  }
164 
165  temp_p_sigpend = strstr(buff, "SigPnd");
166  temp_p_sighold = strstr(buff, "SigBlk");
167  if (!temp_p_sigpend || !temp_p_sighold) {
168  free(buff);
169  free(t);
170  return NULL;
171  }
172  while (!isdigit((ut8)*temp_p_sigpend++)) {
173  // empty body
174  }
175  p_sigpend = temp_p_sigpend - 1;
176  while (isdigit((ut8)*temp_p_sigpend++)) {
177  // empty body
178  }
179  p_sigpend[temp_p_sigpend - p_sigpend - 1] = '\0';
180  while (!isdigit((ut8)*temp_p_sighold++)) {
181  // empty body
182  }
183  p_sighold = temp_p_sighold - 1;
184  while (isdigit((ut8)*temp_p_sighold++)) {
185  // empty body
186  }
187  p_sighold[temp_p_sighold - p_sighold - 1] = '\0';
188  t->sigpend = atoi(p_sigpend);
189  t->sighold = atoi(p_sighold);
190  free(buff);
191  return t;
192 }
193 
194 static prstatus_t *linux_get_prstatus(RzDebug *dbg, int pid, int tid, proc_content_t *proc_data, short int signr) {
195  elf_gregset_t regs;
196  prstatus_t *p;
197 
198  proc_data->per_thread = get_proc_thread_content(pid, tid);
199  if (!proc_data->per_thread) {
200  return NULL;
201  }
202  p = RZ_NEW0(prstatus_t);
203  if (!p) {
204  return NULL;
205  }
206  p->pr_cursig = p->pr_info.si_signo = signr;
207  p->pr_pid = tid;
208  p->pr_ppid = proc_data->per_process->ppid;
209  p->pr_pgrp = proc_data->per_process->pgrp;
210  p->pr_sid = proc_data->per_process->sid;
211  p->pr_sigpend = proc_data->per_thread->sigpend;
212  p->pr_sighold = proc_data->per_thread->sighold;
213  p->pr_utime.tv_sec = proc_data->per_thread->utime / 1000;
214  p->pr_utime.tv_usec = (proc_data->per_thread->utime % 1000) / 1000;
215  p->pr_stime.tv_sec = proc_data->per_thread->stime / 1000;
216  p->pr_stime.tv_usec = (proc_data->per_thread->stime % 1000) / 1000;
217  p->pr_cutime.tv_sec = proc_data->per_thread->cutime / 1000;
218  p->pr_cutime.tv_usec = (proc_data->per_thread->cutime % 1000) / 1000;
219  p->pr_cstime.tv_sec = proc_data->per_thread->cstime / 1000;
220  p->pr_cstime.tv_usec = (proc_data->per_thread->cstime % 1000) / 1000;
221 
222  if (rz_debug_ptrace(dbg, PTRACE_GETREGS, tid, NULL, &regs) < 0) {
223  perror("PTRACE_GETREGS");
224  RZ_FREE(proc_data->per_thread);
225  free(p);
226  return NULL;
227  }
228  memcpy(p->pr_reg, &regs, sizeof(regs));
229  RZ_FREE(proc_data->per_thread);
230  return p;
231 }
232 
233 static elf_fpregset_t *linux_get_fp_regset(RzDebug *dbg, int pid) {
234  elf_fpregset_t *p = RZ_NEW0(elf_fpregset_t);
235  if (p) {
236  if (rz_debug_ptrace(dbg, PTRACE_GETFPREGS, pid, NULL, p) < 0) {
237  perror("PTRACE_GETFPREGS");
238  free(p);
239  return NULL;
240  }
241  return p;
242  }
243  return NULL;
244 }
245 
246 static siginfo_t *linux_get_siginfo(RzDebug *dbg, int pid) {
247  siginfo_t *siginfo = RZ_NEW0(siginfo_t);
248  if (!siginfo) {
249  return NULL;
250  }
251  int ret = rz_debug_ptrace(dbg, PTRACE_GETSIGINFO, pid, 0, (rz_ptrace_data_t)(size_t)siginfo);
252  if (ret == -1 || !siginfo->si_signo) {
253  perror("PTRACE_GETSIGINFO");
254  free(siginfo);
255  return NULL;
256  }
257  return siginfo;
258 }
259 
260 static bool has_map_deleted_part(char *name) {
261  if (name) {
262  const char deleted_str[] = "(deleted)";
263  int len_name = strlen(name);
264  int len_suffx = strlen(deleted_str);
265  return !strncmp(name + len_name - len_suffx, deleted_str, len_suffx);
266  }
267  return false;
268 }
269 
270 static bool getAnonymousValue(char *keyw) {
271  if (!keyw) {
272  return false;
273  }
274  keyw = strchr(keyw, ' ');
275  if (!keyw) {
276  return false;
277  }
278  while (*keyw && isspace((ut8)*keyw)) {
279  keyw++;
280  }
281  return *keyw && *keyw != '0';
282 }
283 
284 static char *isAnonymousKeyword(const char *pp) {
285  if (!pp) {
286  return NULL;
287  }
288  char *keyw = strstr(pp, "Anonymous:");
289  if (!keyw) {
290  keyw = strstr(pp, "AnonHugePages:");
291  }
292  return keyw;
293 }
294 
295 static bool has_map_anonymous_content(char *buff_smaps, unsigned long start_addr, unsigned long end_addr) {
296  char *pp, *extern_tok = NULL, *keyw = NULL;
297  char *identity = rz_str_newf(fmt_addr, start_addr, end_addr);
298  char *str = strdup(buff_smaps);
299  char *p = strtok_r(str, "\n", &extern_tok);
300  for (; p; p = strtok_r(NULL, "\n", &extern_tok)) {
301  if (strstr(p, identity)) {
302  pp = strtok_r(NULL, "\n", &extern_tok);
303  for (; pp; pp = strtok_r(NULL, "\n", &extern_tok)) {
304  if ((keyw = isAnonymousKeyword(pp))) {
305  bool is_anonymous = getAnonymousValue(keyw);
306  free(identity);
307  free(str);
308  return is_anonymous;
309  }
310  }
311  }
312  }
313  free(identity);
314  free(str);
315  return 0;
316 }
317 
318 static bool dump_this_map(char *buff_smaps, linux_map_entry_t *entry, ut8 filter_flags) {
319  char *p, *pp, *ppp, *extern_tok, *flags_str = NULL;
320  char *identity = rz_str_newf(fmt_addr, entry->start_addr, entry->end_addr);
321  bool found = false;
322  char *aux = NULL;
323  ut8 vmflags = 0, perms = entry->perms;
324 
325  if (!identity) {
326  return false;
327  }
328  /* if the map doesn't have r/w quit right here */
329  if ((!(perms & RZ_PERM_R) && !(perms & RZ_PERM_W))) {
330  free(identity);
331  return false;
332  }
333  aux = strdup(buff_smaps);
334  if (!aux) {
335  free(identity);
336  return false;
337  }
338 
339  pp = strtok_r(aux, "\n", &extern_tok);
340  for (; pp; pp = strtok_r(NULL, "\n", &extern_tok)) {
341  if (strstr(pp, identity)) {
342  ppp = strtok_r(NULL, "\n", &extern_tok);
343  for (; ppp; ppp = strtok_r(NULL, "\n", &extern_tok)) {
344  if ((flags_str = strstr(ppp, "VmFlags:"))) {
345  found = true;
346  break;
347  }
348  }
349  }
350  }
351 
352  if (entry->file_backed) {
353  if (filter_flags & MAP_FILE_PRIV) {
354  goto beach;
355  }
356  if (filter_flags & MAP_FILE_SHR) {
357  goto beach;
358  }
359  }
360 
361  if (!flags_str || !found) {
362  /* if we don't have VmFlags, let's check it out in another way */
363  if (entry->kernel_mapping) {
364  goto beach;
365  }
366 
367  if (perms & !entry->shared) {
368  if ((filter_flags & MAP_ANON_PRIV) && entry->anonymous) {
369  goto beach;
370  }
371  if ((filter_flags & MAP_HUG_PRIV) && entry->anonymous) {
372  goto beach;
373  }
374  }
375 
376  if (perms & entry->shared) {
377  if (filter_flags & MAP_ANON_SHR) {
378  goto beach;
379  }
380  if (filter_flags & MAP_HUG_SHR) {
381  goto beach;
382  }
383  }
384  } else {
385  /* We have VmFlags */
386  flags_str = strchr(flags_str, ' ');
387  if (!flags_str) {
388  goto fail;
389  }
390  while (*flags_str++ == ' ') {
391  // empty body
392  }
393  flags_str--;
394  p = strtok(flags_str, " ");
395  while (p) {
396  if (!strncmp(p, "sh", 2)) {
397  vmflags |= SH_FLAG;
398  }
399  if (!strncmp(p, "io", 2)) {
400  vmflags |= IO_FLAG;
401  }
402  if (!strncmp(p, "ht", 2)) {
403  vmflags |= HT_FLAG;
404  }
405  if (!strncmp(p, "dd", 2)) {
406  vmflags |= DD_FLAG;
407  }
408  p = strtok(NULL, " ");
409  }
410 
411  if (!(vmflags & SH_FLAG)) {
412  vmflags |= PV_FLAG;
413  }
414  /* first check for dd and io flags */
415  if ((vmflags & DD_FLAG) || (vmflags & IO_FLAG)) {
416  goto fail;
417  }
418 
419  /* if current map comes from kernel and does not have DD flag, just stop checking */
420  if (entry->kernel_mapping) {
421  goto beach;
422  }
423 
424  if (vmflags & HT_FLAG) {
425  if ((filter_flags & MAP_HUG_PRIV) && entry->anonymous) {
426  goto beach;
427  }
428  if (filter_flags & MAP_HUG_SHR) {
429  goto beach;
430  }
431  }
432 
433  if (vmflags & SH_FLAG) {
434  if (filter_flags & MAP_ANON_SHR) {
435  goto beach;
436  }
437  if (filter_flags & MAP_HUG_SHR) {
438  goto beach;
439  }
440  }
441 
442  if (vmflags & PV_FLAG) {
443  if ((filter_flags & MAP_ANON_PRIV) && entry->anonymous) {
444  goto beach;
445  }
446  if ((filter_flags & MAP_HUG_PRIV) && entry->anonymous) {
447  goto beach;
448  }
449  }
450  }
451 
452 fail:
453  free(identity);
454  free(aux);
455  return false;
456 beach:
457  free(identity);
458  free(aux);
459  return true;
460 }
461 
462 static void clean_maps(linux_map_entry_t *h) {
463  linux_map_entry_t *aux, *p = h;
464  while (p) {
465  aux = p;
466  p = p->n;
467  free(aux);
468  }
469 }
470 
471 static linux_map_entry_t *linux_get_mapped_files(RzDebug *dbg, ut8 filter_flags) {
472  linux_map_entry_t *me_head = NULL, *me_tail = NULL;
473  RzListIter *iter;
474  RzDebugMap *map;
475  bool is_anonymous = false, is_deleted = false, ret = 0;
476  char *file = NULL, *buff_maps = NULL, *buff_smaps = NULL;
477  size_t size_file = 0;
478 
479  file = rz_str_newf("/proc/%d/smaps", dbg->pid);
480  buff_smaps = rz_file_slurp(file, &size_file);
481  if (!buff_smaps) {
482  goto error;
483  }
484  RZ_FREE(file);
485 
486  file = rz_str_newf("/proc/%d/maps", dbg->pid);
487  buff_maps = rz_file_slurp(file, &size_file);
488  if (!buff_maps) {
489  goto error;
490  }
491  RZ_FREE(file);
492 
493  ret = rz_debug_map_sync(dbg);
494  if (!ret) {
495  goto error;
496  }
497  rz_list_foreach (dbg->maps, iter, map) {
499  if (!pmentry) {
500  goto error;
501  }
502  pmentry->start_addr = map->addr;
503  pmentry->end_addr = map->addr_end;
504  pmentry->offset = map->offset;
505  pmentry->name = strncmp(map->name, "unk", strlen("unk"))
506  ? strdup(map->name)
507  : NULL;
508  pmentry->perms = map->perm;
509  pmentry->shared = map->shared;
510  pmentry->kernel_mapping = false;
511  /* Check if is a kernel mapping */
512  if (pmentry->name && is_a_kernel_mapping(pmentry->name)) {
513  pmentry->anonymous = pmentry->kernel_mapping = true;
514  } else {
515  /* Check if map has anonymous content by checking Anonymous and AnonHugePages */
516  is_anonymous = has_map_anonymous_content(buff_smaps, pmentry->start_addr, pmentry->end_addr);
517  if (!is_anonymous && pmentry->name) {
518  is_anonymous = is_deleted = has_map_deleted_part(pmentry->name);
519  }
520  pmentry->anonymous = is_anonymous;
521  }
522  if (pmentry->name && !pmentry->kernel_mapping && !is_deleted) {
523  pmentry->file_backed = true;
524  }
525  pmentry->dumpeable = dump_this_map(buff_smaps, pmentry, filter_flags);
526  eprintf(fmt_addr " - anonymous: %d, kernel_mapping: %d, file_backed: %d, dumpeable: %d\n",
527  pmentry->start_addr, pmentry->end_addr,
528  pmentry->anonymous, pmentry->kernel_mapping,
529  pmentry->file_backed, pmentry->dumpeable);
530  if (pmentry->file_backed) {
531  const char *name = pmentry->name;
532  if (!name) {
533  name = "";
534  }
535  mapping_file.size += SIZE_NT_FILE_DESCSZ + strlen(name) + 1;
536  mapping_file.count++;
537  }
538  ADD_MAP_NODE(pmentry);
539  }
540  /* number of mappings and page size */
541  mapping_file.size += sizeof(unsigned long) * 2;
542  free(buff_maps);
543  free(buff_smaps);
544 
545  return me_head;
546 error:
547  free(buff_maps);
548  free(buff_smaps);
549  free(file);
550  clean_maps(me_head);
551  return NULL;
552 }
553 
554 static auxv_buff_t *linux_get_auxv(RzDebug *dbg) {
555  char *buff = NULL;
556  auxv_buff_t *auxv = NULL;
557  int auxv_entries;
558  size_t size;
559 
560  const char *file = sdb_fmt("/proc/%d/auxv", dbg->pid);
561  buff = rz_file_slurp(file, &size);
562  if (!buff) {
563  return NULL;
564  }
565 
566  auxv_entries = size / sizeof(elf_auxv_t);
567  if (auxv_entries > 0) {
568  auxv = RZ_NEW0(auxv_buff_t);
569  if (!auxv) {
570  free(buff);
571  return NULL;
572  }
573  auxv->size = size;
574  auxv->data = rz_mem_dup(buff, (int)size);
575  if (!auxv->data) {
576  free(buff);
577  free(auxv);
578  return NULL;
579  }
580  }
581  free(buff);
582  return auxv;
583 }
584 
585 static elf_hdr_t *build_elf_hdr(int n_segments) {
586  int pad_byte;
587  int ph_size;
588  int ph_offset;
589  elf_hdr_t *h = RZ_NEW0(elf_hdr_t);
590  if (!h) {
591  return NULL;
592  }
593 
594  ph_offset = ELF_HDR_SIZE;
595  ph_size = sizeof(elf_phdr_t);
596  h->e_ident[EI_MAG0] = ELFMAG0;
597  h->e_ident[EI_MAG1] = ELFMAG1;
598  h->e_ident[EI_MAG2] = ELFMAG2;
599  h->e_ident[EI_MAG3] = ELFMAG3;
600 #if __x86_64__ || __arm64__
601  h->e_ident[EI_CLASS] = ELFCLASS64; /*64bits */
602 #elif __i386__ || __arm__
603  h->e_ident[EI_CLASS] = ELFCLASS32;
604 #endif
605  h->e_ident[EI_DATA] = ELFDATA2LSB;
606  h->e_ident[EI_VERSION] = EV_CURRENT;
607  h->e_ident[EI_OSABI] = ELFOSABI_NONE;
608  h->e_ident[EI_ABIVERSION] = 0x0;
609 
610  for (pad_byte = EI_PAD; pad_byte < EI_NIDENT; pad_byte++) {
611  h->e_ident[pad_byte] = '\0';
612  }
613  h->e_type = ET_CORE;
614 #if __x86_64__
615  h->e_machine = EM_X86_64;
616 #elif __i386__
617  h->e_machine = EM_386;
618 #elif __arm__
619  h->e_machine = EM_ARM;
620 #elif __arm64__
621  h->e_machine = EM_AARCH64;
622 #endif
623  h->e_version = EV_CURRENT;
624  h->e_entry = 0x0;
625  h->e_ehsize = ELF_HDR_SIZE;
626  h->e_phoff = ph_offset;
627  h->e_phentsize = ph_size;
628  /* n_segments + NOTE segment */
629  h->e_phnum = (n_segments + 1) > PN_XNUM ? PN_XNUM : n_segments + 1;
630  h->e_flags = 0x0;
631  /* Coredump contains no sections */
632  h->e_shoff = 0x0;
633  h->e_shentsize = 0x0;
634  h->e_shnum = 0x0;
635  h->e_shstrndx = 0x0;
636  return h;
637 }
638 
639 static int get_info_mappings(linux_map_entry_t *me_head, size_t *maps_size) {
641  int n_entries;
642  for (n_entries = 0, p = me_head; p; p = p->n) {
643  /* We don't count maps which does not have r/w perms */
644  if (((p->perms & RZ_PERM_R) || (p->perms & RZ_PERM_W)) && p->dumpeable) {
645  *maps_size += p->end_addr - p->start_addr;
646  n_entries++;
647  }
648  }
649  return n_entries;
650 }
651 
652 static bool dump_elf_header(RzBuffer *dest, elf_hdr_t *hdr) {
653  return rz_buf_append_bytes(dest, (const ut8 *)hdr, hdr->e_ehsize);
654 }
655 
656 static void *get_ntfile_data(linux_map_entry_t *head) {
657  char *maps_data, *pp;
659  unsigned long n_pag, n_segments;
660  size_t size = mapping_file.size;
661 
662  if ((int)size < 1) {
663  return NULL;
664  }
665  n_segments = mapping_file.count;
666  n_pag = 1;
667  pp = maps_data = malloc(size);
668  if (!maps_data) {
669  return NULL;
670  }
671  memcpy(maps_data, &n_segments, sizeof(n_segments));
672  memcpy(maps_data + sizeof(n_segments), &n_pag, sizeof(n_pag));
673  pp += sizeof(n_segments) + sizeof(n_pag);
674 
675  for (p = head; p; p = p->n) {
676  if (p->file_backed && !is_a_kernel_mapping(p->name)) {
677  memcpy(pp, &p->start_addr, sizeof(p->start_addr));
678  pp += sizeof(p->start_addr);
679  memcpy(pp, &p->end_addr, sizeof(p->end_addr));
680  pp += sizeof(p->end_addr);
681  memcpy(pp, &p->offset, sizeof(p->offset));
682  pp += sizeof(p->offset);
683  }
684  }
685  for (p = head; p; p = p->n) {
686  if (p->file_backed && !is_a_kernel_mapping(p->name)) {
687  strncpy(pp, p->name, size - (pp - maps_data));
688  pp += strlen(p->name) + 1;
689  }
690  }
691  return maps_data;
692 }
693 
694 static bool dump_elf_pheaders(RzBuffer *dest, linux_map_entry_t *maps, elf_offset_t *offset, size_t note_section_size) {
695  linux_map_entry_t *me_p;
696  elf_offset_t offset_to_next;
697  elf_phdr_t phdr;
698  bool ret;
699 
700  /* Start with note */
701  phdr.p_type = PT_NOTE;
702  phdr.p_flags = PF_R;
703  phdr.p_offset = *offset;
704  phdr.p_vaddr = 0x0;
705  phdr.p_paddr = 0x0;
706  phdr.p_filesz = note_section_size;
707  phdr.p_memsz = 0x0;
708  phdr.p_align = 0x1;
709 
710  if (!rz_buf_append_bytes(dest, (const ut8 *)&phdr, sizeof(elf_phdr_t))) {
711  return false;
712  }
713 
714  offset_to_next = *offset + note_section_size;
715 
716  /* write program headers */
717  for (me_p = maps; me_p; me_p = me_p->n) {
718  if ((!(me_p->perms & RZ_PERM_R) && !(me_p->perms & RZ_PERM_W)) || !me_p->dumpeable) {
719  continue;
720  }
721  phdr.p_type = PT_LOAD;
722  phdr.p_flags = me_p->perms;
723  phdr.p_vaddr = me_p->start_addr;
724  phdr.p_paddr = 0x0;
725  phdr.p_memsz = me_p->end_addr - me_p->start_addr;
726  phdr.p_filesz = me_p->dumpeable == 0 ? 0 : phdr.p_memsz;
727  phdr.p_offset = offset_to_next;
728  phdr.p_align = 0x1;
729  offset_to_next += phdr.p_filesz == 0 ? 0 : phdr.p_filesz;
730  ret = rz_buf_append_bytes(dest, (const ut8 *)&phdr, sizeof(elf_phdr_t));
731  if (!ret) {
732  return false;
733  }
734  memset(&phdr, '\0', sizeof(elf_phdr_t));
735  }
736 
737  *offset = offset_to_next;
738  return true;
739 }
740 
741 static bool dump_elf_note(RzBuffer *dest, void *note_data, size_t note_section_size) {
742  return rz_buf_append_bytes(dest, (const ut8 *)note_data, note_section_size);
743 }
744 
745 static bool dump_elf_map_content(RzDebug *dbg, RzBuffer *dest, linux_map_entry_t *head, pid_t pid) {
747  ut8 *map_content;
748  size_t size;
749  bool ret;
750 
751  eprintf("dump_elf_map_content starting\n\n");
752 
753  for (p = head; p; p = p->n) {
754  if (!p->dumpeable) {
755  continue;
756  }
757  size = p->end_addr - p->start_addr;
758  map_content = malloc(size);
759  if (!map_content) {
760  return false;
761  }
762  ret = dbg->iob.read_at(dbg->iob.io, p->start_addr, map_content, size);
763  if (!ret) {
764  eprintf("Problems reading %" PFMTSZd " bytes at %" PFMT64x "\n", size, (ut64)p->start_addr);
765  } else {
766  ret = rz_buf_append_bytes(dest, (const ut8 *)map_content, size);
767  if (!ret) {
768  eprintf("rz_buf_append_bytes - failed\n");
769  }
770  }
771  free(map_content);
772  }
773  eprintf("dump_elf_map_content - done\n");
774  return true;
775 }
776 
777 static proc_per_process_t *get_proc_process_content(RzDebug *dbg) {
779  char *temp_p_uid, *temp_p_gid, *p_uid, *p_gid;
780  ut16 filter_flags, default_filter_flags = 0x33;
781  char *buff;
782  const char *file = sdb_fmt("/proc/%d/stat", dbg->pid);
783  size_t size;
784 
785  buff = rz_file_slurp(file, &size);
786  if (!buff) {
787  return NULL;
788  }
789 
791  if (!p) {
792  free(buff);
793  return NULL;
794  }
795 
796  /* /proc/[pid]/stat */
797  /* we only need few fields which are process-wide */
798  {
799  char no_str[128];
800  long unsigned int no_lui;
801  long int no_li;
802  int no_num;
803  sscanf(buff, "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu"
804  "%lu %lu %ld %ld %ld %ld %ld",
805  &p->pid, no_str, &p->s_name, &p->ppid, &p->pgrp, &no_num,
806  &no_num, &p->sid, &p->flag, &no_lui, &no_lui, &no_lui,
807  &no_lui, &no_lui, &no_lui, &no_li, &no_li,
808  &no_li, &p->nice, &p->num_threads);
809  free(buff);
810  }
811  if (!p->num_threads || p->num_threads < 1) {
812  free(p);
813  eprintf("Warning: number of threads is < 1\n");
814  return NULL;
815  }
816  file = sdb_fmt("/proc/%d/status", dbg->pid);
817  buff = rz_file_slurp(file, &size);
818  if (!buff) {
819  free(p);
820  return NULL;
821  }
822  temp_p_uid = strstr(buff, "Uid:");
823  temp_p_gid = strstr(buff, "Gid:");
824  /* Uid */
825  if (temp_p_uid) {
826  while (!isdigit((ut8)*temp_p_uid++)) {
827  // empty body
828  }
829  p_uid = temp_p_uid - 1;
830  while (isdigit((ut8)*temp_p_uid++)) {
831  // empty body
832  }
833  p_uid[temp_p_uid - p_uid - 1] = '\0';
834  } else {
835  p_uid = NULL;
836  }
837  p->uid = p_uid ? atoi(p_uid) : 0;
838 
839  /* Gid */
840  if (temp_p_gid) {
841  while (!isdigit((ut8)*temp_p_gid++)) {
842  // empty body
843  }
844  p_gid = temp_p_gid - 1;
845  while (isdigit((ut8)*temp_p_gid++)) {
846  // empty body
847  }
848  p_gid[temp_p_gid - p_gid - 1] = '\0';
849  } else {
850  p_gid = NULL;
851  }
852  p->gid = p_gid ? atoi(p_gid) : 0;
853 
854  free(buff);
855  /* Check the coredump_filter value if we have*/
856  file = sdb_fmt("/proc/%d/coredump_filter", dbg->pid);
857  buff = rz_file_slurp(file, &size);
858  if (buff) {
859  sscanf(buff, "%hx", &filter_flags);
860  p->coredump_filter = filter_flags;
861  free(buff);
862  } else {
863  /* Old kernels do not have coredump_filter, so just take the default one */
864  p->coredump_filter = default_filter_flags;
865  }
866  return p;
867 }
868 
869 static void may_clean_all(elf_proc_note_t *elf_proc_note, proc_content_t *proc_data, elf_hdr_t *elf_hdr) {
870  RZ_FREE(elf_proc_note->prpsinfo);
871  RZ_FREE(elf_proc_note->auxv);
872  clean_maps(elf_proc_note->maps);
873  free(elf_proc_note);
874  RZ_FREE(proc_data->per_thread);
875  RZ_FREE(proc_data->per_process);
876  free(proc_data);
877  free(elf_hdr);
878 }
879 
880 static elf_shdr_t *get_extra_sectionhdr(elf_hdr_t *elf_hdr, st64 offset, int n_segments) {
881  elf_shdr_t *shdr = RZ_NEW0(elf_shdr_t);
882  if (!shdr) {
883  return NULL;
884  }
885  elf_hdr->e_shoff = offset;
886  elf_hdr->e_shentsize = sizeof(elf_shdr_t);
887  elf_hdr->e_shnum = 1;
888  elf_hdr->e_shstrndx = SHN_UNDEF;
889  shdr->sh_type = SHT_NULL;
890  shdr->sh_size = elf_hdr->e_shnum;
891  shdr->sh_link = elf_hdr->e_shstrndx;
892  shdr->sh_info = n_segments + 1;
893  return shdr;
894 }
895 
896 static bool dump_elf_sheader_pxnum(RzBuffer *dest, elf_shdr_t *shdr) {
897  return rz_buf_append_bytes(dest, (const ut8 *)shdr, sizeof(*shdr));
898 }
899 
900 #if __i386__
901 static elf_fpxregset_t *linux_get_fpx_regset(RzDebug *dbg, int tid) {
902 #ifdef PTRACE_GETREGSET
903  struct iovec transfer;
904  elf_fpxregset_t *fpxregset = RZ_NEW0(elf_fpxregset_t);
905  if (fpxregset) {
906  transfer.iov_base = fpxregset;
907  transfer.iov_len = sizeof(elf_fpxregset_t);
908  if (rz_debug_ptrace(dbg, PTRACE_GETREGSET, tid, (void *)NT_PRXFPREG, &transfer) < 0) {
909  perror("linux_get_fpx_regset");
910  RZ_FREE(fpxregset);
911  }
912  }
913  return fpxregset;
914 #else
915  return NULL;
916 #endif
917 }
918 #endif
919 
920 #if __i386__ || __x86_64__
921 void *linux_get_xsave_data(RzDebug *dbg, int tid, ut32 size) {
922 #ifdef PTRACE_GETREGSET
923  struct iovec transfer;
924  char *xsave_data = calloc(size, 1);
925  if (!xsave_data) {
926  return NULL;
927  }
928  transfer.iov_base = xsave_data;
929  transfer.iov_len = size;
930  if (rz_debug_ptrace_get_x86_xstate(dbg, tid, &transfer) < 0) {
931  free(xsave_data);
932  return NULL;
933  }
934  return xsave_data;
935 #else
936  return NULL;
937 #endif
938 }
939 #endif
940 
941 #if __arm__ || __arm64__
942 void *linux_get_arm_vfp_data(RzDebug *dbg, int tid) {
943 #ifdef PTRACE_GETVFPREGS
944  char *vfp_data = calloc(ARM_VFPREGS_SIZE + 1, 1);
945  if (!vfp_data) {
946  return NULL;
947  }
948 
949  if (rz_debug_ptrace(dbg, PTRACE_GETVFPREGS, tid, 0, vfp_data) < 0) {
950  perror("linux_get_arm_vfp_data");
951  free(vfp_data);
952  return NULL;
953  }
954  return vfp_data;
955 #else
956  return NULL;
957 #endif
958 }
959 #endif
960 
961 void write_note_hdr(note_type_t type, ut8 **note_data) {
962  elf_nhdr_t nhdr;
963  static size_t size_note_hdr = sizeof(elf_nhdr_t);
964  ut32 note_type;
965 
966  switch (type) {
967  case NT_PRPSINFO_T:
968  note_type = NT_PRPSINFO;
969  nhdr.n_descsz = note_info[type].size;
970  break;
971  case NT_AUXV_T:
972  note_type = NT_AUXV;
973  nhdr.n_descsz = note_info[type].size;
974  break;
975  case NT_FILE_T:
976  note_type = NT_FILE;
977  nhdr.n_descsz = note_info[type].size;
978  break;
979  case NT_PRSTATUS_T:
980  note_type = NT_PRSTATUS;
981  nhdr.n_descsz = note_info[type].size;
982  break;
983  case NT_FPREGSET_T:
984  note_type = NT_FPREGSET;
985  nhdr.n_descsz = note_info[type].size;
986  break;
987 #if __i386__
988  case NT_PRXFPREG_T:
989  note_type = NT_PRXFPREG;
990  nhdr.n_descsz = note_info[type].size;
991  break;
992 #endif
993  case NT_SIGINFO_T:
994  note_type = NT_SIGINFO;
995  nhdr.n_descsz = note_info[type].size;
996  break;
997 #if __i386__ || __x86_64__
998  case NT_X86_XSTATE_T:
999  note_type = NT_X86_XSTATE;
1000  nhdr.n_descsz = note_info[type].size;
1001  break;
1002 #elif __arm__ || __arm64__
1003  case NT_ARM_VFP_T:
1004  note_type = NT_ARM_VFP;
1005  nhdr.n_descsz = note_info[type].size;
1006  break;
1007 #endif
1008  default:
1009  /* shouldn't happen */
1010  memset(*note_data, 0, size_note_hdr);
1011  return;
1012  }
1013 
1014  nhdr.n_type = note_type;
1015  if (note_type == NT_X86_XSTATE || note_type == NT_ARM_VFP || note_type == NT_PRXFPREG) {
1016  nhdr.n_namesz = sizeof("LINUX");
1017  } else {
1018  nhdr.n_namesz = sizeof("CORE");
1019  }
1020 
1021  memcpy(*note_data, (void *)&nhdr, size_note_hdr);
1022  *note_data += size_note_hdr;
1023 }
1024 
1025 static int *get_unique_thread_id(RzDebug *dbg, int n_threads) {
1026  RzListIter *it;
1027  RzList *list;
1028  RzDebugPid *th;
1029  int *thread_id = NULL;
1030  int i = 0;
1031  bool found = false;
1032 
1033  if (dbg->cur) {
1034  list = dbg->cur->threads(dbg, dbg->pid);
1035  if (!list) {
1036  return NULL;
1037  }
1038  thread_id = calloc(sizeof(int), n_threads);
1039  if (!thread_id) {
1040  return NULL; /* free list */
1041  }
1042  rz_list_foreach (list, it, th) {
1043  if (th->pid) {
1044  int j;
1045  for (j = 0; j < i && !found; j++) {
1046  if (th->pid == thread_id[j]) {
1047  found = true;
1048  break;
1049  }
1050  }
1051  if (!found) {
1052  /* Adding to array and attaching to thread */
1053  thread_id[i] = th->pid;
1054  /* The main thread is already being traced */
1055  if (th->pid != dbg->pid) {
1056  if (rz_debug_ptrace(dbg, PTRACE_ATTACH, thread_id[i], 0, 0) < 0) {
1057  perror("Could not attach to thread");
1058  }
1059  }
1060  i++;
1061  }
1062  found = false;
1063  }
1064  }
1065  free(list);
1066  }
1067  return thread_id;
1068 }
1069 
1070 void detach_threads(RzDebug *dbg, int *thread_id, int n_threads) {
1071  int i;
1072  for (i = 0; i < n_threads; i++) {
1073  if (dbg->pid != thread_id[i]) {
1074  if (rz_debug_ptrace(dbg, PTRACE_DETACH, thread_id[i], 0, 0) < 0) {
1075  perror("PTRACE_DETACH");
1076  }
1077  }
1078  }
1079 }
1080 
1081 static ut8 *build_note_section(RzDebug *dbg, elf_proc_note_t *elf_proc_note, proc_content_t *proc_data, size_t *section_size) {
1082  ut8 *note_data, *pnote_data;
1083  char *maps_data;
1084  int i, n_notes = 0, *thread_id;
1085  size_t size = 0;
1086  note_type_t type;
1087 #if __i386__
1088  bool fpx_flag = false;
1089 #endif
1090 #if __i386__ || __x86_64__
1091  bool xsave_flag = false;
1092 #elif __arm__ || __arm64__
1093  bool vfp_flag = false;
1094 #endif
1095 
1096  maps_data = get_ntfile_data(elf_proc_note->maps);
1097  if (!maps_data) {
1098  return NULL;
1099  }
1100 
1101  thread_id = get_unique_thread_id(dbg, elf_proc_note->n_threads);
1102  if (!thread_id) {
1103  free(maps_data);
1104  return NULL;
1105  }
1106 
1107  /* NT_* per proc */
1108  /* NT_PRPSINFO */
1109  type = NT_PRPSINFO_T;
1110  size += note_info[type].size_roundedup;
1111  size += note_info[type].size_name;
1112  n_notes++;
1113  /* NT_AUXV */
1114  type = NT_AUXV_T;
1115  size += note_info[type].size_roundedup;
1116  size += note_info[type].size_name;
1117  n_notes++;
1118  /* NT_FILE */
1119  type = NT_FILE_T;
1120  size += note_info[type].size_roundedup;
1121  size += note_info[type].size_name;
1122  n_notes++;
1123 
1124  /* NT_* per thread: NT_PRSTATUS, NT_SIGINFO, NT_FPREGSET, (NT_PRXFPREG), NT_X86_XSTATE */
1125  for (i = 0; i < elf_proc_note->n_threads; i++) {
1126  type = NT_PRSTATUS_T;
1127  size += note_info[type].size_roundedup;
1128  size += note_info[type].size_name;
1129  n_notes++;
1130  type = NT_SIGINFO_T;
1131  size += note_info[type].size_roundedup;
1132  size += note_info[type].size_name;
1133  n_notes++;
1134  type = NT_FPREGSET_T;
1135  size += note_info[type].size_roundedup;
1136  size += note_info[type].size_name;
1137  n_notes++;
1138 #if __i386__
1139  type = NT_PRXFPREG_T;
1140  if (note_info[type].size) {
1141  fpx_flag = true;
1142  size += note_info[type].size_roundedup;
1143  size += note_info[type].size_name;
1144  n_notes++;
1145  }
1146 #endif
1147 #if __i386__ || __x86_64__
1148  type = NT_X86_XSTATE_T;
1149  if (note_info[type].size) {
1150  xsave_flag = true;
1151  size += note_info[type].size_roundedup;
1152  size += note_info[type].size_name;
1153  n_notes++;
1154  }
1155 #endif
1156 #if __arm__ || __arm64__
1157  type = NT_ARM_VFP_T;
1158  if (note_info[type].size) {
1159  vfp_flag = true;
1160  size += note_info[type].size_roundedup;
1161  size += note_info[type].size_name;
1162  n_notes++;
1163  }
1164 #endif
1165  }
1166  size += round_up(n_notes * sizeof(elf_nhdr_t));
1167  *section_size = size;
1168 
1169  /* Start building note */
1170  note_data = calloc(1, size);
1171  if (!note_data) {
1172  free(thread_id);
1173  free(maps_data);
1174  return NULL;
1175  }
1176  pnote_data = note_data;
1177  /* prpsinfo */
1178  type = NT_PRPSINFO_T;
1179  write_note_hdr(type, &note_data);
1180  memcpy(note_data, note_info[type].name, note_info[type].size_name);
1181  note_data += note_info[type].size_name;
1182  memcpy(note_data, elf_proc_note->prpsinfo, note_info[type].size);
1183  note_data += note_info[type].size_roundedup;
1184 
1185  /* prstatus + fpregset + (prxfpreg) + siginfo + x86xstate per thread */
1186  {
1187  elf_proc_note->thread_note = RZ_NEW0(thread_elf_note_t);
1188  if (!elf_proc_note->thread_note) {
1189  goto fail;
1190  }
1191  for (i = 0; i < elf_proc_note->n_threads; i++) {
1192  elf_proc_note->thread_note->siginfo = linux_get_siginfo(dbg, thread_id[i]);
1193  if (!elf_proc_note->thread_note->siginfo) {
1194  goto fail;
1195  }
1196  elf_proc_note->thread_note->prstatus = linux_get_prstatus(dbg, dbg->pid,
1197  thread_id[i], proc_data,
1198  elf_proc_note->thread_note->siginfo->si_signo);
1199  if (!elf_proc_note->thread_note->prstatus) {
1200  goto fail;
1201  }
1202  elf_proc_note->thread_note->fp_regset = linux_get_fp_regset(dbg, thread_id[i]);
1203  if (!elf_proc_note->thread_note->fp_regset) {
1204  goto fail;
1205  }
1206 #if __i386__
1207  if (fpx_flag) {
1208  elf_proc_note->thread_note->fpx_regset = linux_get_fpx_regset(dbg, thread_id[i]);
1209  if (!elf_proc_note->thread_note->fpx_regset) {
1210  goto fail;
1211  }
1212  }
1213 #endif
1214 #if __i386__ || __x86_64__
1215  if (xsave_flag) {
1216  elf_proc_note->thread_note->xsave_data = linux_get_xsave_data(dbg, thread_id[i],
1217  note_info[NT_X86_XSTATE_T].size);
1218  if (!elf_proc_note->thread_note->xsave_data) {
1219  goto fail;
1220  }
1221  }
1222 #elif __arm__ || __arm64__
1223  if (vfp_flag) {
1224  elf_proc_note->thread_note->arm_vfp_data = linux_get_arm_vfp_data(dbg, thread_id[i]);
1225  if (!elf_proc_note->thread_note->arm_vfp_data) {
1226  goto fail;
1227  }
1228  }
1229 #endif
1230  type = NT_PRSTATUS_T;
1231  write_note_hdr(type, &note_data);
1232  memcpy(note_data, note_info[type].name, note_info[type].size_name);
1233  note_data += note_info[type].size_name;
1234  memcpy(note_data, elf_proc_note->thread_note->prstatus, note_info[type].size);
1235  note_data += note_info[type].size_roundedup;
1236 
1237  type = NT_FPREGSET_T;
1238  write_note_hdr(type, &note_data);
1239  memcpy(note_data, note_info[type].name, note_info[type].size_name);
1240  note_data += note_info[type].size_name;
1241  memcpy(note_data, elf_proc_note->thread_note->fp_regset, note_info[type].size);
1242  note_data += note_info[type].size_roundedup;
1243 #if __i386__
1244  if (fpx_flag) {
1245  type = NT_PRXFPREG_T;
1246  write_note_hdr(type, &note_data);
1247  memcpy(note_data, note_info[type].name, note_info[type].size_name);
1248  note_data += note_info[type].size_name;
1249  memcpy(note_data, elf_proc_note->thread_note->fpx_regset, note_info[type].size);
1250  note_data += note_info[type].size_roundedup;
1251  RZ_FREE(elf_proc_note->thread_note->fpx_regset);
1252  }
1253 #endif
1254  type = NT_SIGINFO_T;
1255  write_note_hdr(type, &note_data);
1256  memcpy(note_data, note_info[type].name, note_info[type].size_name);
1257  note_data += note_info[type].size_name;
1258  memcpy(note_data, elf_proc_note->thread_note->fp_regset, note_info[type].size);
1259  note_data += note_info[type].size_roundedup;
1260 
1261 #if __arm__ || __arm64
1262  if (vfp_flag) {
1263  type = NT_ARM_VFP_T;
1264  write_note_hdr(type, &note_data);
1265  memcpy(note_data, note_info[type].name, note_info[type].size_name);
1266  note_data += note_info[type].size_name;
1267  memcpy(note_data, elf_proc_note->thread_note->arm_vfp_data, note_info[type].size);
1268  note_data += note_info[type].size_roundedup;
1269  RZ_FREE(elf_proc_note->thread_note->arm_vfp_data);
1270  }
1271 #endif
1272 
1273 #if __i386__ || __x86_64__
1274  if (xsave_flag) {
1275  type = NT_X86_XSTATE_T;
1276  write_note_hdr(type, &note_data);
1277  memcpy(note_data, note_info[type].name, note_info[type].size_name);
1278  note_data += note_info[type].size_name;
1279  memcpy(note_data, elf_proc_note->thread_note->xsave_data, note_info[type].size);
1280  note_data += note_info[type].size_roundedup;
1281  RZ_FREE(elf_proc_note->thread_note->xsave_data);
1282  }
1283 #endif
1284  RZ_FREE(elf_proc_note->thread_note->siginfo);
1285  RZ_FREE(elf_proc_note->thread_note->prstatus);
1286  RZ_FREE(elf_proc_note->thread_note->fp_regset);
1287  }
1288  free(elf_proc_note->thread_note);
1289  }
1290  type = NT_AUXV_T;
1291  write_note_hdr(type, &note_data);
1292  memcpy(note_data, note_info[type].name, note_info[type].size_name);
1293  note_data += note_info[type].size_name;
1294  memcpy(note_data, elf_proc_note->auxv->data, note_info[type].size);
1295  note_data += note_info[type].size_roundedup;
1296 
1297  type = NT_FILE_T;
1298  write_note_hdr(type, &note_data);
1299  memcpy(note_data, note_info[type].name, note_info[type].size_name);
1300  note_data += note_info[type].size_name;
1301  memcpy(note_data, maps_data, note_info[type].size);
1302  note_data += note_info[type].size_roundedup;
1303 
1304  detach_threads(dbg, thread_id, elf_proc_note->n_threads);
1305  free(thread_id);
1306  free(maps_data);
1307  return pnote_data;
1308 fail:
1309  if (elf_proc_note->thread_note) {
1310  free(elf_proc_note->thread_note->siginfo);
1311  free(elf_proc_note->thread_note->prstatus);
1312  free(elf_proc_note->thread_note->fp_regset);
1313 #if __i386__
1314  free(elf_proc_note->thread_note->fpx_regset);
1315 #endif
1316 #if __i386__ || __x86_64__
1317  free(elf_proc_note->thread_note->xsave_data);
1318 #elif __arm__ || __arm64__
1319  free(elf_proc_note->thread_note->arm_vfp_data);
1320 #endif
1321  }
1322  free(pnote_data);
1323  free(maps_data);
1324  free(thread_id);
1325  return NULL;
1326 }
1327 
1328 #if __i386__ || __x86_64__
1329 static int get_xsave_size(RzDebug *dbg, int pid) {
1330 #ifdef PTRACE_GETREGSET
1331  struct iovec local;
1332  unsigned long xstate_hdr[XSTATE_HDR_SIZE / sizeof(unsigned long)];
1333  unsigned long xcr0;
1334 
1335  /*We request with NT_X86_XSTATE. Maybe our PC does not have xsave flag. In that case errno would be -ENODEV.
1336  We could also check this by cpuid instruction https://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits*/
1337  local.iov_base = xstate_hdr;
1338  local.iov_len = sizeof(xstate_hdr);
1340  return 0;
1341  }
1342 
1343  xcr0 = xstate_hdr[XCR0_OFFSET / sizeof(unsigned long)];
1344  switch (xcr0) {
1345  case XSTATE_SSE_MASK:
1346  return XSTATE_SSE_SIZE;
1347  case XSTATE_AVX_MASK:
1348  return XSTATE_AVX_SIZE;
1349  case XSTATE_MPX_MASK:
1350  return XSTATE_MPX_SIZE;
1351  case XSTATE_AVX512_MASK:
1352  return XSTATE_FULL_SIZE;
1353  default:
1354  return 0;
1355  }
1356 #else
1357  return 0;
1358 #endif
1359 }
1360 #endif
1361 
1362 #if __i386__
1363 static int get_i386_fpx_size(void) {
1364 #ifdef PTRACE_GETREGSET
1365  return sizeof(elf_fpxregset_t);
1366 #else
1367  return 0;
1368 #endif
1369 }
1370 #endif
1371 
1372 #if __arm__ || __arm64__
1373 static int get_arm_vfpregs_size(void) {
1374 #ifdef PTRACE_GETVFPREGS
1375  return ARM_VFPREGS_SIZE;
1376 #else
1377  return 0;
1378 #endif
1379 }
1380 #endif
1381 
1382 static void init_note_info_structure(RzDebug *dbg, int pid, size_t auxv_size) {
1383  note_type_t type;
1384  int len_name_core = round_up(strlen("CORE") + 1);
1385  int len_name_linux = round_up(strlen("LINUX") + 1);
1386 
1387  /* NT_PRPSINFO_T */;
1388  type = NT_PRPSINFO_T;
1389  note_info[type].size = sizeof(prpsinfo_t);
1390  note_info[type].size_roundedup = sizeof_round_up(prpsinfo_t);
1391  note_info[type].size_name = len_name_core;
1392  strncpy(note_info[type].name, "CORE", sizeof(note_info[type].name));
1393  /* NT_AUXV_T */
1394  type = NT_AUXV_T;
1395  note_info[type].size = auxv_size;
1396  note_info[type].size_roundedup = round_up(auxv_size);
1397  note_info[type].size_name = len_name_core;
1398  strncpy(note_info[type].name, "CORE", sizeof(note_info[type].name));
1399  /* NT_FILE_T */
1400  type = NT_FILE_T;
1401  note_info[type].size = mapping_file.size;
1402  note_info[type].size_roundedup = round_up(mapping_file.size);
1403  note_info[type].size_name = len_name_core;
1404  strncpy(note_info[type].name, "CORE", sizeof(note_info[type].name));
1405  /* NT_PRSTATUS_T */
1406  type = NT_PRSTATUS_T;
1407  note_info[type].size = sizeof(prstatus_t);
1408  note_info[type].size_roundedup = sizeof_round_up(prstatus_t);
1409  note_info[type].size_name = len_name_core;
1410  strncpy(note_info[type].name, "CORE", sizeof(note_info[type].name));
1411  /* NT_SIGINFO_T */
1412  type = NT_SIGINFO_T;
1413  note_info[type].size = sizeof(siginfo_t);
1414  note_info[type].size_roundedup = sizeof_round_up(siginfo_t);
1415  note_info[type].size_name = len_name_core;
1416  strncpy(note_info[type].name, "CORE", sizeof(note_info[type].name));
1417  /* NT_FPREGSET_T */
1418  type = NT_FPREGSET_T;
1419  note_info[type].size = sizeof(elf_fpregset_t);
1420  note_info[type].size_roundedup = sizeof_round_up(elf_fpregset_t);
1421  note_info[type].size_name = len_name_core;
1422  strncpy(note_info[type].name, "CORE", sizeof(note_info[type].name));
1423 #if __i386__
1424  type = NT_PRXFPREG_T;
1425  note_info[type].size = get_i386_fpx_size();
1426  note_info[type].size_roundedup = sizeof_round_up(elf_fpxregset_t);
1427  note_info[type].size_name = len_name_core;
1428  strncpy(note_info[type].name, "CORE", sizeof(note_info[type].name));
1429  type++;
1430 #endif
1431 #if __x86_64__ || __i386__
1432  /* NT_X86_XSTATE_T */
1433  type = NT_X86_XSTATE_T;
1434  note_info[type].size = get_xsave_size(dbg, pid);
1435  note_info[type].size_roundedup = round_up(note_info[type].size);
1436  note_info[type].size_name = len_name_linux;
1437  strncpy(note_info[type].name, "LINUX", sizeof(note_info[type].name));
1438 #elif __arm__ || __arm64__
1439  /* NT_ARM_VFP_T */
1440  type = NT_ARM_VFP_T;
1441  note_info[type].size = get_arm_vfpregs_size();
1442  note_info[type].size_roundedup = round_up(note_info[type].size);
1443  note_info[type].size_name = len_name_linux;
1444  strncpy(note_info[type].name, "LINUX", sizeof(note_info[type].name));
1445 #endif
1446 }
1447 
1449  proc_content_t *proc_data = NULL;
1450  elf_proc_note_t *elf_proc_note = NULL;
1451  elf_shdr_t *shdr_pxnum = NULL;
1452  elf_hdr_t *elf_hdr = NULL;
1453  void *note_data = NULL;
1454  bool error = false;
1455  size_t note_section_size, maps_size = 0;
1456  int n_segments;
1457  ut32 hdr_size;
1458  elf_offset_t offset = 0;
1459 
1460  elf_proc_note = RZ_NEW0(elf_proc_note_t);
1461  if (!elf_proc_note) {
1462  return false;
1463  }
1464  proc_data = RZ_NEW0(proc_content_t);
1465  if (!proc_data) {
1466  free(elf_proc_note);
1467  return false;
1468  }
1469  proc_data->per_process = get_proc_process_content(dbg);
1470  if (!proc_data->per_process) {
1471  free(elf_proc_note);
1472  free(proc_data);
1473  return false;
1474  }
1475  elf_proc_note->n_threads = proc_data->per_process->num_threads;
1476 
1477  /* Get NT_ process_wide: AUXV, MAPS, PRPSINFO */
1478  /* NT_PRPSINFO */
1479  elf_proc_note->prpsinfo = linux_get_prpsinfo(dbg, proc_data->per_process);
1480  if (!elf_proc_note->prpsinfo) {
1481  error = true;
1482  goto cleanup;
1483  }
1484  /* NT_AUXV */
1485  elf_proc_note->auxv = linux_get_auxv(dbg);
1486  if (!elf_proc_note->auxv) {
1487  error = true;
1488  goto cleanup;
1489  }
1490  /* NT_FILE */
1491  elf_proc_note->maps = linux_get_mapped_files(dbg, proc_data->per_process->coredump_filter);
1492  if (!elf_proc_note->maps) {
1493  error = true;
1494  goto cleanup;
1495  }
1496  n_segments = get_info_mappings(elf_proc_note->maps, &maps_size);
1497 
1498  init_note_info_structure(dbg, dbg->pid, elf_proc_note->auxv->size);
1499  note_data = build_note_section(dbg, elf_proc_note, proc_data, &note_section_size);
1500  if (!note_data) {
1501  error = true;
1502  goto cleanup;
1503  }
1504 
1505  elf_hdr = build_elf_hdr(n_segments);
1506  if (!elf_hdr) {
1507  error = true;
1508  goto cleanup;
1509  }
1510 
1511  hdr_size = (proc_data->per_process->coredump_filter & MAP_ELF_HDR) ? elf_hdr->e_ehsize : 0;
1512  if (hdr_size) {
1513  if (elf_hdr->e_phnum == PN_XNUM) {
1514  elf_offset_t offset_shdr;
1515  /* Since extra section header must be placed at the end,
1516  we need to compute the total size to known at which position should be written */
1517  offset_shdr = hdr_size + (elf_hdr->e_phnum * elf_hdr->e_phentsize) + note_section_size + maps_size;
1518  shdr_pxnum = get_extra_sectionhdr(elf_hdr, offset_shdr, n_segments);
1519  }
1520  (void)dump_elf_header(dest, elf_hdr);
1521  }
1522  offset = hdr_size + (elf_hdr->e_phnum * elf_hdr->e_phentsize);
1523 
1524  /* Write to file */
1525  (void)dump_elf_pheaders(dest, elf_proc_note->maps, &offset, note_section_size);
1526  (void)dump_elf_note(dest, note_data, note_section_size);
1527  (void)dump_elf_map_content(dbg, dest, elf_proc_note->maps, dbg->pid);
1528  if (elf_hdr->e_phnum == PN_XNUM) {
1529  (void)dump_elf_sheader_pxnum(dest, shdr_pxnum);
1530  }
1531 cleanup:
1532  may_clean_all(elf_proc_note, proc_data, elf_hdr);
1533  free(shdr_pxnum);
1534  free(note_data);
1535  return !error;
1536 }
1537 #endif
size_t len
Definition: 6502dis.c:15
static char * regs[]
Definition: analysis_sh.c:203
lzma_index ** i
Definition: index.h:629
static RzList * maps(RzBinFile *bf)
Definition: bin_bf.c:116
#define local
Definition: blast.c:36
struct buffer buffer
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags long
Definition: sflib.h:79
uint16_t ut16
uint32_t ut32
RzDebug * dbg
Definition: desil.c:30
RZ_API bool rz_debug_map_sync(RzDebug *dbg)
Definition: dmap.c:33
#define EM_AARCH64
Definition: elf_specs.h:161
size_t map(int syms, int left, int len)
Definition: enough.c:237
void cleanup(void)
Definition: enough.c:244
RZ_API char * sdb_fmt(const char *fmt,...)
Definition: fmt.c:26
#define NT_SIGINFO
Definition: glibc_elf.h:751
#define NT_ARM_VFP
Definition: glibc_elf.h:788
#define PN_XNUM
Definition: glibc_elf.h:698
#define NT_X86_XSTATE
Definition: glibc_elf.h:773
#define NT_FILE
Definition: glibc_elf.h:752
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf uLong offset
Definition: ioapi.h:144
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
void * p
Definition: libc.cpp:67
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
#define SHT_NULL
Definition: common.h:331
#define EM_X86_64
Definition: common.h:151
#define EI_MAG2
Definition: common.h:45
#define ELFMAG0
Definition: common.h:40
#define ET_CORE
Definition: common.h:92
#define ELFMAG3
Definition: common.h:49
#define EI_MAG1
Definition: common.h:42
#define ELFOSABI_NONE
Definition: common.h:64
#define NT_FPREGSET
Definition: common.h:394
#define NT_PRPSINFO
Definition: common.h:395
#define EI_CLASS
Definition: common.h:51
#define ELFCLASS32
Definition: common.h:53
#define ELFMAG1
Definition: common.h:43
#define NT_PRXFPREG
Definition: common.h:398
#define EI_ABIVERSION
Definition: common.h:82
#define PT_NOTE
Definition: common.h:306
#define EM_386
Definition: common.h:105
#define EI_DATA
Definition: common.h:56
#define EV_CURRENT
Definition: common.h:298
#define PT_LOAD
Definition: common.h:303
#define EI_OSABI
Definition: common.h:63
#define ELFMAG2
Definition: common.h:46
#define NT_PRSTATUS
Definition: common.h:393
#define ELFCLASS64
Definition: common.h:54
#define EI_VERSION
Definition: common.h:61
#define SHN_UNDEF
Definition: common.h:505
#define EI_MAG0
Definition: common.h:39
#define NT_AUXV
Definition: common.h:397
#define EI_MAG3
Definition: common.h:48
#define EM_ARM
Definition: common.h:129
#define PF_R
Definition: common.h:324
#define EI_PAD
Definition: common.h:84
#define ELFDATA2LSB
Definition: common.h:58
#define EI_NIDENT
Definition: internal.h:43
#define basename
Definition: libiberty.h:109
static void list(RzEgg *egg)
Definition: rz-gg.c:52
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")
#define IO_FLAG
#define SH_FLAG
#define MAP_ANON_PRIV
#define MAP_ELF_HDR
#define MAP_HUG_SHR
#define MAP_FILE_SHR
#define MAP_FILE_PRIV
note_type_t
@ NT_PRSTATUS_T
@ NT_LENGHT_T
@ NT_AUXV_T
@ NT_FILE_T
@ NT_SIGINFO_T
@ NT_PRPSINFO_T
@ NT_FPREGSET_T
bool linux_generate_corefile(RzDebug *dbg, RzBuffer *dest)
#define PV_FLAG
#define HT_FLAG
#define ADD_MAP_NODE(p)
#define MAP_ANON_SHR
#define SIZE_NT_FILE_DESCSZ
#define MAP_HUG_PRIV
#define DD_FLAG
long rz_debug_ptrace_get_x86_xstate(RzDebug *dbg, pid_t pid, struct iovec *iov)
Definition: linux_debug.c:50
char * dest
Definition: lz4.h:697
int type
Definition: mipsasm.c:17
#define eprintf(x, y...)
Definition: rlcc.c:7
RZ_API bool rz_buf_append_bytes(RZ_NONNULL RzBuffer *b, RZ_NONNULL const ut8 *buf, ut64 len)
Append an array of bytes to the buffer.
Definition: buf.c:732
RZ_API const char * rz_file_basename(const char *path)
Definition: file.c:83
RZ_API RZ_OWN char * rz_file_slurp(const char *str, RZ_NULLABLE size_t *usz)
Definition: file.c:454
RZ_API void * rz_mem_dup(const void *s, int l)
Definition: mem.c:319
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
#define PFMTSZd
Definition: rz_types.h:398
#define RZ_PERM_R
Definition: rz_types.h:93
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_PERM_W
Definition: rz_types.h:94
#define RZ_FREE(x)
Definition: rz_types.h:369
#define PFMT64x
Definition: rz_types.h:393
#define st64
Definition: rz_types_base.h:10
#define isspace(c)
Definition: safe-ctype.h:141
#define isdigit(c)
Definition: safe-ctype.h:131
int pid_t
Definition: sftypes.h:38
@ PTRACE_GETREGS
Definition: sftypes.h:598
@ PTRACE_ATTACH
Definition: sftypes.h:617
@ PTRACE_GETFPREGS
Definition: sftypes.h:608
@ PTRACE_DETACH
Definition: sftypes.h:621
#define h(i)
Definition: sha256.c:48
Definition: buffer.h:15
Definition: zipcmp.c:77
Definition: gzappend.c:170
Definition: sftypes.h:73
unsigned long end_addr
bool dumpeable
ut8 perms
unsigned long start_addr
bool anonymous
char * name
bool file_backed
struct linux_map_entry * n
bool shared
bool kernel_mapping
unsigned long offset
Definition: z80asm.h:102
proc_per_process_t * per_process
proc_per_thread_t * per_thread
auxv_buff_t * auxv
prpsinfo_t * prpsinfo
thread_elf_note_t * thread_note
linux_map_entry_t * maps
unsigned char coredump_filter
RzList *(* threads)(RzDebug *dbg, int pid)
Definition: rz_debug.h:375
RzList * maps
Definition: rz_debug.h:306
struct rz_debug_plugin_t * cur
Definition: rz_debug.h:295
RzIOBind iob
Definition: rz_debug.h:293
RzIOReadAt read_at
Definition: rz_io.h:240
RzIO * io
Definition: rz_io.h:232
siginfo_t * siginfo
elf_fpregset_t * fp_regset
prstatus_t * prstatus
#define fail(test)
Definition: tests.h:29
void error(const char *msg)
Definition: untgz.c:593
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
ut64(WINAPI *w32_GetEnabledXStateFeatures)()