/*
 * Acquire ticket lock. Increment the tail of the queue and use the original
 * value as the ticket value. Wait until the head of the queue equals the
 * ticket value. The futex used to wait depends on the ticket value in order
 * to avoid that all threads get woken up every time a ticket lock is
 * released. That last effect is sometimes called the "thundering herd"
 * effect.
 *
 * See also Nick Piggin, x86: FIFO ticket spinlocks, Linux kernel mailing list
 * (http://lkml.org/lkml/2007/11/1/125) for more info.
 */
static void acquire_sched_lock(struct sched_lock *p)
{
   unsigned ticket, futex_value;
   volatile unsigned *futex;
   SysRes sres;

   ticket = __sync_fetch_and_add(&p->tail, 1);
   futex = &p->futex[ticket & TL_FUTEX_MASK];
   if (s_debug)
      VG_(printf)("[%d/%d] acquire: ticket %u\n", VG_(getpid)(),
                  VG_(gettid)(), ticket);
   for (;;) {
      futex_value = *futex;
      __sync_synchronize();
      if (ticket == p->head)
         break;
      if (s_debug)
         VG_(printf)("[%d/%d] acquire: ticket %u - waiting until"
                     " futex[%ld] != %u\n", VG_(getpid)(),
                     VG_(gettid)(), ticket, (long)(futex - p->futex),
                     futex_value);
      sres = VG_(do_syscall3)(__NR_futex, (UWord)futex,
                              VKI_FUTEX_WAIT | VKI_FUTEX_PRIVATE_FLAG,
                              futex_value);
      if (sr_isError(sres) && sr_Err(sres) != VKI_EAGAIN) {
         VG_(printf)("futex_wait() returned error code %lu\n", sr_Err(sres));
         vg_assert(False);
      }
   }
   __sync_synchronize();
   INNER_REQUEST(ANNOTATE_RWLOCK_ACQUIRED(p, /*is_w*/1));
   vg_assert(p->owner == 0);
   p->owner = VG_(gettid)();
}
예제 #2
0
static void check_mmap(SysRes res, Addr base, SizeT len)
{
   if (sr_isError(res)) {
      VG_(printf)("valgrind: mmap(0x%llx, %lld) failed in UME "
                  "with error %lu (%s).\n", 
                  (ULong)base, (Long)len, 
                  sr_Err(res), VG_(strerror)(sr_Err(res)) );
      if (sr_Err(res) == VKI_EINVAL) {
         VG_(printf)("valgrind: this can be caused by executables with "
                     "very large text, data or bss segments.\n");
      }
      VG_(exit)(1);
   }
}
예제 #3
0
static Region_map *vrm_determine_local_rm_address()
{
    /*
     * Determine the address of the RE kernel's local RM.
     */

    /*
     * 1. Try to find symbol in ELF image file
     */
    if (dbg_elf) VG_(printf)("opening rom/l4re\n");
    SysRes res = VG_(open)((const Char*)"rom/l4re", VKI_O_RDONLY, 0);
    if (dbg_elf) VG_(printf)("opened: %ld\n", sr_Res(res));
    if (sr_isError(res)) {
        VG_(printf)("Error opening file: %ld\n", sr_Err(res));
        enter_kdebug();
    }

    int fd = sr_Res(res);

    struct vg_stat statbuf;
    int err = VG_(fstat)(fd, &statbuf);
    if (dbg_elf) VG_(printf)("stat: %d, size %d\n", err, (int)statbuf.size);

    if (err) {
        VG_(printf)("error on fstat(): %d\n", err);
        enter_kdebug();
    }

    void *a = 0;
    a = mmap(a, statbuf.size, VKI_PROT_READ, VKI_MAP_PRIVATE, fd, 0);
    if (dbg_elf) VG_(printf)("mmap to %p\n", a);

    melf_global_elf_info i;
    err = melf_parse_elf(a, &i);
    if (dbg_elf) VG_(printf)("parsed: %d\n", err);

    char *rm_addr = melf_find_symbol_by_name(&i, (char*)"__local_rm");
    if (dbg_elf) VG_(printf)("Found symbol %s @ %p\n", (char*)"__local_rm", rm_addr);

    munmap(a, VG_PGROUNDUP(statbuf.size));
    VG_(close)(fd);

    if (rm_addr)
        return reinterpret_cast<Region_map*>(rm_addr);

    /*
     * 2. If not successful parsing binary, try hard-coded value
     */
    VG_(printf)("Did not find local-rm, aborting\n");
    VG_(exit)(1);

    /* Not found? */
}
예제 #4
0
// returns: 0 = success, non-0 is failure
//
// We can execute only binaries (ELF, etc) or scripts that begin with "#!".
// (Not, for example, scripts that don't begin with "#!";  see the
// VG_(do_exec)() invocation from m_main.c for how that's handled.)
Int VG_(do_exec_inner)(const HChar* exe, ExeInfo* info)
{
   SysRes res;
   Int fd;
   Int ret;

   res = VG_(pre_exec_check)(exe, &fd, False/*allow_setuid*/);
   if (sr_isError(res))
      return sr_Err(res);

   vg_assert2(sr_Res(res) >= 0 && sr_Res(res) < EXE_HANDLER_COUNT, 
              "invalid VG_(pre_exec_check) result");

   ret = (*exe_handlers[sr_Res(res)].load_fn)(fd, exe, info);

   VG_(close)(fd);

   return ret;
}
예제 #5
0
static 
struct elfinfo *readelf(Int fd, const char *filename)
{
   SysRes sres;
   struct elfinfo *e = VG_(malloc)("ume.re.1", sizeof(*e));
   Int phsz;

