コード例 #1
0
ファイル: libltrace.c プロジェクト: mer-tools/ltrace
void
ltrace_init(int argc, char **argv) {
	struct opt_p_t *opt_p_tmp;

	atexit(normal_exit);
	signal(SIGINT, signal_exit);	/* Detach processes when interrupted */
	signal(SIGTERM, signal_exit);	/*  ... or killed */

	argv = process_options(argc, argv);
	init_global_config();
	while (opt_F) {
		/* If filename begins with ~, expand it to the user's home */
		/* directory. This does not correctly handle ~yoda, but that */
		/* isn't as bad as it seems because the shell will normally */
		/* be doing the expansion for us; only the hardcoded */
		/* ~/.ltrace.conf should ever use this code. */
		if (opt_F->filename[0] == '~') {
			char path[PATH_MAX];
			char *home_dir = getenv("HOME");
			if (home_dir) {
				strncpy(path, home_dir, PATH_MAX - 1);
				path[PATH_MAX - 1] = '\0';
				strncat(path, opt_F->filename + 1,
						PATH_MAX - strlen(path) - 1);
				read_config_file(path);
			}
		} else {
			read_config_file(opt_F->filename);
		}

		struct opt_F_t *next = opt_F->next;
		if (opt_F->own_filename)
			free(opt_F->filename);
		free(opt_F);
		opt_F = next;
	}
	if (command) {
		/* Check that the binary ABI is supported before
		 * calling execute_program.  */
		struct ltelf lte = {};
		open_elf(&lte, command);
		do_close_elf(&lte);

		pid_t pid = execute_program(command, argv);
		struct Process *proc = open_program(command, pid);
		if (proc == NULL) {
			fprintf(stderr, "couldn't open program '%s': %s\n",
				command, strerror(errno));
			exit(EXIT_FAILURE);
		}

		trace_set_options(proc);
		continue_process(pid);
	}
	opt_p_tmp = opt_p;
	while (opt_p_tmp) {
		open_pid(opt_p_tmp->pid);
		opt_p_tmp = opt_p_tmp->next;
	}
}
コード例 #2
0
ファイル: pvs.c プロジェクト: jff/mathspad
void pvs_start(Char *title)
{
  pvs_after_init=0;
  pvs_in_checker=0;
  open_program(translate("pvsscript %i &"), title, pvs_parse);
  pvs_get_templates();
}
コード例 #3
0
ファイル: proc.c プロジェクト: daljung/ltrace_android
void
open_pid(pid_t pid) {
	Process *proc;
	char *filename;

	if (trace_pid(pid) < 0) {
		fprintf(stderr, "Cannot attach to pid %u: %s\n", pid,
			strerror(errno));
		return;
	}

	filename = pid2name(pid);

	if (!filename) {
		fprintf(stderr, "Cannot trace pid %u: %s\n", pid,
				strerror(errno));
		return;
	}

	proc = open_program(filename, pid);
	continue_process(pid);
    proc->breakpoints_enabled = 1;
    //modify for android
    attach_child_thread(proc);
}
コード例 #4
0
ファイル: libltrace.c プロジェクト: KapJlcoH/ltrace
void
ltrace_init(int argc, char **argv) {
	struct opt_p_t *opt_p_tmp;

#ifdef HAVE_PYTHON
	Py_Initialize();
#endif

	atexit(normal_exit);
	signal(SIGINT, signal_exit);	/* Detach processes when interrupted */
	signal(SIGTERM, signal_exit);	/*  ... or killed */

	argv = process_options(argc, argv);
	while (opt_F) {
		/* If filename begins with ~, expand it to the user's home */
		/* directory. This does not correctly handle ~yoda, but that */
		/* isn't as bad as it seems because the shell will normally */
		/* be doing the expansion for us; only the hardcoded */
		/* ~/.ltrace.conf should ever use this code. */
		if (opt_F->filename[0] == '~') {
			char path[PATH_MAX];
			char *home_dir = getenv("HOME");
			if (home_dir) {
				strncpy(path, home_dir, PATH_MAX - 1);
				path[PATH_MAX - 1] = '\0';
				strncat(path, opt_F->filename + 1,
						PATH_MAX - strlen(path) - 1);
				read_config_file(path);
			}
		} else {
			read_config_file(opt_F->filename);
		}
		opt_F = opt_F->next;
	}
	if (opt_e) {
		struct opt_e_t *tmp = opt_e;
		while (tmp) {
			debug(1, "Option -e: %s\n", tmp->name);
			tmp = tmp->next;
		}
	}
	if (command) {
		/* Check that the binary ABI is supported before
		 * calling execute_program.  */
		struct ltelf lte = {};
		open_elf(&lte, command);

		open_program(command, execute_program(command, argv), 0);
	}
	opt_p_tmp = opt_p;
	while (opt_p_tmp) {
		open_pid(opt_p_tmp->pid);
		opt_p_tmp = opt_p_tmp->next;
	}
}
void
ltrace_init(int argc, char **argv)
{
	setlocale(LC_ALL, "");

	struct opt_p_t *opt_p_tmp;

	atexit(normal_exit);
	signal(SIGINT, signal_exit);	/* Detach processes when interrupted */
	signal(SIGTERM, signal_exit);	/*  ... or killed */

	argv = process_options(argc, argv);
	init_global_config();

	if (command) {
		/* Check that the binary ABI is supported before
		 * calling execute_program.  */
		{
			struct ltelf lte;
			if (ltelf_init(&lte, command) == 0)
				ltelf_destroy(&lte);
			else
				exit(EXIT_FAILURE);
		}

		pid_t pid = execute_program(command, argv);
		struct process *proc = open_program(command, pid);
		if (proc == NULL) {
			fprintf(stderr, "couldn't open program '%s': %s\n",
				command, strerror(errno));
			exit(EXIT_FAILURE);
		}

		trace_set_options(proc);
		continue_process(pid);
	}
	opt_p_tmp = opt_p;
	while (opt_p_tmp) {
		open_pid(opt_p_tmp->pid);
		opt_p_tmp = opt_p_tmp->next;
	}
}
コード例 #6
0
ファイル: proc.c プロジェクト: mer-tools/ltrace
int
process_clone(struct Process *retp, struct Process *proc, pid_t pid)
{
	if (process_bare_init(retp, proc->filename, pid, 0) < 0) {
	fail1:
		fprintf(stderr, "failed to clone process %d->%d : %s\n",
			proc->pid, pid, strerror(errno));
		return -1;
	}

	retp->tracesysgood = proc->tracesysgood;
	retp->e_machine = proc->e_machine;
	retp->e_class = proc->e_class;

	/* For non-leader processes, that's all we need to do.  */
	if (retp->leader != retp)
		return 0;

	/* Clone symbols first so that we can clone and relink
	 * breakpoints.  */
	struct library *lib;
	struct library **nlibp = &retp->libraries;
	for (lib = proc->leader->libraries; lib != NULL; lib = lib->next) {
		*nlibp = malloc(sizeof(**nlibp));
		if (*nlibp == NULL
		    || library_clone(*nlibp, lib) < 0) {
		fail2:
			process_bare_destroy(retp, 0);

			/* Error when cloning.  Unroll what was done.  */
			for (lib = retp->libraries; lib != NULL; ) {
				struct library *next = lib->next;
				library_destroy(lib);
				free(lib);
				lib = next;
			}
			goto fail1;
		}

		nlibp = &(*nlibp)->next;
	}

	/* Now clone breakpoints.  Symbol relinking is done in
	 * clone_single_bp.  */
	struct clone_single_bp_data data = {
		.old_proc = proc,
		.new_proc = retp,
		.error = 0,
	};
	dict_apply_to_all(proc->leader->breakpoints, &clone_single_bp, &data);
	if (data.error < 0)
		goto fail2;

	/* And finally the call stack.  */
	/* XXX clearly the callstack handling should be moved to a
	 * separate module and this whole business extracted to
	 * callstack_clone, or callstack_element_clone.  */
	memcpy(retp->callstack, proc->callstack, sizeof(retp->callstack));
	retp->callstack_depth = proc->callstack_depth;

	size_t i;
	for (i = 0; i < retp->callstack_depth; ++i) {
		struct callstack_element *elem = &retp->callstack[i];
		struct fetch_context *ctx = elem->fetch_context;
		if (ctx != NULL) {
			struct fetch_context *nctx = fetch_arg_clone(retp, ctx);
			if (nctx == NULL) {
				size_t j;
			fail3:
				for (j = 0; j < i; ++j) {
					nctx = elem->fetch_context;
					fetch_arg_done(nctx);
					elem->fetch_context = NULL;
				}
				goto fail2;
			}
			elem->fetch_context = nctx;
		}

		struct value_dict *args = elem->arguments;
		if (args != NULL) {
			struct value_dict *nargs = malloc(sizeof(*nargs));
			if (nargs == NULL
			    || val_dict_clone(nargs, args) < 0) {
				size_t j;
				for (j = 0; j < i; ++j) {
					nargs = elem->arguments;
					val_dict_destroy(nargs);
					free(nargs);
					elem->arguments = NULL;
				}

				/* Pretend that this round went well,
				 * so that fail3 frees I-th
				 * fetch_context.  */
				++i;
				goto fail3;
			}
			elem->arguments = nargs;
		}

		/* If it's not a syscall, we need to find the
		 * corresponding library symbol in the cloned
		 * library.  */
		if (!elem->is_syscall && elem->c_un.libfunc != NULL) {
			struct library_symbol *libfunc = elem->c_un.libfunc;
			int rc = proc_find_symbol(retp, libfunc,
						  NULL, &elem->c_un.libfunc);
			assert(rc == 0);
		}
	}

	/* At this point, retp is fully initialized, except for OS and
	 * arch parts, and we can call private_process_destroy.  */
	if (os_process_clone(retp, proc) < 0) {
		private_process_destroy(retp, 0);
		return -1;
	}
	if (arch_process_clone(retp, proc) < 0) {
		os_process_destroy(retp);
		private_process_destroy(retp, 0);
		return -1;
	}

	return 0;
}