   vg_assert(e);
   e->fd = fd;

   sres = VG_(pread)(fd, &e->e, sizeof(e->e), 0);
   if (sr_isError(sres) || sr_Res(sres) != sizeof(e->e)) {
      VG_(printf)("valgrind: %s: can't read ELF header: %s\n", 
                  filename, VG_(strerror)(sr_Err(sres)));
      goto bad;
   }

   if (VG_(memcmp)(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
      VG_(printf)("valgrind: %s: bad ELF magic number\n", filename);
      goto bad;
   }
   if (e->e.e_ident[EI_CLASS] != VG_ELF_CLASS) {
      VG_(printf)("valgrind: wrong ELF executable class "
                  "(eg. 32-bit instead of 64-bit)\n");
      goto bad;
   }
   if (e->e.e_ident[EI_DATA] != VG_ELF_DATA2XXX) {
      VG_(printf)("valgrind: executable has wrong endian-ness\n");
      goto bad;
   }
   if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
      VG_(printf)("valgrind: this is not an executable\n");
      goto bad;
   }

   if (e->e.e_machine != VG_ELF_MACHINE) {
      VG_(printf)("valgrind: executable is not for "
                  "this architecture\n");
      goto bad;
   }

   if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
      VG_(printf)("valgrind: sizeof ELF Phdr wrong\n");
      goto bad;
   }

   phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
   e->p = VG_(malloc)("ume.re.2", phsz);
   vg_assert(e->p);

   sres = VG_(pread)(fd, e->p, phsz, e->e.e_phoff);
   if (sr_isError(sres) || sr_Res(sres) != phsz) {
      VG_(printf)("valgrind: can't read phdr: %s\n", 
                  VG_(strerror)(sr_Err(sres)));
      VG_(free)(e->p);
      goto bad;
   }

   return e;

  bad:
   VG_(free)(e);
   return NULL;
}
예제 #6
0
// If the do_exec fails we try to emulate what the shell does (I used
// bash as a guide).  It's worth noting that the shell can execute some
// things that VG_(do_exec)() (which subsitutes for the kernel's exec())
// will refuse to (eg. scripts lacking a "#!" prefix).
static Int do_exec_shell_followup(Int ret, const HChar* exe_name, ExeInfo* info)
{
#  if defined(VGPV_arm_linux_android) \
      || defined(VGPV_x86_linux_android) \
      || defined(VGPV_mips32_linux_android) \
      || defined(VGPV_arm64_linux_android)
   const HChar*  default_interp_name = "/system/bin/sh";
#  else
   const HChar*  default_interp_name = "/bin/sh";
#  endif

   SysRes res;
   struct vg_stat st;

   if (VKI_ENOEXEC == ret) {
      // It was an executable file, but in an unacceptable format.  Probably
      // is a shell script lacking the "#!" prefix;  try to execute it so.

      // Is it a binary file?  
      if (is_binary_file(exe_name)) {
         VG_(fmsg)("%s: cannot execute binary file\n", exe_name);
         VG_(exit)(126);      // 126 == NOEXEC
      }

      // Looks like a script.  Run it with /bin/sh.  This includes
      // zero-length files.
      VG_(free)(info->interp_name);
      info->interp_name = VG_(strdup)("ume.desf.1", default_interp_name);
      VG_(free)(info->interp_args); info->interp_args = NULL;
      if (info->argv && info->argv[0] != NULL)
         info->argv[0] = exe_name;

      ret = VG_(do_exec_inner)(info->interp_name, info);

      if (0 != ret) {
         // Something went wrong with executing the default interpreter
         VG_(fmsg)("%s: bad interpreter (%s): %s\n",
                     exe_name, info->interp_name, VG_(strerror)(ret));
         VG_(exit)(126);      // 126 == NOEXEC
      }

   } else if (0 != ret) {
      // Something else went wrong.  Try to make the error more specific,
      // and then print a message and abort.
      Int exit_code = 126;    // 126 == NOEXEC (bash)

      res = VG_(stat)(exe_name, &st);

      // Does the file exist ?
      if (sr_isError(res) && sr_Err(res) == VKI_ENOENT) {
         VG_(fmsg)("%s: %s\n", exe_name, VG_(strerror)(ret));
         exit_code = 127;     // 127 == NOTFOUND (bash)

      // Was it a directory?
      } else if (!sr_isError(res) && VKI_S_ISDIR(st.mode)) {
         VG_(fmsg)("%s: is a directory\n", exe_name);
      
      // Was it not executable?
      } else if (0 != VG_(check_executable)(NULL, exe_name, 
                                            False/*allow_setuid*/)) {
         VG_(fmsg)("%s: %s\n", exe_name, VG_(strerror)(ret));

      // Did it start with "#!"?  If so, it must have been a bad interpreter.
      } else if (is_hash_bang_file(exe_name)) {
         VG_(fmsg)("%s: bad interpreter: %s\n", exe_name, VG_(strerror)(ret));

      // Otherwise it was something else.
      } else {
         VG_(fmsg)("%s: %s\n", exe_name, VG_(strerror)(ret));
      }
      VG_(exit)(exit_code);
   }
   return ret;
}