static int
open_one_pid(pid_t pid)
{
	Process *proc;
	char *filename;
	debug(DEBUG_PROCESS, "open_one_pid(pid=%d)", pid);

	/* Get the filename first.  Should the trace_pid fail, we can
	 * easily free it, untracing is more work.  */
	if ((filename = pid2name(pid)) == NULL
	    || trace_pid(pid) < 0) {
	fail:
		free(filename);
		return -1;
	}

	proc = open_program(filename, pid);
	if (proc == NULL)
		goto fail;
	free(filename);
	trace_set_options(proc);

	return 0;
}
コード例 #7
0
/*
 * Open an ELF file and load it into memory.
 */
static Elf32_Addr load_elf_file(const char *filename,
                                size_t pagesize,
                                Elf32_Addr *out_base,
                                Elf32_Addr *out_phdr,
                                Elf32_Addr *out_phnum,
                                const char **out_interp) {
  int fd = open_program(filename);
  if (fd < 0) {
    fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno));
    exit(2);
  }

  uintptr_t pread_pos = 0;
  Elf32_Ehdr ehdr;
  my_pread(filename, "Failed to read ELF header from file!  ",
           fd, &ehdr, sizeof(ehdr), 0, &pread_pos);

  if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
      ehdr.e_version != EV_CURRENT ||
      ehdr.e_ehsize != sizeof(ehdr) ||
      ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
    fprintf(stderr, "%s has no valid ELF header!\n", filename);
    exit(1);
  }

  switch (ehdr.e_machine) {
#if defined(__i386__)
    case EM_386:
#elif defined(__x86_64__)
    case EM_X86_64:
#elif defined(__arm__)
    case EM_ARM:
#elif defined(__mips__)
    case EM_MIPS:
#else
# error "Don't know the e_machine value for this architecture!"
#endif
      break;
    default:
      fprintf(stderr,
              "%s: ELF file has wrong architecture (e_machine=%u)\n",
              filename, ehdr.e_machine);
      exit(1);
  }

  Elf32_Phdr phdr[MAX_PHNUM];
  if (ehdr.e_phnum > sizeof(phdr) / sizeof(phdr[0]) || ehdr.e_phnum < 1) {
    fprintf(stderr, "%s: ELF file has unreasonable e_phnum=%u\n",
            filename, ehdr.e_phnum);
    exit(1);
  }

  bool anywhere;
  switch (ehdr.e_type) {
    case ET_EXEC:
      anywhere = false;
      break;
    case ET_DYN:
      anywhere = true;
      break;
    default:
      fprintf(stderr, "%s: ELF file has unexpected e_type=%u\n",
              filename, ehdr.e_type);
      exit(1);
  }

  my_pread(filename, "Failed to read program headers from ELF file!  ",
           fd, phdr, sizeof(phdr[0]) * ehdr.e_phnum, ehdr.e_phoff, &pread_pos);

  size_t i = 0;
  while (i < ehdr.e_phnum && phdr[i].p_type != PT_LOAD)
    ++i;
  if (i == ehdr.e_phnum) {
    fprintf(stderr, "%s: ELF file has no PT_LOAD header!", filename);
    exit(1);
  }

  /*
   * ELF requires that PT_LOAD segments be in ascending order of p_vaddr.
   * Find the last one to calculate the whole address span of the image.
   */
  const Elf32_Phdr *first_load = &phdr[i];
  const Elf32_Phdr *last_load = &phdr[ehdr.e_phnum - 1];
  while (last_load > first_load && last_load->p_type != PT_LOAD)
    --last_load;

  /*
   * For NaCl, the first load segment must always be the code segment.
   */
  if (first_load->p_flags != (PF_R | PF_X)) {
    fprintf(stderr, "%s: First PT_LOAD has p_flags=%#x (expecting RX=%#x)\n",
            filename, first_load->p_flags, PF_R | PF_X);
    exit(1);
  }
  if (first_load->p_filesz != first_load->p_memsz) {
    fprintf(stderr, "%s: Code segment has p_filesz %u != p_memsz %u\n",
            filename, first_load->p_filesz, first_load->p_memsz);
    exit(1);
  }

  /*
   * Decide where to load the image and reserve the portions of the address
   * space where it will reside.
   */
  Elf32_Addr load_bias = choose_load_bias(filename, pagesize,
                                          first_load, last_load, anywhere);
  DEBUG_PRINTF("XXX load_bias (%s) %#x\n",
               anywhere ? "anywhere" : "fixed",
               load_bias);

  /*
   * Map the code segment in.
   */
  my_mmap(filename, "code segment", first_load - phdr,
          load_bias + round_down(first_load->p_vaddr, pagesize),
          first_load->p_memsz, prot_from_phdr(first_load),
          MAP_PRIVATE | MAP_FIXED, fd,
          round_down(first_load->p_offset, pagesize));

  Elf32_Addr last_end = first_load->p_vaddr + load_bias + first_load->p_memsz;
  Elf32_Addr last_page_end = round_up(last_end, pagesize);

  /*
   * Map the remaining segments, and protect any holes between them.
   * The large hole after the code segment does not need to be
   * protected (and cannot be).  It covers the whole large tail of the
   * dynamic text area, which cannot be touched by mprotect.
   */
  const Elf32_Phdr *ph;
  for (ph = first_load + 1; ph <= last_load; ++ph) {
    if (ph->p_type == PT_LOAD) {
      Elf32_Addr start = round_down(ph->p_vaddr + load_bias, pagesize);

      if (start > last_page_end && ph > first_load + 1) {
        if (mprotect((void *) last_page_end, start - last_page_end,
                     PROT_NONE) != 0) {
          fprintf(stderr, "%s: Failed to mprotect segment %u hole! (%s)\n",
                  filename, ph - phdr, strerror(errno));
          exit(1);
        }
      }

      last_end = ph->p_vaddr + load_bias + ph->p_memsz;
      last_page_end = round_up(last_end, pagesize);
      Elf32_Addr map_end = last_page_end;

      /*
       * Unlike POSIX mmap, NaCl's mmap does not reliably handle COW
       * faults in the remainder of the final partial page.  So to get
       * the expected behavior for the unaligned boundary between data
       * and bss, it's necessary to allocate the final partial page of
       * data as anonymous memory rather than mapping it from the file.
       */
      Elf32_Addr file_end = ph->p_vaddr + load_bias + ph->p_filesz;
      if (ph->p_memsz > ph->p_filesz)
        map_end = round_down(file_end, pagesize);

      if (map_end > start) {
        my_mmap(filename, "segment", ph - phdr,
                start, map_end - start,
                prot_from_phdr(ph), MAP_PRIVATE | MAP_FIXED, fd,
                round_down(ph->p_offset, pagesize));
      }

      if (map_end < last_page_end) {
        /*
         * Handle the "bss" portion of a segment, where the memory size
         * exceeds the file size and we zero-fill the difference.  We map
         * anonymous pages for all the pages containing bss space.  Then,
         * if there is any partial-page tail of the file data, we read that
         * into the first such page.
         *
         * This scenario is invalid for an unwritable segment.
         */

        if ((ph->p_flags & PF_W) == 0) {
          fprintf(stderr,
                  "%s: Segment %u has p_memsz %u > p_filesz %u but no PF_W!\n",
                  filename, ph - phdr, ph->p_memsz, ph->p_filesz);
          exit(1);
        }

        my_mmap(filename, "bss segment", ph - phdr,
                map_end, last_page_end - map_end, prot_from_phdr(ph),
                MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);

        if (file_end > map_end) {
          /*
           * There is a partial page of data to read in.
           */
          my_pread(filename, "Failed to read final partial page of data!  ",
                   fd, (void *) map_end, file_end - map_end,
                   round_down(ph->p_offset + ph->p_filesz, pagesize),
                   &pread_pos);
        }
      }
    }
  }

  /*
   * We've finished with the file now.
   */
  close(fd);

  /*
   * Find the PT_INTERP header, if there is one.
   */
  const Elf32_Phdr *interp = NULL;
  if (out_interp != NULL) {
    for (i = 0; i < ehdr.e_phnum; ++i) {
      if (phdr[i].p_type == PT_INTERP) {
        interp = &phdr[i];
        break;
      }
    }
  }

  /*
   * Find the PT_LOAD segments containing the PT_INTERP data and the phdrs.
   */
  for (ph = first_load;
       ph <= last_load && (interp != NULL || out_phdr != NULL);
       ++ph) {
    if (interp != NULL &&
        segment_contains(ph, interp->p_offset, interp->p_filesz)) {
      *out_interp = (const char *) (interp->p_vaddr + load_bias);
      interp = NULL;
    }
    if (out_phdr != NULL &&
        segment_contains(ph, ehdr.e_phoff, ehdr.e_phnum * sizeof(phdr[0]))) {
      *out_phdr = ehdr.e_phoff - ph->p_offset + ph->p_vaddr + load_bias;
      out_phdr = NULL;
    }
  }

  if (interp != NULL) {
    fprintf(stderr, "%s: PT_INTERP not within any PT_LOAD segment\n",
            filename);
    exit(1);
  }

  if (out_phdr != NULL) {
    *out_phdr = 0;
    fprintf(stderr,
            "Warning: %s: ELF program headers not within any PT_LOAD segment\n",
            filename);
  }

  if (out_phnum != NULL)
    *out_phnum = ehdr.e_phnum;

  if (out_base != NULL)
    *out_base = load_bias;

  return ehdr.e_entry + load_bias;
}