コード例 #1
0
ファイル: vg_memory.c プロジェクト: svn2github/valgrind-3
void VG_(map_file_segment)(Addr addr, UInt len, UInt prot, UInt flags, 
			   UInt dev, UInt ino, ULong off, const Char *filename)
{
   Segment *s;
   static const Bool debug = False || mem_debug;
   Bool recycled;

   if (debug)
      VG_(printf)("map_file_segment(%p, %d, %x, %x, %4x, %d, %ld, %s)\n",
		  addr, len, prot, flags, dev, ino, off, filename);

   /* Everything must be page-aligned */
   vg_assert((addr & (VKI_BYTES_PER_PAGE-1)) == 0);
   len = PGROUNDUP(len);

   /* First look to see what already exists around here */
   s = VG_(SkipList_Find)(&sk_segments, &addr);

   if (s != NULL && s->addr == addr && s->len == len) {
      /* This probably means we're just updating the flags */
      recycled = True;
      recycleseg(s);

      /* If we had a symtab, but the new mapping is incompatible, then
	 free up the old symtab in preparation for a new one. */
      if (s->symtab != NULL		&&
	  (!(s->flags & SF_FILE)	||
	   !(flags & SF_FILE)		||
	   s->dev != dev		||
	   s->ino != ino		||
	   s->offset != off)) {
	 VG_(symtab_decref)(s->symtab, s->addr, s->len);
	 s->symtab = NULL;
      }
   } else {
      recycled = False;
      VG_(unmap_range)(addr, len);

      s = VG_(SkipNode_Alloc)(&sk_segments);

      s->addr   = addr;
      s->len    = len;
      s->symtab = NULL;
   }

   s->flags  = flags;
   s->prot   = prot;
   s->dev    = dev;
   s->ino    = ino;
   s->offset = off;
   
   if (filename != NULL)
      s->filename = VG_(arena_strdup)(VG_AR_CORE, filename);
   else
      s->filename = NULL;

   if (debug) {
      Segment *ts;
      for(ts = VG_(SkipNode_First)(&sk_segments);
	  ts != NULL;
	  ts = VG_(SkipNode_Next)(&sk_segments, ts))
	 VG_(printf)("list: %8p->%8p ->%d (0x%x) prot=%x flags=%x\n",
		     ts, ts->addr, ts->len, ts->len, ts->prot, ts->flags);

      VG_(printf)("inserting s=%p addr=%p len=%d\n",
		  s, s->addr, s->len);
   }

   if (!recycled)
      VG_(SkipList_Insert)(&sk_segments, s);

   /* If this mapping is of the beginning of a file, isn't part of
      Valgrind, is at least readable and seems to contain an object
      file, then try reading symbols from it. */
   if ((flags & (SF_MMAP|SF_NOSYMS)) == SF_MMAP	&&
       s->symtab == NULL) {
      if (off == 0									&&
	  filename != NULL								&&
	  (prot & (VKI_PROT_READ|VKI_PROT_EXEC)) == (VKI_PROT_READ|VKI_PROT_EXEC)	&&
	  len >= VKI_BYTES_PER_PAGE							&&
	  s->symtab == NULL								&&
	  VG_(is_object_file)((void *)addr)) 
      {
         s->symtab = VG_(read_seg_symbols)(s);

         if (s->symtab != NULL) {
            s->flags |= SF_DYNLIB;
         }
      } else if (flags & SF_MMAP) {
	 const SegInfo *info;

	 /* Otherwise see if an existing symtab applies to this Segment */
	 for(info = VG_(next_seginfo)(NULL);
	     info != NULL;
	     info = VG_(next_seginfo)(info)) {
	    if (VG_(seg_overlaps)(s, VG_(seg_start)(info), VG_(seg_size)(info)))
            {
	       s->symtab = (SegInfo *)info;
	       VG_(symtab_incref)((SegInfo *)info);
	    }
	 }
      }
   }

   /* clean up */
   merge_segments(addr, len);
}
コード例 #2
0
ファイル: readmacho.c プロジェクト: svn2github/valgrind-3
/* Read a symbol table (nlist).  Add the resulting candidate symbols
   to 'syms'; the caller will post-process them and hand them off to
   ML_(addSym) itself. */
static
void read_symtab( /*OUT*/XArray* /* DiSym */ syms,
                  struct _DebugInfo* di, 
                  struct NLIST* o_symtab, UInt o_symtab_count,
                  UChar*     o_strtab, UInt o_strtab_sz )
{
   Int    i;
   Addr   sym_addr;
   DiSym  risym;
   UChar* name;

   static UChar* s_a_t_v = NULL; /* do not make non-static */

   for (i = 0; i < o_symtab_count; i++) {
      struct NLIST *nl = o_symtab+i;
      if ((nl->n_type & N_TYPE) == N_SECT) {
         sym_addr = di->text_bias + nl->n_value;
    /*} else if ((nl->n_type & N_TYPE) == N_ABS) {
         GrP fixme don't ignore absolute symbols?
         sym_addr = nl->n_value; */
      } else {
         continue;
      }
      
      if (di->trace_symtab)
         VG_(printf)("nlist raw: avma %010lx  %s\n",
                     sym_addr, o_strtab + nl->n_un.n_strx );

      /* If no part of the symbol falls within the mapped range,
         ignore it. */
      if (sym_addr <= di->text_avma
          || sym_addr >= di->text_avma+di->text_size) {
         continue;
      }

      /* skip names which point outside the string table;
         following these risks segfaulting Valgrind */
      name = o_strtab + nl->n_un.n_strx;
      if (name < o_strtab || name >= o_strtab + o_strtab_sz)
         continue;

      /* skip nameless symbols; these appear to be common, but
         useless */
      if (*name == 0)
         continue;

      risym.tocptr = 0;
      risym.addr = sym_addr;
      risym.size = // let canonicalize fix it
                   di->text_avma+di->text_size - sym_addr;
      risym.name = ML_(addStr)(di, name, -1);
      risym.isText = True;
      // Lots of user function names get prepended with an underscore.  Eg. the
      // function 'f' becomes the symbol '_f'.  And the "below main"
      // function is called "start".  So we skip the leading underscore, and
      // if we see 'start' and --show-below-main=no, we rename it as
      // "start_according_to_valgrind", which makes it easy to spot later
      // and display as "(below main)".
      if (risym.name[0] == '_') {
         risym.name++;
      } else if (!VG_(clo_show_below_main) && VG_STREQ(risym.name, "start")) {
         if (s_a_t_v == NULL)
            s_a_t_v = ML_(addStr)(di, "start_according_to_valgrind", -1);
         vg_assert(s_a_t_v);
         risym.name = s_a_t_v;
      }

      vg_assert(risym.name);
      VG_(addToXA)( syms, &risym );
   }
}
コード例 #3
0
ファイル: readmacho.c プロジェクト: svn2github/valgrind-3
Bool ML_(read_macho_debug_info)( struct _DebugInfo* di )
{
   struct symtab_command *symcmd = NULL;
   struct dysymtab_command *dysymcmd = NULL;
   HChar* dsymfilename = NULL;
   Bool have_uuid = False;
   UChar uuid[16];
   ImageInfo ii;  /* main file */
   ImageInfo iid; /* auxiliary .dSYM file */
   Bool ok;

   /* mmap the object file to look for di->soname and di->text_bias 
      and uuid and nlist and STABS */

   if (VG_(clo_verbosity) > 1)
      VG_(message)(Vg_DebugMsg,
                   "%s (%#lx)\n", di->filename, di->rx_map_avma );

   /* This should be ensured by our caller. */
   vg_assert(di->have_rx_map);
   vg_assert(di->have_rw_map);

   VG_(memset)(&ii,   0, sizeof(ii));
   VG_(memset)(&iid,  0, sizeof(iid));
   VG_(memset)(&uuid, 0, sizeof(uuid));

   ok = map_image_aboard( di, &ii, di->filename );
   if (!ok) goto fail;

   vg_assert(ii.macho_img != NULL && ii.macho_img_szB > 0);

   /* Poke around in the Mach-O header, to find some important
      stuff. */
   // Find LC_SYMTAB and LC_DYSYMTAB, if present.
   // Read di->soname from LC_ID_DYLIB if present, 
   //    or from LC_ID_DYLINKER if present, 
   //    or use "NONE".
   // Get di->text_bias (aka slide) based on the corresponding LC_SEGMENT
   // Get uuid for later dsym search

   di->text_bias = 0;

   { struct MACH_HEADER *mh = (struct MACH_HEADER *)ii.macho_img;
      struct load_command *cmd;
      Int c;

      for (c = 0, cmd = (struct load_command *)(mh+1);
           c < mh->ncmds;
           c++, cmd = (struct load_command *)(cmd->cmdsize
                                              + (unsigned long)cmd)) {
         if (cmd->cmd == LC_SYMTAB) {
            symcmd = (struct symtab_command *)cmd;
         } 
         else if (cmd->cmd == LC_DYSYMTAB) {
            dysymcmd = (struct dysymtab_command *)cmd;
         } 
         else if (cmd->cmd == LC_ID_DYLIB && mh->filetype == MH_DYLIB) {
            // GrP fixme bundle?
            struct dylib_command *dcmd = (struct dylib_command *)cmd;
            UChar *dylibname = dcmd->dylib.name.offset + (UChar *)dcmd;
            UChar *soname = VG_(strrchr)(dylibname, '/');
            if (!soname) soname = dylibname;
            else soname++;
            di->soname = ML_(dinfo_strdup)("di.readmacho.dylibname",
                                           soname);
         }
         else if (cmd->cmd==LC_ID_DYLINKER  &&  mh->filetype==MH_DYLINKER) {
            struct dylinker_command *dcmd = (struct dylinker_command *)cmd;
            UChar *dylinkername = dcmd->name.offset + (UChar *)dcmd;
            UChar *soname = VG_(strrchr)(dylinkername, '/');
            if (!soname) soname = dylinkername;
            else soname++;
            di->soname = ML_(dinfo_strdup)("di.readmacho.dylinkername",
                                           soname);
         }

         // A comment from Julian about why varinfo[35] fail:
         //
         // My impression is, from comparing the output of otool -l for these
         // executables with the logic in ML_(read_macho_debug_info),
         // specifically the part that begins "else if (cmd->cmd ==
         // LC_SEGMENT_CMD) {", that it's a complete hack which just happens
         // to work ok for text symbols.  In particular, it appears to assume
         // that in a "struct load_command" of type LC_SEGMENT_CMD, the first
         // "struct SEGMENT_COMMAND" inside it is going to contain the info we
         // need.  However, otool -l shows, and also the Apple docs state,
         // that a struct load_command may contain an arbitrary number of
         // struct SEGMENT_COMMANDs, so I'm not sure why it's OK to merely
         // snarf the first.  But I'm not sure about this.
         //
         // The "Try for __DATA" block below simply adds acquisition of data
         // svma/bias values using the same assumption.  It also needs
         // (probably) to deal with bss sections, but I don't understand how
         // this all ties together really, so it requires further study.
         //
         // If you can get your head around the relationship between MachO
         // segments, sections and load commands, this might be relatively
         // easy to fix properly.
         //
         // Basically we need to come up with plausible numbers for di->
         // {text,data,bss}_{avma,svma}, from which the _bias numbers are
         // then trivially derived.  Then I think the debuginfo reader should
         // work pretty well.
         else if (cmd->cmd == LC_SEGMENT_CMD) {
            struct SEGMENT_COMMAND *seg = (struct SEGMENT_COMMAND *)cmd;
            /* Try for __TEXT */
            if (!di->text_present
                && 0 == VG_(strcmp)(seg->segname, "__TEXT")
                /* DDD: is the  next line a kludge? -- JRS */
                && seg->fileoff == 0 && seg->filesize != 0) {
               di->text_present = True;
               di->text_svma = (Addr)seg->vmaddr;
               di->text_avma = di->rx_map_avma;
               di->text_size = seg->vmsize;
               di->text_bias = di->text_avma - di->text_svma;
               /* Make the _debug_ values be the same as the
                  svma/bias for the primary object, since there is
                  no secondary (debuginfo) object, but nevertheless
                  downstream biasing of Dwarf3 relies on the
                  _debug_ values. */
               di->text_debug_svma = di->text_svma;
               di->text_debug_bias = di->text_bias;
            }
            /* Try for __DATA */
            if (!di->data_present
                && 0 == VG_(strcmp)(seg->segname, "__DATA")
                /* && DDD:seg->fileoff == 0 */ && seg->filesize != 0) {
               di->data_present = True;
               di->data_svma = (Addr)seg->vmaddr;
               di->data_avma = di->rw_map_avma;
               di->data_size = seg->vmsize;
               di->data_bias = di->data_avma - di->data_svma;
               di->data_debug_svma = di->data_svma;
               di->data_debug_bias = di->data_bias;
            }
         }
         else if (cmd->cmd == LC_UUID) {
             struct uuid_command *uuid_cmd = (struct uuid_command *)cmd;
             VG_(memcpy)(uuid, uuid_cmd->uuid, sizeof(uuid));
             have_uuid = True;
         }
      }
   }

   if (!di->soname) {
      di->soname = ML_(dinfo_strdup)("di.readmacho.noname", "NONE");
   }

   /* Now we have the base object to hand.  Read symbols from it. */

   if (ii.macho_img && ii.macho_img_szB > 0 && symcmd && dysymcmd) {

      /* Read nlist symbol table */
      struct NLIST *syms;
      UChar *strs;
      XArray* /* DiSym */ candSyms = NULL;
      Word i, nCandSyms;

      if (ii.macho_img_szB < symcmd->stroff + symcmd->strsize
          || ii.macho_img_szB < symcmd->symoff + symcmd->nsyms
                                                 * sizeof(struct NLIST)) {
         ML_(symerr)(di, False, "Invalid Mach-O file (5 too small).");
         goto fail;
      }   
      if (dysymcmd->ilocalsym + dysymcmd->nlocalsym > symcmd->nsyms
          || dysymcmd->iextdefsym + dysymcmd->nextdefsym > symcmd->nsyms) {
         ML_(symerr)(di, False, "Invalid Mach-O file (bad symbol table).");
         goto fail;
      }
      
      syms = (struct NLIST *)(ii.macho_img + symcmd->symoff);
      strs = (UChar *)(ii.macho_img + symcmd->stroff);
      
      if (VG_(clo_verbosity) > 1)
         VG_(message)(Vg_DebugMsg,
            "   reading syms   from primary file (%d %d)\n",
            dysymcmd->nextdefsym, dysymcmd->nlocalsym );

      /* Read candidate symbols into 'candSyms', so we can truncate
         overlapping ends and generally tidy up, before presenting
         them to ML_(addSym). */
      candSyms = VG_(newXA)(
                    ML_(dinfo_zalloc), "di.readmacho.candsyms.1",
                    ML_(dinfo_free), sizeof(DiSym)
                 );
      vg_assert(candSyms);

      // extern symbols
      read_symtab(candSyms,
                  di, 
                  syms + dysymcmd->iextdefsym, dysymcmd->nextdefsym, 
                  strs, symcmd->strsize);
      // static and private_extern symbols
      read_symtab(candSyms,
                  di, 
                  syms + dysymcmd->ilocalsym, dysymcmd->nlocalsym, 
                  strs, symcmd->strsize);

      /* tidy up the cand syms -- trim overlapping ends.  May resize
         candSyms. */
      tidy_up_cand_syms( candSyms, di->trace_symtab );

      /* and finally present them to ML_(addSym) */
      nCandSyms = VG_(sizeXA)( candSyms );
      for (i = 0; i < nCandSyms; i++) {
         DiSym* cand = (DiSym*) VG_(indexXA)( candSyms, i );
         if (di->trace_symtab)
            VG_(printf)("nlist final: acquire  avma %010lx-%010lx  %s\n",
                        cand->addr, cand->addr + cand->size - 1, cand->name );
         ML_(addSym)( di, cand );
      }
      VG_(deleteXA)( candSyms );
   }

   /* If there's no UUID in the primary, don't even bother to try and
      read any DWARF, since we won't be able to verify it matches.
      Our policy is not to load debug info unless we can verify that
      it matches the primary.  Just declare success at this point.
      And don't complain to the user, since that would cause us to
      complain on objects compiled without -g.  (Some versions of
      XCode are observed to omit a UUID entry for object linked(?)
      without -g.  Others don't appear to omit it.) */
   if (!have_uuid)
      goto success;

   /* mmap the dSYM file to look for DWARF debug info.  If successful,
      use the .macho_img and .macho_img_szB in iid. */

   dsymfilename = find_separate_debug_file( di->filename );

   /* Try to load it. */
   if (dsymfilename) {
      Bool valid;

      if (VG_(clo_verbosity) > 1)
         VG_(message)(Vg_DebugMsg, "   dSYM= %s\n", dsymfilename);

      ok = map_image_aboard( di, &iid, dsymfilename );
      if (!ok) goto fail;

      /* check it has the right uuid. */
      vg_assert(have_uuid);
      valid = iid.macho_img && iid.macho_img_szB > 0 
              && check_uuid_matches( (Addr)iid.macho_img,
                                     iid.macho_img_szB, uuid );
      if (valid)
         goto read_the_dwarf;

      if (VG_(clo_verbosity) > 1)
         VG_(message)(Vg_DebugMsg, "   dSYM does not have "
                                   "correct UUID (out of date?)\n");
   }

   /* There was no dsym file, or it doesn't match.  We'll have to try
      regenerating it, unless --dsymutil=no, in which case just complain
      instead. */

   /* If this looks like a lib that we shouldn't run dsymutil on, just
      give up.  (possible reasons: is system lib, or in /usr etc, or
      the dsym dir would not be writable by the user, or we're running
      as root) */
   vg_assert(di->filename);
   if (is_systemish_library_name(di->filename))
      goto success;

   if (!VG_(clo_dsymutil)) {
      if (VG_(clo_verbosity) == 1) {
         VG_(message)(Vg_DebugMsg, "%s:\n", di->filename);
      }
      if (VG_(clo_verbosity) > 0)
         VG_(message)(Vg_DebugMsg, "%sdSYM directory %s; consider using "
                      "--dsymutil=yes\n",
                      VG_(clo_verbosity) > 1 ? "   " : "",
                      dsymfilename ? "has wrong UUID" : "is missing"); 
      goto success;
   }

   /* Run dsymutil */

   { Int r;
     HChar* dsymutil = "/usr/bin/dsymutil ";
     HChar* cmd = ML_(dinfo_zalloc)( "di.readmacho.tmp1", 
                                     VG_(strlen)(dsymutil)
                                     + VG_(strlen)(di->filename)
                                     + 30 /* misc */ );
     VG_(strcpy)(cmd, dsymutil);
     if (0) VG_(strcat)(cmd, "--verbose ");
     VG_(strcat)(cmd, di->filename);
     VG_(message)(Vg_DebugMsg, "run: %s\n", cmd);
     r = VG_(system)( cmd );
     if (r)
        VG_(message)(Vg_DebugMsg, "run: %s FAILED\n", dsymutil);
     ML_(dinfo_free)(cmd);
     dsymfilename = find_separate_debug_file(di->filename);
   }

   /* Try again to load it. */
   if (dsymfilename) {
      Bool valid;

      if (VG_(clo_verbosity) > 1)
         VG_(message)(Vg_DebugMsg, "   dsyms= %s\n", dsymfilename);

      ok = map_image_aboard( di, &iid, dsymfilename );
      if (!ok) goto fail;

      /* check it has the right uuid. */
      vg_assert(have_uuid);
      valid = iid.macho_img && iid.macho_img_szB > 0 
              && check_uuid_matches( (Addr)iid.macho_img,
                                     iid.macho_img_szB, uuid );
      if (!valid) {
         if (VG_(clo_verbosity) > 0) {
            VG_(message)(Vg_DebugMsg,
               "WARNING: did not find expected UUID %02X%02X%02X%02X"
               "-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X"
               " in dSYM dir\n",
               (UInt)uuid[0], (UInt)uuid[1], (UInt)uuid[2], (UInt)uuid[3],
               (UInt)uuid[4], (UInt)uuid[5], (UInt)uuid[6], (UInt)uuid[7],
               (UInt)uuid[8], (UInt)uuid[9], (UInt)uuid[10],
               (UInt)uuid[11], (UInt)uuid[12], (UInt)uuid[13],
               (UInt)uuid[14], (UInt)uuid[15] );
            VG_(message)(Vg_DebugMsg,
                         "WARNING: for %s\n", di->filename);
         }
         unmap_image( &iid );
         /* unmap_image zeroes the fields, so the following test makes
            sense. */
         goto fail;
      }
   }

   /* Right.  Finally we have our best try at the dwarf image, so go
      on to reading stuff out of it. */

  read_the_dwarf:
   if (iid.macho_img && iid.macho_img_szB > 0) {
      UChar* debug_info_img = NULL;
      Word   debug_info_sz;
      UChar* debug_abbv_img;
      Word   debug_abbv_sz;
      UChar* debug_line_img;
      Word   debug_line_sz;
      UChar* debug_str_img;
      Word   debug_str_sz;
      UChar* debug_ranges_img;
      Word   debug_ranges_sz;
      UChar* debug_loc_img;
      Word   debug_loc_sz;
      UChar* debug_name_img;
      Word   debug_name_sz;

      debug_info_img = 
          getsectdata(iid.macho_img, iid.macho_img_szB, 
                      "__DWARF", "__debug_info", &debug_info_sz);
      debug_abbv_img = 
          getsectdata(iid.macho_img, iid.macho_img_szB, 
                      "__DWARF", "__debug_abbrev", &debug_abbv_sz);
      debug_line_img = 
          getsectdata(iid.macho_img, iid.macho_img_szB, 
                      "__DWARF", "__debug_line", &debug_line_sz);
      debug_str_img = 
          getsectdata(iid.macho_img, iid.macho_img_szB, 
                      "__DWARF", "__debug_str", &debug_str_sz);
      debug_ranges_img = 
          getsectdata(iid.macho_img, iid.macho_img_szB, 
                      "__DWARF", "__debug_ranges", &debug_ranges_sz);
      debug_loc_img = 
          getsectdata(iid.macho_img, iid.macho_img_szB, 
                      "__DWARF", "__debug_loc", &debug_loc_sz);
      debug_name_img = 
          getsectdata(iid.macho_img, iid.macho_img_szB, 
                      "__DWARF", "__debug_pubnames", &debug_name_sz);
   
      if (debug_info_img) {
         if (VG_(clo_verbosity) > 1) {
            if (0)
            VG_(message)(Vg_DebugMsg,
                         "Reading dwarf3 for %s (%#lx) from %s"
                         " (%ld %ld %ld %ld %ld %ld)\n",
                         di->filename, di->text_avma, dsymfilename,
                         debug_info_sz, debug_abbv_sz, debug_line_sz, 
                         debug_str_sz, debug_ranges_sz, debug_loc_sz
                         );
            VG_(message)(Vg_DebugMsg,
               "   reading dwarf3 from dsyms file\n");
         }
         /* The old reader: line numbers and unwind info only */
         ML_(read_debuginfo_dwarf3) ( di,
                                      debug_info_img, debug_info_sz,
                                      debug_abbv_img, debug_abbv_sz,
                                      debug_line_img, debug_line_sz,
                                      debug_str_img,  debug_str_sz );

         /* The new reader: read the DIEs in .debug_info to acquire
            information on variable types and locations.  But only if
            the tool asks for it, or the user requests it on the
            command line. */
         if (VG_(needs).var_info /* the tool requires it */
             || VG_(clo_read_var_info) /* the user asked for it */) {
            ML_(new_dwarf3_reader)(
               di, debug_info_img,   debug_info_sz,
                   debug_abbv_img,   debug_abbv_sz,
                   debug_line_img,   debug_line_sz,
                   debug_str_img,    debug_str_sz,
                   debug_ranges_img, debug_ranges_sz,
                   debug_loc_img,    debug_loc_sz
            );
         }
      }
   }

   if (dsymfilename) ML_(dinfo_free)(dsymfilename);

  success:
   if (ii.img)
      unmap_image(&ii);
   if (iid.img)
      unmap_image(&iid);
   return True;

   /* NOTREACHED */

  fail:
   ML_(symerr)(di, True, "Error reading Mach-O object.");
   if (ii.img)
      unmap_image(&ii);
   if (iid.img)
      unmap_image(&iid);
   return False;
}
コード例 #4
0
/* store registers in the guest state (gdbserver_to_valgrind)
   or fetch register from the guest state (valgrind_to_gdbserver). */
static
void transfer_register (ThreadId tid, int abs_regno, void * buf,
                        transfer_direction dir, int size, Bool *mod)
{
   ThreadState* tst = VG_(get_ThreadState)(tid);
   int set = abs_regno / num_regs;
   int regno = abs_regno % num_regs;
   *mod = False;

   VexGuestX86State* x86 = (VexGuestX86State*) get_arch (set, tst);

   switch (regno) { 
   // numbers here have to match the order of regs above
   // Attention: gdb order does not match valgrind order.
   case 0:  VG_(transfer) (&x86->guest_EAX, buf, dir, size, mod); break;
   case 1:  VG_(transfer) (&x86->guest_ECX, buf, dir, size, mod); break;
   case 2:  VG_(transfer) (&x86->guest_EDX, buf, dir, size, mod); break;
   case 3:  VG_(transfer) (&x86->guest_EBX, buf, dir, size, mod); break;
   case 4:  VG_(transfer) (&x86->guest_ESP, buf, dir, size, mod); break;
   case 5:  VG_(transfer) (&x86->guest_EBP, buf, dir, size, mod); break;
   case 6:  VG_(transfer) (&x86->guest_ESI, buf, dir, size, mod); break;
   case 7:  VG_(transfer) (&x86->guest_EDI, buf, dir, size, mod); break;
   case 8:  VG_(transfer) (&x86->guest_EIP, buf, dir, size, mod); break;
   case 9:  
      if (dir == valgrind_to_gdbserver) {
         UInt eflags;
         /* we can only retrieve the real flags (set 0)
            retrieving shadow flags is not ok */
         if (set == 0)
            eflags = LibVEX_GuestX86_get_eflags (x86);
         else
            eflags = 0;
         VG_(transfer) (&eflags, buf, dir, size, mod); break;
      } else {
         *mod = False; //GDBTD? how do we store eflags in libvex_guest_x86.h ???
      }
      break;
   case 10: VG_(transfer) (&x86->guest_CS, buf, dir, size, mod); break;
   case 11: VG_(transfer) (&x86->guest_SS, buf, dir, size, mod); break;
   case 12: VG_(transfer) (&x86->guest_DS, buf, dir, size, mod); break;
   case 13: VG_(transfer) (&x86->guest_ES, buf, dir, size, mod); break;
   case 14: VG_(transfer) (&x86->guest_FS, buf, dir, size, mod); break;
   case 15: VG_(transfer) (&x86->guest_GS, buf, dir, size, mod); break;
   case 16:
   case 17:
   case 18:
   case 19: /* register 16 to 23 are float registers 80 bits but 64 bits in valgrind */
   case 20:
   case 21:
   case 22:
   case 23: {
      if (dir == valgrind_to_gdbserver) {
         UChar fpreg80[10];
         convert_f64le_to_f80le ((UChar *)&x86->guest_FPREG[regno-16],
                                 fpreg80);
         VG_(transfer) (&fpreg80, buf, dir, sizeof(fpreg80), mod);
      } else {
         ULong fpreg64;
         convert_f80le_to_f64le (buf, (UChar *)&fpreg64); 
         VG_(transfer) (&x86->guest_FPREG[regno-16], &fpreg64, 
                        dir, sizeof(fpreg64), mod);
      }
      break;
   }
   case 24: 
      if (dir == valgrind_to_gdbserver) {
         // vex only models the rounding bits (see libvex_guest_x86.h)
         UWord value = 0x037f;
         value |= x86->guest_FPROUND << 10;
         VG_(transfer)(&value, buf, dir, size, mod);
      } else {
         *mod = False; // GDBTD???? VEX { "fctrl", 1152, 32 },
      }
      break; 
   case 25:
      if (dir == valgrind_to_gdbserver) {
         UWord value = x86->guest_FC3210;
         value |= (x86->guest_FTOP & 7) << 11;
         VG_(transfer)(&value, buf, dir, size, mod); 
      } else {
         *mod = False; // GDBTD???? VEX { "fstat", 1184, 32 },
      }
      break;
   case 26: 
      if (dir == valgrind_to_gdbserver) {
         // vex doesn't model these precisely
         UWord value = 
            ((x86->guest_FPTAG[0] ? 0 : 3) << 0)  | 
            ((x86->guest_FPTAG[1] ? 0 : 3) << 2)  | 
            ((x86->guest_FPTAG[2] ? 0 : 3) << 4)  | 
            ((x86->guest_FPTAG[3] ? 0 : 3) << 6)  | 
            ((x86->guest_FPTAG[4] ? 0 : 3) << 8)  | 
            ((x86->guest_FPTAG[5] ? 0 : 3) << 10) | 
            ((x86->guest_FPTAG[6] ? 0 : 3) << 12) | 
            ((x86->guest_FPTAG[7] ? 0 : 3) << 14);
         VG_(transfer)(&value, buf, dir, size, mod); 
      } else {
         *mod = False;  // GDBTD???? VEX { "ftag", 1216, 32 },
      }
      break;
   case 27: *mod = False; break; // GDBTD???? VEX { "fiseg", 1248, 32 },
   case 28: *mod = False; break; // GDBTD???? VEX { "fioff", 1280, 32 },
   case 29: *mod = False; break; // GDBTD???? VEX { "foseg", 1312, 32 },
   case 30: *mod = False; break; // GDBTD???? VEX { "fooff", 1344, 32 },
   case 31: *mod = False; break; // GDBTD???? VEX { "fop", 1376, 32 },
   case 32: VG_(transfer) (&x86->guest_XMM0, buf, dir, size, mod); break;
   case 33: VG_(transfer) (&x86->guest_XMM1, buf, dir, size, mod); break;
   case 34: VG_(transfer) (&x86->guest_XMM2, buf, dir, size, mod); break;
   case 35: VG_(transfer) (&x86->guest_XMM3, buf, dir, size, mod); break;
   case 36: VG_(transfer) (&x86->guest_XMM4, buf, dir, size, mod); break;
   case 37: VG_(transfer) (&x86->guest_XMM5, buf, dir, size, mod); break;
   case 38: VG_(transfer) (&x86->guest_XMM6, buf, dir, size, mod); break;
   case 39: VG_(transfer) (&x86->guest_XMM7, buf, dir, size, mod); break;
   case 40: 
      if (dir == valgrind_to_gdbserver) {
         // vex only models the rounding bits (see libvex_guest_x86.h)
         UWord value = 0x1f80;
         value |= x86->guest_SSEROUND << 13;
         VG_(transfer)(&value, buf, dir, size, mod); 
      } else {
         *mod = False; // GDBTD???? VEX { "mxcsr", 2432, 32 },
      }
      break;
   case 41: *mod = False; break; // GDBTD???? VEX { "orig_eax", 2464, 32 },
   default: vg_assert(0);
   }
}
コード例 #5
0
ファイル: m_debugger.c プロジェクト: svn2github/valgrind-3
/* Start debugger and get it to attach to this process.  Called if the
   user requests this service after an error has been shown, so she can
   poke around and look at parameters, memory, etc.  You can't
   meaningfully get the debugger to continue the program, though; to
   continue, quit the debugger.  */
void VG_(start_debugger) ( ThreadId tid )
{
#  define N_BUF 4096
   Int pid;

   if ((pid = VG_(fork)()) == 0) {
      VG_(ptrace)(VKI_PTRACE_TRACEME, 0, NULL, NULL);
      VG_(kill)(VG_(getpid)(), VKI_SIGSTOP);

   } else if (pid > 0) {
      Int status;
      Int res;

      if ((res = VG_(waitpid)(pid, &status, 0)) == pid &&
          WIFSTOPPED(status) && WSTOPSIG(status) == VKI_SIGSTOP &&
          ptrace_setregs(pid, &(VG_(threads)[tid].arch.vex)) == 0 &&
          VG_(kill)(pid, VKI_SIGSTOP) == 0 &&
          VG_(ptrace)(VKI_PTRACE_DETACH, pid, NULL, 0) == 0)
      {
         Char pidbuf[15];
         Char file[50];
         Char buf[N_BUF];
         Char *bufptr;
         Char *cmdptr;
         
         VG_(sprintf)(pidbuf, "%d", pid);
         VG_(sprintf)(file, "/proc/%d/fd/%d", pid, VG_(cl_exec_fd));
 
         bufptr = buf;
         cmdptr = VG_(clo_db_command);
         
         while (*cmdptr) {
            /* each iteration can advance bufptr by at most the length
               of file[], so the following assertion is generously
               over-paranoid. */
            vg_assert(bufptr - buf < N_BUF-15-50-10/*paranoia*/);
            switch (*cmdptr) {
               case '%':
                  switch (*++cmdptr) {
                     case 'f':
                        VG_(memcpy)(bufptr, file, VG_(strlen)(file));
                        bufptr += VG_(strlen)(file);
                        cmdptr++;
                        break;
                     case 'p':
                        VG_(memcpy)(bufptr, pidbuf, VG_(strlen)(pidbuf));
                        bufptr += VG_(strlen)(pidbuf);
                        cmdptr++;
                        break;
                     default:
                        *bufptr++ = *cmdptr++;
                        break;
                  }
                  break;
               default:
                  *bufptr++ = *cmdptr++;
                  break;
            }
            vg_assert(bufptr - buf < N_BUF-15-50-10/*paranoia*/);
         }
         
         *bufptr++ = '\0';
  
         VG_(message)(Vg_UserMsg, "starting debugger with cmd: %s", buf);
         res = VG_(system)(buf);
         if (res == 0) {      
            VG_(message)(Vg_UserMsg, "");
            VG_(message)(Vg_UserMsg, 
                         "Debugger has detached.  Valgrind regains control.  We continue.");
         } else {
            VG_(message)(Vg_UserMsg, "Apparently failed!");
            VG_(message)(Vg_UserMsg, "");
         }
      }

      VG_(kill)(pid, VKI_SIGKILL);
      VG_(waitpid)(pid, &status, 0);
   }
#  undef N_BUF
}
コード例 #6
0
ファイル: tytypes.c プロジェクト: sabinaya/valgrind-variant
static MaybeULong mul_MaybeULong ( MaybeULong mul1, MaybeULong mul2 ) {
   if (!mul1.b) { vg_assert(mul1.ul == 0); return mul1; }
   if (!mul2.b) { vg_assert(mul2.ul == 0); return mul2; }
   mul1.ul *= mul2.ul;
   return mul1;
}
コード例 #7
0
ファイル: tytypes.c プロジェクト: sabinaya/valgrind-variant
XArray* /*HChar*/ ML_(describe_type)( /*OUT*/PtrdiffT* residual_offset,
                                      XArray* /* of TyEnt */ tyents,
                                      UWord ty_cuOff, 
                                      PtrdiffT offset )
{
   TyEnt*  ty;
   XArray* xa = VG_(newXA)( ML_(dinfo_zalloc), "di.tytypes.dt.1",
                            ML_(dinfo_free),
                            sizeof(HChar) );
   vg_assert(xa);

   ty = ML_(TyEnts__index_by_cuOff)(tyents, NULL, ty_cuOff);

   while (True) {
      vg_assert(ty);
      vg_assert(ML_(TyEnt__is_type)(ty));

      switch (ty->tag) {

         /* These are all atomic types; there is nothing useful we can
            do. */
         case Te_TyEnum:
         case Te_TyFn:
         case Te_TyVoid:
         case Te_TyPtr:
         case Te_TyRef:
         case Te_TyPtrMbr:
         case Te_TyRvalRef:
         case Te_TyBase:
            goto done;

         case Te_TyStOrUn: {
            Word       i;
            GXResult   res;
            MaybeULong mul;
            XArray*    fieldRs;
            UWord      fieldR;
            TyEnt*     field = NULL;
            PtrdiffT   offMin = 0, offMax1 = 0;
            if (!ty->Te.TyStOrUn.isStruct) goto done;
            fieldRs = ty->Te.TyStOrUn.fieldRs;
            if ((!fieldRs) || VG_(sizeXA)(fieldRs) == 0) goto done;
            for (i = 0; i < VG_(sizeXA)( fieldRs ); i++ ) {
               fieldR = *(UWord*)VG_(indexXA)( fieldRs, i );
               field = ML_(TyEnts__index_by_cuOff)(tyents, NULL, fieldR);
               vg_assert(field);
               vg_assert(field->tag == Te_Field);
               vg_assert(field->Te.Field.nLoc < 0
                         || (field->Te.Field.nLoc > 0
                             && field->Te.Field.pos.loc));
               if (field->Te.Field.nLoc == -1) {
                  res.kind = GXR_Addr;
                  res.word = field->Te.Field.pos.offset;
               } else {
                  /* Re data_bias in this call, we should really send in
                     a legitimate value.  But the expression is expected
                     to be a constant expression, evaluation of which
                     will not need to use DW_OP_addr and hence we can
                     avoid the trouble of plumbing the data bias through
                     to this point (if, indeed, it has any meaning; from
                     which DebugInfo would we take the data bias? */
                   res =  ML_(evaluate_Dwarf3_Expr)(
                          field->Te.Field.pos.loc, field->Te.Field.nLoc,
                          NULL/*fbGX*/, NULL/*RegSummary*/,
                          0/*data_bias*/,
                          True/*push_initial_zero*/);
                  if (0) {
                     VG_(printf)("QQQ ");
                     ML_(pp_GXResult)(res);
                     VG_(printf)("\n");
                  }
               }
               if (res.kind != GXR_Addr)
                  continue;
               mul = ML_(sizeOfType)( tyents, field->Te.Field.typeR );
               if (mul.b != True)
                  goto done; /* size of field is unknown (?!) */
               offMin  = res.word;
               offMax1 = offMin + (PtrdiffT)mul.ul;
               if (offMin == offMax1)
                  continue;
               vg_assert(offMin < offMax1);
               if (offset >= offMin && offset < offMax1)
                  break;
            }
            /* Did we find a suitable field? */
            vg_assert(i >= 0 && i <= VG_(sizeXA)( fieldRs ));
            if (i == VG_(sizeXA)( fieldRs ))
               goto done; /* No.  Give up. */
            /* Yes.  'field' is it. */
            vg_assert(field);
            if (!field->Te.Field.name) goto done;
            VG_(addBytesToXA)( xa, ".", 1 );
            VG_(addBytesToXA)( xa, field->Te.Field.name,
                               VG_(strlen)(field->Te.Field.name) );
            offset -= offMin;
            ty = ML_(TyEnts__index_by_cuOff)(tyents, NULL,
                                             field->Te.Field.typeR );
            tl_assert(ty);
            if (ty->tag == Te_UNKNOWN) goto done;
            /* keep going; look inside the field. */
            break;
         }

         case Te_TyArray: {
            MaybeULong mul;
            UWord      size, eszB, ix;
            UWord      boundR;
            TyEnt*     elemTy;
            TyEnt*     bound;
            /* Just deal with the simple, common C-case: 1-D array,
               zero based, known size. */
            elemTy = ML_(TyEnts__index_by_cuOff)(tyents, NULL, 
                                                 ty->Te.TyArray.typeR);
            vg_assert(elemTy);
            if (elemTy->tag == Te_UNKNOWN) goto done;
            vg_assert(ML_(TyEnt__is_type)(elemTy));
            if (!ty->Te.TyArray.boundRs)
               goto done;
            if (VG_(sizeXA)( ty->Te.TyArray.boundRs ) != 1) goto done;
            boundR = *(UWord*)VG_(indexXA)( ty->Te.TyArray.boundRs, 0 );
            bound = ML_(TyEnts__index_by_cuOff)(tyents, NULL, boundR);
            vg_assert(bound);
            vg_assert(bound->tag == Te_Bound);
            if (!(bound->Te.Bound.knownL && bound->Te.Bound.knownU
                  && bound->Te.Bound.boundL == 0
                  && bound->Te.Bound.boundU >= bound->Te.Bound.boundL))
               goto done;
            size = bound->Te.Bound.boundU - bound->Te.Bound.boundL + 1;
            vg_assert(size >= 1);
            mul = ML_(sizeOfType)( tyents, ty->Te.TyArray.typeR );
            if (mul.b != True)
               goto done; /* size of element type not known */
            eszB = mul.ul;
            if (eszB == 0) goto done;
            ix = offset / eszB;
            VG_(addBytesToXA)( xa, "[", 1 );
            copy_UWord_into_XA( xa, ix );
            VG_(addBytesToXA)( xa, "]", 1 );
            ty = elemTy;
            offset -= ix * eszB;
            /* keep going; look inside the array element. */
            break;
         }

         case Te_TyQual: {
            ty = ML_(TyEnts__index_by_cuOff)(tyents, NULL,
                                             ty->Te.TyQual.typeR);
            tl_assert(ty);
            if (ty->tag == Te_UNKNOWN) goto done;
            break;
         }

         case Te_TyTyDef: {
            ty = ML_(TyEnts__index_by_cuOff)(tyents, NULL,
                                             ty->Te.TyTyDef.typeR);
            tl_assert(ty);
            if (ty->tag == Te_UNKNOWN) goto done;
            break;
         }

         default: {
            VG_(printf)("ML_(describe_type): unhandled: ");
            ML_(pp_TyEnt)(ty);
            VG_(printf)("\n");
            vg_assert(0);
         }

      }
   }

  done:
   *residual_offset = offset;
   VG_(addBytesToXA)( xa, "\0", 1 );
   return xa;
}
コード例 #8
0
ファイル: m_options.c プロジェクト: lu-zero/valgrind
/* Should we trace into this child executable (across execve etc) ?
   This involves considering --trace-children=,
   --trace-children-skip=, --trace-children-skip-by-arg=, and the name
   of the executable.  'child_argv' must not include the name of the
   executable itself; iow child_argv[0] must be the first arg, if any,
   for the child. */
Bool VG_(should_we_trace_this_child) ( HChar* child_exe_name,
                                       HChar** child_argv )
{
   // child_exe_name is pulled out of the guest's space.  We
   // should be at least marginally cautious with it, lest it
   // explode or burst into flames unexpectedly.
   if (child_exe_name == NULL || VG_(strlen)(child_exe_name) == 0)
      return VG_(clo_trace_children);  // we know narfink

   // If --trace-children=no, the answer is simply NO.
   if (! VG_(clo_trace_children))
      return False;

   // Otherwise, look for other reasons to say NO.  First,
   // see if the exe name matches any of the patterns specified
   // by --trace-children-skip=.
   if (VG_(clo_trace_children_skip)) {
      HChar const* last = VG_(clo_trace_children_skip);
      HChar const* name = child_exe_name;
      while (*last) {
         Bool   matches;
         HChar* patt;
         HChar const* first = consume_commas(last);
         last = consume_field(first);
         if (first == last)
            break;
         vg_assert(last > first);
         /* copy the candidate string into a temporary malloc'd block
            so we can use VG_(string_match) on it. */
         patt = VG_(calloc)("m_options.swttc.1", last - first + 1, 1);
         VG_(memcpy)(patt, first, last - first);
         vg_assert(patt[last-first] == 0);
         matches = VG_(string_match)(patt, name);
         VG_(free)(patt);
         if (matches)
            return False;
      }
   }

   // Check if any of the args match any of the patterns specified
   // by --trace-children-skip-by-arg=. 
   if (VG_(clo_trace_children_skip_by_arg) && child_argv != NULL) {
      HChar const* last = VG_(clo_trace_children_skip_by_arg);
      while (*last) {
         Int    i;
         Bool   matches;
         HChar* patt;
         HChar const* first = consume_commas(last);
         last = consume_field(first);
         if (first == last)
            break;
         vg_assert(last > first);
         /* copy the candidate string into a temporary malloc'd block
            so we can use VG_(string_match) on it. */
         patt = VG_(calloc)("m_options.swttc.1", last - first + 1, 1);
         VG_(memcpy)(patt, first, last - first);
         vg_assert(patt[last-first] == 0);
         for (i = 0; child_argv[i]; i++) {
            matches = VG_(string_match)(patt, child_argv[i]);
            if (matches) {
               VG_(free)(patt);
               return False;
            }
         }
         VG_(free)(patt);
      }
   }

   // --trace-children=yes, and this particular executable isn't
   // excluded
   return True;
}
コード例 #9
0
ファイル: tytypes.c プロジェクト: eeight/tdheap
static MaybeUWord mul_MaybeUWord ( MaybeUWord muw1, MaybeUWord muw2 ) {
   if (!muw1.b) { vg_assert(muw1.w == 0); return muw1; }
   if (!muw2.b) { vg_assert(muw2.w == 0); return muw2; }
   muw1.w *= muw2.w;
   return muw1;
}
コード例 #10
0
void* VG_(client_realloc) ( ThreadState* tst, void* p, UInt new_size )
{
   ShadowChunk  *sc;
   ShadowChunk **prev_chunks_next_ptr;
   UInt          i;

   VGP_PUSHCC(VgpCliMalloc);

   vg_cmalloc_n_frees ++;
   vg_cmalloc_n_mallocs ++;
   vg_cmalloc_bs_mallocd += new_size;

   if (! needs_shadow_chunks()) {
      vg_assert(p != NULL && new_size != 0);
      p = VG_(arena_realloc) ( VG_AR_CLIENT, p, VG_(clo_alignment), 
                               new_size );
      VGP_POPCC(VgpCliMalloc);
      return p;

   } else {
      /* First try and find the block. */
      sc = getShadowChunk ( (Addr)p, &prev_chunks_next_ptr );

      if (sc == NULL) {
         VG_TRACK( bad_free, tst, (Addr)p );
         /* Perhaps we should return to the program regardless. */
         VGP_POPCC(VgpCliMalloc);
         return NULL;
      }
     
      /* check if its a matching free() / delete / delete [] */
      if (Vg_AllocMalloc != sc->allockind) {
         /* can not realloc a range that was allocated with new or new [] */
         VG_TRACK( mismatched_free, tst, (Addr)p );
         /* but keep going anyway */
      }

      if (sc->size == new_size) {
         /* size unchanged */
         VGP_POPCC(VgpCliMalloc);
         return p;
         
      } else if (sc->size > new_size) {
         /* new size is smaller */
         VG_TRACK( die_mem_heap, sc->data+new_size, sc->size-new_size );
         sc->size = new_size;
         VGP_POPCC(VgpCliMalloc);
#        ifdef DEBUG_CLIENTMALLOC
         VG_(printf)("[m %d, f %d (%d)] client_realloc_smaller ( %p, %d ) = %p\n", 
                     count_malloclists(), 
                     0/*count_freelist()*/, 0/*vg_freed_list_volume*/,
                     p, new_size, p );
#        endif
         return p;

      } else {
         /* new size is bigger */
         Addr p_new;
         
         /* Get new memory */
         vg_assert(VG_(clo_alignment) >= 4);
         if (VG_(clo_alignment) == 4)
            p_new = (Addr)VG_(arena_malloc)(VG_AR_CLIENT, new_size);
         else
            p_new = (Addr)VG_(arena_malloc_aligned)(VG_AR_CLIENT, 
                                            VG_(clo_alignment), new_size);

         /* First half kept and copied, second half new, 
            red zones as normal */
         VG_TRACK( ban_mem_heap, p_new-VG_AR_CLIENT_REDZONE_SZB, 
                                 VG_AR_CLIENT_REDZONE_SZB );
         VG_TRACK( copy_mem_heap, (Addr)p, p_new, sc->size );
         VG_TRACK( new_mem_heap, p_new+sc->size, new_size-sc->size, 
                   /*inited=*/False );
         VG_TRACK( ban_mem_heap, p_new+new_size, VG_AR_CLIENT_REDZONE_SZB );

         /* Copy from old to new */
         for (i = 0; i < sc->size; i++)
            ((UChar*)p_new)[i] = ((UChar*)p)[i];

         /* Free old memory */
         die_and_free_mem ( tst, sc, prev_chunks_next_ptr );

         /* this has to be after die_and_free_mem, otherwise the
            former succeeds in shorting out the new block, not the
            old, in the case when both are on the same list.  */
         addShadowChunk ( tst, p_new, new_size, Vg_AllocMalloc );

         VGP_POPCC(VgpCliMalloc);
#        ifdef DEBUG_CLIENTMALLOC
         VG_(printf)("[m %d, f %d (%d)] client_realloc_bigger ( %p, %d ) = %p\n", 
                     count_malloclists(), 
                     0/*count_freelist()*/, 0/*vg_freed_list_volume*/,
                     p, new_size, (void*)p_new );
#        endif
         return (void*)p_new;
      }  
   }
}
コード例 #11
0
ファイル: script.c プロジェクト: AmesianX/pathgrind
/* returns: 0 = success, non-0 is failure */
Int VG_(load_script)(Int fd, const HChar* name, ExeInfo* info)
{
   Char  hdr[4096];
   Int   len = 4096;
   Int   eol;
   Char* interp;
   Char* end;
   Char* cp;
   Char* arg = NULL;
   SysRes res;

   // Read the first part of the file.
   res = VG_(pread)(fd, hdr, len, 0);
   if (sr_isError(res)) {
      VG_(close)(fd);
      return VKI_EACCES;
   } else {
      len = sr_Res(res);
   }

   vg_assert('#' == hdr[0] && '!' == hdr[1]);

   end    = hdr + len;
   interp = hdr + 2;
   while (interp < end && VG_(isspace)(*interp))
      interp++;

   vg_assert(*interp == '/');   /* absolute path only for interpreter */

   /* skip over interpreter name */
   for (cp = interp; cp < end && !VG_(isspace)(*cp); cp++)
      ;

   eol = (*cp == '\n');

   *cp++ = '\0';

   if (!eol && cp < end) {
      /* skip space before arg */
      while (cp < end && VG_(isspace)(*cp) && *cp != '\n')
         cp++;

      /* arg is from here to eol */
      arg = cp;
      while (cp < end && *cp != '\n')
         cp++;
      *cp = '\0';
   }
   
   info->interp_name = VG_(strdup)("ume.ls.1", interp);
   vg_assert(NULL != info->interp_name);
   if (arg != NULL && *arg != '\0') {
      info->interp_args = VG_(strdup)("ume.ls.2", arg);
      vg_assert(NULL != info->interp_args);
   }

   if (info->argv && info->argv[0] != NULL)
      info->argv[0] = (char *)name;

   VG_(args_the_exename) = name;

   if (0)
      VG_(printf)("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
                  info->interp_name, info->interp_args);

   return VG_(do_exec_inner)(interp, info);
}
コード例 #12
0
/* Based on ML_(generic_PRE_sys_mmap) from syswrap-generic.c.
   If we are trying to do mmap with VKI_MAP_SHARED flag we need to align the
   start address on VKI_SHMLBA like we did in
   VG_(am_mmap_file_float_valgrind_flags)
 */
static SysRes mips_PRE_sys_mmap(ThreadId tid,
                                UWord arg1, UWord arg2, UWord arg3,
                                UWord arg4, UWord arg5, Off64T arg6)
{
   Addr       advised;
   SysRes     sres;
   MapRequest mreq;
   Bool       mreq_ok;

   if (arg2 == 0) {
      /* SuSV3 says: If len is zero, mmap() shall fail and no mapping
         shall be established. */
      return VG_(mk_SysRes_Error)( VKI_EINVAL );
   }

   if (!VG_IS_PAGE_ALIGNED(arg1)) {
      /* zap any misaligned addresses. */
      /* SuSV3 says misaligned addresses only cause the MAP_FIXED case
         to fail.   Here, we catch them all. */
      return VG_(mk_SysRes_Error)( VKI_EINVAL );
   }

   if (!VG_IS_PAGE_ALIGNED(arg6)) {
      /* zap any misaligned offsets. */
      /* SuSV3 says: The off argument is constrained to be aligned and
         sized according to the value returned by sysconf() when
         passed _SC_PAGESIZE or _SC_PAGE_SIZE. */
      return VG_(mk_SysRes_Error)( VKI_EINVAL );
   }

   /* Figure out what kind of allocation constraints there are
      (fixed/hint/any), and ask aspacem what we should do. */
   mreq.start = arg1;
   mreq.len   = arg2;
   if (arg4 & VKI_MAP_FIXED) {
      mreq.rkind = MFixed;
   } else
   if (arg1 != 0) {
      mreq.rkind = MHint;
   } else {
      mreq.rkind = MAny;
   }

   if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & arg4)
       && !(VKI_MAP_FIXED & arg4))
      mreq.len = arg2 + VKI_SHMLBA - VKI_PAGE_SIZE;

   /* Enquire ... */
   advised = VG_(am_get_advisory)( &mreq, True/*client*/, &mreq_ok );

   if ((VKI_SHMLBA > VKI_PAGE_SIZE) && (VKI_MAP_SHARED & arg4)
       && !(VKI_MAP_FIXED & arg4))
      advised = VG_ROUNDUP(advised, VKI_SHMLBA);

   if (!mreq_ok) {
      /* Our request was bounced, so we'd better fail. */
      return VG_(mk_SysRes_Error)( VKI_EINVAL );
   }

   /* Otherwise we're OK (so far).  Install aspacem's choice of
      address, and let the mmap go through.  */
   sres = VG_(am_do_mmap_NO_NOTIFY)(advised, arg2, arg3,
                                    arg4 | VKI_MAP_FIXED,
                                    arg5, arg6);

   /* A refinement: it may be that the kernel refused aspacem's choice
      of address.  If we were originally asked for a hinted mapping,
      there is still a last chance: try again at any address.
      Hence: */
   if (mreq.rkind == MHint && sr_isError(sres)) {
      mreq.start = 0;
      mreq.len   = arg2;
      mreq.rkind = MAny;
      advised = VG_(am_get_advisory)( &mreq, True/*client*/, &mreq_ok );
      if (!mreq_ok) {
         /* Our request was bounced, so we'd better fail. */
         return VG_(mk_SysRes_Error)( VKI_EINVAL );
      }
      /* and try again with the kernel */
      sres = VG_(am_do_mmap_NO_NOTIFY)(advised, arg2, arg3,
                                       arg4 | VKI_MAP_FIXED,
                                       arg5, arg6);
   }

   if (!sr_isError(sres)) {
      ULong di_handle;
      /* Notify aspacem. */
      notify_core_of_mmap(
         (Addr)sr_Res(sres), /* addr kernel actually assigned */
         arg2, /* length */
         arg3, /* prot */
         arg4, /* the original flags value */
         arg5, /* fd */
         arg6  /* offset */
      );
      /* Load symbols? */
      di_handle = VG_(di_notify_mmap)( (Addr)sr_Res(sres), 
                                       False/*allow_SkFileV*/, (Int)arg5 );
      /* Notify the tool. */
      notify_tool_of_mmap(
         (Addr)sr_Res(sres), /* addr kernel actually assigned */
         arg2, /* length */
         arg3, /* prot */
         di_handle /* so the tool can refer to the read debuginfo later,
                      if it wants. */
      );
   }

   /* Stay sane */
   if (!sr_isError(sres) && (arg4 & VKI_MAP_FIXED))
      vg_assert(sr_Res(sres) == arg1);

   return sres;
}
コード例 #13
0
static SysRes do_clone (ThreadId ptid, 
                        UInt flags, Addr sp, 
                        Int * parent_tidptr,
                        Int * child_tidptr, 
                        Addr child_tls) 
{
   const Bool debug = False;
   ThreadId ctid = VG_ (alloc_ThreadState) ();
   ThreadState * ptst = VG_ (get_ThreadState) (ptid);
   ThreadState * ctst = VG_ (get_ThreadState) (ctid);
   UInt ret = 0;
   UWord * stack;
   SysRes res;
   vki_sigset_t blockall, savedmask;

   VG_ (sigfillset) (&blockall);
   vg_assert (VG_ (is_running_thread) (ptid));
   vg_assert (VG_ (is_valid_tid) (ctid));
   stack = (UWord *) ML_ (allocstack) (ctid);
   if (stack == NULL) {
      res = VG_ (mk_SysRes_Error) (VKI_ENOMEM);
      goto out;
   }
   setup_child (&ctst->arch, &ptst->arch);

   /* on MIPS we need to set V0 and A3 to zero */ 
   ctst->arch.vex.guest_r2 = 0;
   ctst->arch.vex.guest_r7 = 0;
   if (sp != 0)
      ctst->arch.vex.guest_r29 = sp;

   ctst->os_state.parent = ptid;
   ctst->sig_mask = ptst->sig_mask;
   ctst->tmp_sig_mask = ptst->sig_mask;

   /* Start the child with its threadgroup being the same as the
      parent's.  This is so that any exit_group calls that happen
      after the child is created but before it sets its
      os_state.threadgroup field for real (in thread_wrapper in
      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
      a race condition in which the thread is unkillable (via
      exit_group) because its threadgroup is not set.  The race window
      is probably only a few hundred or a few thousand cycles long.
      See #226116. */ 

   ctst->os_state.threadgroup = ptst->os_state.threadgroup;

   ML_(guess_and_register_stack) (sp, ctst);

   VG_TRACK (pre_thread_ll_create, ptid, ctid);
   if (flags & VKI_CLONE_SETTLS) {
      if (debug)
        VG_(printf)("clone child has SETTLS: tls at %#lx\n", child_tls);
      ctst->arch.vex.guest_r27 = child_tls;
      res = sys_set_tls(ctid, child_tls);
      if (sr_isError(res))
         goto out;
      ctst->arch.vex.guest_r27 = child_tls;
  }

   flags &= ~VKI_CLONE_SETTLS;
   VG_ (sigprocmask) (VKI_SIG_SETMASK, &blockall, &savedmask);
   /* Create the new thread */ 
   ret = do_syscall_clone_mips_linux (ML_ (start_thread_NORETURN),
                                    stack, flags, &VG_ (threads)[ctid], 
                                    child_tidptr, parent_tidptr,
                                    0 /*child_tls*/);

   /* High half word64 is syscall return value.  Low half is
      the entire CR, from which we need to extract CR0.SO. */ 
   if (debug)
      VG_(printf)("ret: 0x%x\n", ret);

   res = VG_ (mk_SysRes_mips32_linux) (/*val */ ret, 0, /*errflag */ 0);

   VG_ (sigprocmask) (VKI_SIG_SETMASK, &savedmask, NULL);

   out:
   if (sr_isError (res)) {
      VG_(cleanup_thread) (&ctst->arch);
      ctst->status = VgTs_Empty;
      VG_TRACK (pre_thread_ll_exit, ctid);
   }
   ptst->arch.vex.guest_r2 = 0;

   return res;
}
コード例 #14
0
ファイル: target.c プロジェクト: lu-zero/valgrind
void gdbserver_process_exit_encountered (unsigned char status, Int code)
{
   vg_assert (status == 'W' || status == 'X');
   exit_status_to_report = status;
   exit_code_to_report = code;
}
コード例 #15
0
ファイル: tytypes.c プロジェクト: sabinaya/valgrind-variant
TyEnt* ML_(TyEnts__index_by_cuOff) ( XArray* /* of TyEnt */ ents,
                                     TyEntIndexCache* cache,
                                     UWord cuOff_to_find )
{
   Bool  found;
   Word  first, last;
   TyEnt key, *res;

   /* crude stats, aggregated over all caches */
   static UWord cacheQs = 0 - 1;
   static UWord cacheHits = 0;

   if (0 && 0 == (cacheQs & 0xFFFF))
      VG_(printf)("cache: %'lu queries, %'lu misses\n", 
                  cacheQs, cacheQs - cacheHits);

   if (LIKELY(cache != NULL)) {
      UWord h = cuOff_to_find % (UWord)N_TYENT_INDEX_CACHE;
      cacheQs++;
      // dude, like, way 0, dude.
      if (cache->ce[h].cuOff0 == cuOff_to_find && cache->ce[h].ent0 != NULL) {
         // dude, way 0 is a total hit!
         cacheHits++;
         return cache->ce[h].ent0;
      }
      // dude, check out way 1, dude.
      if (cache->ce[h].cuOff1 == cuOff_to_find && cache->ce[h].ent1 != NULL) {
         // way 1 hit
         UWord  tc;
         TyEnt* te;
         cacheHits++;
         // dude, way 1 is the new way 0.  move with the times, dude.
         tc = cache->ce[h].cuOff0;
         te = cache->ce[h].ent0;
         cache->ce[h].cuOff0 = cache->ce[h].cuOff1;
         cache->ce[h].ent0   = cache->ce[h].ent1;
         cache->ce[h].cuOff1 = tc;
         cache->ce[h].ent1   = te;
         return cache->ce[h].ent0;
      }
   }

   /* We'll have to do it the hard way */
   key.cuOff = cuOff_to_find;
   key.tag   = Te_EMPTY;
   found = VG_(lookupXA)( ents, &key, &first, &last );
   //found = VG_(lookupXA_UNBOXED)( ents, cuOff_to_find, &first, &last, 
   //                               offsetof(TyEnt,cuOff) );
   if (!found)
      return NULL;
   /* If this fails, the array is invalid in the sense that there is
      more than one entry with .cuOff == cuOff_to_find. */
   vg_assert(first == last);
   res = (TyEnt*)VG_(indexXA)( ents, first );

   if (LIKELY(cache != NULL) && LIKELY(res != NULL)) {
      /* this is a bit stupid, computing this twice.  Oh well.
         Perhaps some magic gcc transformation will common them up.
         re "res != NULL", since .ent of NULL denotes 'invalid entry',
         we can't cache the result when res == NULL. */
      UWord h = cuOff_to_find % (UWord)N_TYENT_INDEX_CACHE;
      cache->ce[h].cuOff1 = cache->ce[h].cuOff0;
      cache->ce[h].ent1   = cache->ce[h].ent0;
      cache->ce[h].cuOff0 = cuOff_to_find;
      cache->ce[h].ent0   = res;
   }

   return res;
}
コード例 #16
0
/* Do initial consistency checks on some of the definitions to do with
   signals (vki_sigset_t and vki_sigaction_{toK,fromK}_t).  This stuff
   is fragile enough that it's important to check at startup that
   the world looks like what we expect it to look like. 

   The most important thing is to check that the definition of signal
   sets for this platform is right.  A signal set consists of some
   number _VKI_NSIG_WORDS of 32- or 64-bit words.  Because the kernel
   itself has some indexing scheme to set/clear individual bits in the
   set, we must make sure we use the same layout/scheme: where this
   requirement bites us is in the VG_(sigfillset) etc functions in
   m_libcsignal.c.  So we check carefully here that it's all sensible.
*/
void VG_(vki_do_initial_consistency_checks) ( void )
{
   /* --- Platform-independent checks on signal sets --- */

   vki_sigset_t set;
   // Set's size must agree with _VKI_NSIG
   vg_assert( 8 * sizeof(set) == _VKI_NSIG );
   // Set's word size must agree with _VKI_NSIG_BPW
   vg_assert( 8 * sizeof(set.sig[0]) == _VKI_NSIG_BPW );
   // The set elements are 32- or 64-bit
   vg_assert( _VKI_NSIG_BPW == 32 || _VKI_NSIG_BPW == 64 );

   /* --- Platform-specific checks on signal sets --- */

#  if defined(VGO_linux)
   /* nothing to check */
#  elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
   vg_assert(_VKI_NSIG == NSIG);
   vg_assert(_VKI_NSIG == 32);
   vg_assert(_VKI_NSIG_WORDS == 1);
   vg_assert(sizeof(sigset_t) /* defined by Darwin */ 
             == sizeof(vki_sigset_t) /* what we actually use */);
#  else
#    error "Unknown plat"
#  endif

   /* --- Platform-specific checks on sigactions --- */

#  if defined(VGO_linux)
   /* the toK- and fromK- forms are identical */
   vg_assert( sizeof(vki_sigaction_toK_t) 
              == sizeof(vki_sigaction_fromK_t) );
#  elif defined(VGO_darwin)
   /* the toK- and fromK- forms differ by one function-pointer field
      (sa_tramp) */
   vg_assert( sizeof(vki_sigaction_toK_t) 
              == sizeof(vki_sigaction_fromK_t) + sizeof(void*) );

   vg_assert(sizeof(struct sigaction) == sizeof(vki_sigaction_fromK_t));
   vg_assert(sizeof(struct __sigaction) == sizeof(vki_sigaction_toK_t));
   { struct __sigaction    t1;
     vki_sigaction_toK_t   t2;
     struct sigaction      f1;
     vki_sigaction_fromK_t f2;
     vg_assert(sizeof(t1.sa_handler) == sizeof(t2.ksa_handler));
     vg_assert(sizeof(t1.sa_tramp)   == sizeof(t2.sa_tramp));
     vg_assert(sizeof(t1.sa_mask)    == sizeof(t2.sa_mask));
     vg_assert(sizeof(t1.sa_flags)   == sizeof(t2.sa_flags));
     vg_assert(sizeof(f1.sa_handler) == sizeof(f2.ksa_handler));
     vg_assert(sizeof(f1.sa_mask)    == sizeof(f2.sa_mask));
     vg_assert(sizeof(f1.sa_flags)   == sizeof(f2.sa_flags));
#    if 0
     vg_assert(offsetof(t1,sa_handler) == offsetof(t2.ksa_handler));
     vg_assert(offsetof(t1.sa_tramp)   == offsetof(t2.sa_tramp));
     vg_assert(offsetof(t1.sa_mask)    == offsetof(t2.sa_mask));
     vg_assert(offsetof(t1.sa_flags)   == offsetof(t2.sa_flags));
     vg_assert(offsetof(f1.sa_handler) == offsetof(f2.ksa_handler));
     vg_assert(offsetof(f1.sa_mask)    == offsetof(f2.sa_mask));
     vg_assert(offsetof(f1.sa_flags)   == offsetof(f2.sa_flags));
#    endif
   }
   /* also .. */
   /* VKI_SET_SIGMASK is hardwired into syscall-x86-darwin.S and
      syscall-amd64-darwin.S */
   vg_assert(VKI_SIG_SETMASK == 3);

#  else
#     error "Unknown OS" 
#  endif
}
コード例 #17
0
ファイル: tytypes.c プロジェクト: sabinaya/valgrind-variant
Word ML_(TyEnt__cmp_by_all_except_cuOff) ( TyEnt* te1, TyEnt* te2 )
{
   Word r;
   if (te1->tag < te2->tag) return -1;
   if (te1->tag > te2->tag) return 1;
   switch (te1->tag) {
   case Te_EMPTY:
      return 0;
   case Te_INDIR:
      r = UWord__cmp(te1->Te.INDIR.indR, te2->Te.INDIR.indR);
      return r;
   case Te_Atom:
      r = Bool__cmp(te1->Te.Atom.valueKnown, te2->Te.Atom.valueKnown);
      if (r != 0) return r;
      r = Long__cmp(te1->Te.Atom.value, te2->Te.Atom.value);
      if (r != 0) return r;
      r = Asciiz__cmp(te1->Te.Atom.name, te2->Te.Atom.name);
      return r;
   case Te_Field:
      r = Bool__cmp(te1->Te.Field.isStruct, te2->Te.Field.isStruct);
      if (r != 0) return r;
      r = UWord__cmp(te1->Te.Field.typeR, te2->Te.Field.typeR);
      if (r != 0) return r;
      r = Asciiz__cmp(te1->Te.Field.name, te2->Te.Field.name);
      if (r != 0) return r;
      r = UWord__cmp(te1->Te.Field.nLoc, te2->Te.Field.nLoc);
      if (r != 0) return r;
      if (te1->Te.Field.nLoc == -1)
         r = Long__cmp(te1->Te.Field.pos.offset, te2->Te.Field.pos.offset);
      else
         r = Bytevector__cmp(te1->Te.Field.pos.loc, te2->Te.Field.pos.loc,
                             te1->Te.Field.nLoc);
      return r;
   case Te_Bound:
      r = Bool__cmp(te1->Te.Bound.knownL, te2->Te.Bound.knownL);
      if (r != 0) return r;
      r = Bool__cmp(te1->Te.Bound.knownU, te2->Te.Bound.knownU);
      if (r != 0) return r;
      r = Long__cmp(te1->Te.Bound.boundL, te2->Te.Bound.boundL);
      if (r != 0) return r;
      r = Long__cmp(te1->Te.Bound.boundU, te2->Te.Bound.boundU);
      return r;
   case Te_TyBase:
      r = UChar__cmp(te1->Te.TyBase.enc, te2->Te.TyBase.enc);
      if (r != 0) return r;
      r = Int__cmp(te1->Te.TyBase.szB, te2->Te.TyBase.szB);
      if (r != 0) return r;
      r = Asciiz__cmp(te1->Te.TyBase.name, te2->Te.TyBase.name);
      return r;
   case Te_TyPtr:
   case Te_TyRef:
   case Te_TyPtrMbr:
   case Te_TyRvalRef:
      r = Int__cmp(te1->Te.TyPorR.szB, te2->Te.TyPorR.szB);
      if (r != 0) return r;
      r = UWord__cmp(te1->Te.TyPorR.typeR, te2->Te.TyPorR.typeR);
      return r;
   case Te_TyTyDef:
      r = UWord__cmp(te1->Te.TyTyDef.typeR, te2->Te.TyTyDef.typeR);
      if (r != 0) return r;
      r = Asciiz__cmp(te1->Te.TyTyDef.name, te2->Te.TyTyDef.name);
      return r;
   case Te_TyStOrUn:
      r = Bool__cmp(te1->Te.TyStOrUn.isStruct, te2->Te.TyStOrUn.isStruct);
      if (r != 0) return r;
      r = Bool__cmp(te1->Te.TyStOrUn.complete, te2->Te.TyStOrUn.complete);
      if (r != 0) return r;
      r = UWord__cmp(te1->Te.TyStOrUn.szB, te2->Te.TyStOrUn.szB);
      if (r != 0) return r;
      r = Asciiz__cmp(te1->Te.TyStOrUn.name, te2->Te.TyStOrUn.name);
      if (r != 0) return r;
      r = XArray_of_UWord__cmp(te1->Te.TyStOrUn.fieldRs,
                               te2->Te.TyStOrUn.fieldRs);
      return r;
   case Te_TyEnum:
      r = Int__cmp(te1->Te.TyEnum.szB, te2->Te.TyEnum.szB);
      if (r != 0) return r;
      r = Asciiz__cmp(te1->Te.TyEnum.name, te2->Te.TyEnum.name);
      if (r != 0) return r;
      r = XArray_of_UWord__cmp(te1->Te.TyEnum.atomRs, te2->Te.TyEnum.atomRs);
      return r;
   case Te_TyArray:
      r = UWord__cmp(te1->Te.TyArray.typeR, te2->Te.TyArray.typeR);
      if (r != 0) return r;
      r = XArray_of_UWord__cmp(te1->Te.TyArray.boundRs,
                               te2->Te.TyArray.boundRs);
      return r;
   case Te_TyFn:
      return 0;
   case Te_TyQual:
      r = UWord__cmp(te1->Te.TyQual.typeR, te2->Te.TyQual.typeR);
      if (r != 0) return r;
      r = UChar__cmp(te1->Te.TyQual.qual, te2->Te.TyQual.qual);
      return r;
   case Te_TyVoid:
      r = Bool__cmp(te1->Te.TyVoid.isFake, te2->Te.TyVoid.isFake);
      return r;
   default:
      vg_assert(0);
   }
}
コード例 #18
0
ファイル: initimg-darwin.c プロジェクト: cherry-wb/SmartFuzz
static 
Addr setup_client_stack( void*  init_sp,
                         char** orig_envp, 
                         const ExeInfo* info,
                         Addr   clstack_end,
                         SizeT  clstack_max_size )
{
   char **cpp;
   char *strtab;		/* string table */
   char *stringbase;
   Addr *ptr;
   unsigned stringsize;		/* total size of strings in bytes */
   unsigned auxsize;		/* total size of auxv in bytes */
   Int argc;			/* total argc */
   Int envc;			/* total number of env vars */
   unsigned stacksize;		/* total client stack size */
   Addr client_SP;	        /* client stack base (initial SP) */
   Addr clstack_start;
   Int i;
   Bool have_exename;

   vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
   vg_assert( VG_(args_for_client) );

   /* ==================== compute sizes ==================== */

   /* first of all, work out how big the client stack will be */
   stringsize   = 0;
   auxsize = 0;
   have_exename = VG_(args_the_exename) != NULL;

   /* paste on the extra args if the loader needs them (ie, the #! 
      interpreter and its argument) */
   argc = 0;
   if (info->interp_name != NULL) {
      argc++;
      stringsize += VG_(strlen)(info->interp_name) + 1;
   }
   if (info->interp_args != NULL) {
      argc++;
      stringsize += VG_(strlen)(info->interp_args) + 1;
   }

   /* now scan the args we're given... */
   if (have_exename)
      stringsize += VG_(strlen)( VG_(args_the_exename) ) + 1;

   for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
      argc++;
      stringsize += VG_(strlen)( * (HChar**) 
                                   VG_(indexXA)( VG_(args_for_client), i ))
                    + 1;
   }

   /* ...and the environment */
   envc = 0;
   for (cpp = orig_envp; cpp && *cpp; cpp++) {
      envc++;
      stringsize += VG_(strlen)(*cpp) + 1;
   }

   /* Darwin executable_path + NULL */
   auxsize += 2 * sizeof(Word);
   if (info->executable_path) {
       stringsize += 1 + VG_(strlen)(info->executable_path);
   }

   /* Darwin mach_header */
   if (info->dynamic) auxsize += sizeof(Word);

   /* OK, now we know how big the client stack is */
   stacksize =
      sizeof(Word) +                          /* argc */
      (have_exename ? sizeof(char **) : 0) +  /* argc[0] == exename */
      sizeof(char **)*argc +                  /* argv */
      sizeof(char **) +	                      /* terminal NULL */
      sizeof(char **)*envc +                  /* envp */
      sizeof(char **) +	                      /* terminal NULL */
      auxsize +                               /* auxv */
      VG_ROUNDUP(stringsize, sizeof(Word));   /* strings (aligned) */

   if (0) VG_(printf)("stacksize = %d\n", stacksize);

   /* client_SP is the client's stack pointer */
   client_SP = clstack_end - stacksize;
   client_SP = VG_ROUNDDN(client_SP, 32); /* make stack 32 byte aligned */

   /* base of the string table (aligned) */
   stringbase = strtab = (char *)clstack_end 
                         - VG_ROUNDUP(stringsize, sizeof(int));

   /* The max stack size */
   clstack_max_size = VG_PGROUNDUP(clstack_max_size);

   /* Darwin stack is chosen by the ume loader */
   clstack_start = clstack_end - clstack_max_size;

   /* Record stack extent -- needed for stack-change code. */
   /* GrP fixme really? */
   VG_(clstk_base) = clstack_start;
   VG_(clstk_end)  = clstack_end;

   if (0)
      VG_(printf)("stringsize=%d auxsize=%d stacksize=%d maxsize=0x%x\n"
                  "clstack_start %p\n"
                  "clstack_end   %p\n",
	          stringsize, auxsize, stacksize, (Int)clstack_max_size,
                  (void*)clstack_start, (void*)clstack_end);

   /* ==================== allocate space ==================== */

   /* Stack was allocated by the ume loader. */

   /* ==================== create client stack ==================== */

   ptr = (Addr*)client_SP;

   /* --- mach_header --- */
   if (info->dynamic) *ptr++ = info->text;

   /* --- client argc --- */
   *ptr++ = (Addr)(argc + (have_exename ? 1 : 0));

   /* --- client argv --- */
   if (info->interp_name) {
      *ptr++ = (Addr)copy_str(&strtab, info->interp_name);
      VG_(free)(info->interp_name);
   }
   if (info->interp_args) {
      *ptr++ = (Addr)copy_str(&strtab, info->interp_args);
      VG_(free)(info->interp_args);
   }

   if (have_exename)
      *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename));

   for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
      *ptr++ = (Addr)copy_str(
                       &strtab, 
                       * (HChar**) VG_(indexXA)( VG_(args_for_client), i )
                     );
   }
   *ptr++ = 0;

   /* --- envp --- */
   VG_(client_envp) = (Char **)ptr;
   for (cpp = orig_envp; cpp && *cpp; ptr++, cpp++)
      *ptr = (Addr)copy_str(&strtab, *cpp);
   *ptr++ = 0;

   /* --- executable_path + NULL --- */
   if (info->executable_path) 
       *ptr++ = (Addr)copy_str(&strtab, info->executable_path);
   else 
       *ptr++ = 0;
   *ptr++ = 0;

   vg_assert((strtab-stringbase) == stringsize);

   /* client_SP is pointing at client's argc/argv */

   if (0) VG_(printf)("startup SP = %#lx\n", client_SP);
   return client_SP;
}
コード例 #19
0
ファイル: tytypes.c プロジェクト: sabinaya/valgrind-variant
MaybeULong ML_(sizeOfType)( XArray* /* of TyEnt */ tyents,
                            UWord cuOff )
{
   Word       i;
   MaybeULong eszB;
   TyEnt*     ent = ML_(TyEnts__index_by_cuOff)(tyents, NULL, cuOff);
   TyEnt*     ent2;
   vg_assert(ent);
   vg_assert(ML_(TyEnt__is_type)(ent));
   switch (ent->tag) {
      case Te_TyBase:
         vg_assert(ent->Te.TyBase.szB > 0);
         return mk_MaybeULong_Just( ent->Te.TyBase.szB );
      case Te_TyQual:
         return ML_(sizeOfType)( tyents, ent->Te.TyQual.typeR );
      case Te_TyTyDef:
         ent2 = ML_(TyEnts__index_by_cuOff)(tyents, NULL,
                                            ent->Te.TyTyDef.typeR);
         vg_assert(ent2);
         if (ent2->tag == Te_UNKNOWN)
            return mk_MaybeULong_Nothing(); /*UNKNOWN*/
         return ML_(sizeOfType)( tyents, ent->Te.TyTyDef.typeR );
      case Te_TyPtr:
      case Te_TyRef:
      case Te_TyPtrMbr:
      case Te_TyRvalRef:
         vg_assert(ent->Te.TyPorR.szB == 4 || ent->Te.TyPorR.szB == 8);
         return mk_MaybeULong_Just( ent->Te.TyPorR.szB );
      case Te_TyStOrUn:
         return ent->Te.TyStOrUn.complete
                   ? mk_MaybeULong_Just( ent->Te.TyStOrUn.szB )
                   : mk_MaybeULong_Nothing();
      case Te_TyEnum:
         return mk_MaybeULong_Just( ent->Te.TyEnum.szB );
      case Te_TyArray:
         ent2 = ML_(TyEnts__index_by_cuOff)(tyents, NULL,
                                            ent->Te.TyArray.typeR);
         vg_assert(ent2);
         if (ent2->tag == Te_UNKNOWN)
            return mk_MaybeULong_Nothing(); /*UNKNOWN*/
         eszB = ML_(sizeOfType)( tyents, ent->Te.TyArray.typeR );
         for (i = 0; i < VG_(sizeXA)( ent->Te.TyArray.boundRs ); i++) {
            UWord bo_cuOff
               = *(UWord*)VG_(indexXA)(ent->Te.TyArray.boundRs, i);
            TyEnt* bo
              = ML_(TyEnts__index_by_cuOff)( tyents, NULL, bo_cuOff );
            vg_assert(bo);
            vg_assert(bo->tag == Te_Bound);
            if (!(bo->Te.Bound.knownL && bo->Te.Bound.knownU))
               return mk_MaybeULong_Nothing(); /*UNKNOWN*/
            eszB = mul_MaybeULong( 
                      eszB,
                      mk_MaybeULong_Just( (ULong)(bo->Te.Bound.boundU 
                                                  - bo->Te.Bound.boundL + 1) ));
         }
         return eszB;
      case Te_TyVoid:
         return mk_MaybeULong_Nothing(); /*UNKNOWN*/
      default:
         VG_(printf)("ML_(sizeOfType): unhandled: ");
         ML_(pp_TyEnt)(ent);
         VG_(printf)("\n");
         vg_assert(0);
   }
}
コード例 #20
0
static
void transfer_register (ThreadId tid, int abs_regno, void * buf,
                        transfer_direction dir, int size, Bool *mod)
{
   ThreadState* tst = VG_(get_ThreadState)(tid);
   int set = abs_regno / num_regs;
   int regno = abs_regno % num_regs;
   *mod = False;

   VexGuestARMState* arm = (VexGuestARMState*) get_arch (set, tst);

   switch (regno) { 
   
   
   case 0:  VG_(transfer) (&arm->guest_R0,   buf, dir, size, mod); break;
   case 1:  VG_(transfer) (&arm->guest_R1,   buf, dir, size, mod); break;
   case 2:  VG_(transfer) (&arm->guest_R2,   buf, dir, size, mod); break;
   case 3:  VG_(transfer) (&arm->guest_R3,   buf, dir, size, mod); break;
   case 4:  VG_(transfer) (&arm->guest_R4,   buf, dir, size, mod); break;
   case 5:  VG_(transfer) (&arm->guest_R5,   buf, dir, size, mod); break;
   case 6:  VG_(transfer) (&arm->guest_R6,   buf, dir, size, mod); break;
   case 7:  VG_(transfer) (&arm->guest_R7,   buf, dir, size, mod); break;
   case 8:  VG_(transfer) (&arm->guest_R8,   buf, dir, size, mod); break;
   case 9:  VG_(transfer) (&arm->guest_R9,   buf, dir, size, mod); break;
   case 10: VG_(transfer) (&arm->guest_R10,  buf, dir, size, mod); break;
   case 11: VG_(transfer) (&arm->guest_R11,  buf, dir, size, mod); break;
   case 12: VG_(transfer) (&arm->guest_R12,  buf, dir, size, mod); break;
   case 13: VG_(transfer) (&arm->guest_R13,  buf, dir, size, mod); break;
   case 14: VG_(transfer) (&arm->guest_R14,  buf, dir, size, mod); break;
   case 15: { 
      VG_(transfer) (&arm->guest_R15T, buf, dir, size, mod);
      if (dir == gdbserver_to_valgrind && *mod) {
         
         
         arm->guest_R15T = thumb_pc(arm->guest_R15T);
      }
      break;
   }
   case 16:
   case 17:
   case 18:
   case 19:
   case 20: 
   case 21:
   case 22:
   case 23:
   case 24: *mod = False; break;
   case 25: {
      UInt cpsr = LibVEX_GuestARM_get_cpsr (arm);
      if (dir == valgrind_to_gdbserver) {
         VG_(transfer) (&cpsr, buf, dir, size, mod); 
      } else {
#      if 0
         UInt newcpsr;
         VG_(transfer) (&newcpsr, buf, dir, size, mod);
         *mod = newcpsr != cpsr;
         
         LibVEX_GuestARM_put_flags (newcpsr, arm);
#      else
         *mod = False;
#      endif
      }
      break;
   }
   case 26: VG_(transfer) (&arm->guest_D0,  buf, dir, size, mod); break;
   case 27: VG_(transfer) (&arm->guest_D1,  buf, dir, size, mod); break;
   case 28: VG_(transfer) (&arm->guest_D2,  buf, dir, size, mod); break;
   case 29: VG_(transfer) (&arm->guest_D3,  buf, dir, size, mod); break;
   case 30: VG_(transfer) (&arm->guest_D4,  buf, dir, size, mod); break;
   case 31: VG_(transfer) (&arm->guest_D5,  buf, dir, size, mod); break;
   case 32: VG_(transfer) (&arm->guest_D6,  buf, dir, size, mod); break;
   case 33: VG_(transfer) (&arm->guest_D7,  buf, dir, size, mod); break;
   case 34: VG_(transfer) (&arm->guest_D8,  buf, dir, size, mod); break;
   case 35: VG_(transfer) (&arm->guest_D9,  buf, dir, size, mod); break;
   case 36: VG_(transfer) (&arm->guest_D10, buf, dir, size, mod); break;
   case 37: VG_(transfer) (&arm->guest_D11, buf, dir, size, mod); break;
   case 38: VG_(transfer) (&arm->guest_D12, buf, dir, size, mod); break;
   case 39: VG_(transfer) (&arm->guest_D13, buf, dir, size, mod); break;
   case 40: VG_(transfer) (&arm->guest_D14, buf, dir, size, mod); break;
   case 41: VG_(transfer) (&arm->guest_D15, buf, dir, size, mod); break;
   case 42: VG_(transfer) (&arm->guest_D16, buf, dir, size, mod); break;
   case 43: VG_(transfer) (&arm->guest_D17, buf, dir, size, mod); break;
   case 44: VG_(transfer) (&arm->guest_D18, buf, dir, size, mod); break;
   case 45: VG_(transfer) (&arm->guest_D19, buf, dir, size, mod); break;
   case 46: VG_(transfer) (&arm->guest_D20, buf, dir, size, mod); break;
   case 47: VG_(transfer) (&arm->guest_D21, buf, dir, size, mod); break;
   case 48: VG_(transfer) (&arm->guest_D22, buf, dir, size, mod); break;
   case 49: VG_(transfer) (&arm->guest_D23, buf, dir, size, mod); break;
   case 50: VG_(transfer) (&arm->guest_D24, buf, dir, size, mod); break;
   case 51: VG_(transfer) (&arm->guest_D25, buf, dir, size, mod); break;
   case 52: VG_(transfer) (&arm->guest_D26, buf, dir, size, mod); break;
   case 53: VG_(transfer) (&arm->guest_D27, buf, dir, size, mod); break;
   case 54: VG_(transfer) (&arm->guest_D28, buf, dir, size, mod); break;
   case 55: VG_(transfer) (&arm->guest_D29, buf, dir, size, mod); break;
   case 56: VG_(transfer) (&arm->guest_D30, buf, dir, size, mod); break;
   case 57: VG_(transfer) (&arm->guest_D31, buf, dir, size, mod); break;
   case 58: VG_(transfer) (&arm->guest_FPSCR, buf, dir, size, mod); break;
   default: vg_assert(0);
   }
}
コード例 #21
0
ファイル: tytypes.c プロジェクト: sabinaya/valgrind-variant
void ML_(pp_TyEnt)( TyEnt* te )
{
   VG_(printf)("0x%05lx  ", te->cuOff);
   switch (te->tag) {
      case Te_EMPTY:
         VG_(printf)("EMPTY");
         break;
      case Te_INDIR:
         VG_(printf)("INDIR(0x%05lx)", te->Te.INDIR.indR);
         break;
      case Te_UNKNOWN:
         VG_(printf)("UNKNOWN");
         break;
      case Te_Atom:
         VG_(printf)("Te_Atom(%s%lld,\"%s\")",
                     te->Te.Atom.valueKnown ? "" : "unknown:",
                     te->Te.Atom.value, te->Te.Atom.name);
         break;
      case Te_Field:
         if (te->Te.Field.nLoc == -1)
            VG_(printf)("Te_Field(ty=0x%05lx,pos.offset=%ld,\"%s\")",
                        te->Te.Field.typeR, te->Te.Field.pos.offset,
                        te->Te.Field.name ? te->Te.Field.name : "");
         else
            VG_(printf)("Te_Field(ty=0x%05lx,nLoc=%lu,pos.loc=%p,\"%s\")",
                        te->Te.Field.typeR, te->Te.Field.nLoc,
                        te->Te.Field.pos.loc,
                        te->Te.Field.name ? te->Te.Field.name : "");
         break;
      case Te_Bound:
         VG_(printf)("Te_Bound[");
         if (te->Te.Bound.knownL)
            VG_(printf)("%lld", te->Te.Bound.boundL);
         else
            VG_(printf)("??");
         VG_(printf)(",");
         if (te->Te.Bound.knownU)
            VG_(printf)("%lld", te->Te.Bound.boundU);
         else
            VG_(printf)("??");
         VG_(printf)("]");
         break;
      case Te_TyBase:
         VG_(printf)("Te_TyBase(%d,%c,\"%s\")",
                     te->Te.TyBase.szB, te->Te.TyBase.enc,
                     te->Te.TyBase.name ? te->Te.TyBase.name
                                        : "(null)" );
         break;
      case Te_TyPtr:
         VG_(printf)("Te_TyPtr(%d,0x%05lx)", te->Te.TyPorR.szB,
                     te->Te.TyPorR.typeR);
         break;
      case Te_TyRef:
         VG_(printf)("Te_TyRef(%d,0x%05lx)", te->Te.TyPorR.szB,
                     te->Te.TyPorR.typeR);
         break;
      case Te_TyPtrMbr:
         VG_(printf)("Te_TyMbr(%d,0x%05lx)", te->Te.TyPorR.szB,
                     te->Te.TyPorR.typeR);
         break;
      case Te_TyRvalRef:
         VG_(printf)("Te_TyRvalRef(%d,0x%05lx)", te->Te.TyPorR.szB,
                     te->Te.TyPorR.typeR);
         break;
      case Te_TyTyDef:
         VG_(printf)("Te_TyTyDef(0x%05lx,\"%s\")",
                     te->Te.TyTyDef.typeR,
                     te->Te.TyTyDef.name ? te->Te.TyTyDef.name
                                         : "" );
         break;
      case Te_TyStOrUn:
         if (te->Te.TyStOrUn.complete) {
            VG_(printf)("Te_TyStOrUn(%ld,%c,%p,\"%s\")",
                        te->Te.TyStOrUn.szB, 
                        te->Te.TyStOrUn.isStruct ? 'S' : 'U',
                        te->Te.TyStOrUn.fieldRs,
                        te->Te.TyStOrUn.name ? te->Te.TyStOrUn.name
                                             : "" );
            if (te->Te.TyStOrUn.fieldRs)
               pp_XArray_of_cuOffs( te->Te.TyStOrUn.fieldRs );
         } else {
            VG_(printf)("Te_TyStOrUn(INCOMPLETE,\"%s\")",
                        te->Te.TyStOrUn.name);
         }
         break;
      case Te_TyEnum:
         VG_(printf)("Te_TyEnum(%d,%p,\"%s\")",
                     te->Te.TyEnum.szB, te->Te.TyEnum.atomRs,
                     te->Te.TyEnum.name ? te->Te.TyEnum.name
                                        : "" );
         if (te->Te.TyEnum.atomRs)
            pp_XArray_of_cuOffs( te->Te.TyEnum.atomRs );
         break;
      case Te_TyArray:
         VG_(printf)("Te_TyArray(0x%05lx,%p)",
                     te->Te.TyArray.typeR, te->Te.TyArray.boundRs);
         if (te->Te.TyArray.boundRs)
            pp_XArray_of_cuOffs( te->Te.TyArray.boundRs );
         break;
      case Te_TyFn:
         VG_(printf)("Te_TyFn");
         break;
      case Te_TyQual:
         VG_(printf)("Te_TyQual(%c,0x%05lx)", te->Te.TyQual.qual,
                     te->Te.TyQual.typeR);
         break;
      case Te_TyVoid:
         VG_(printf)("Te_TyVoid%s",
                     te->Te.TyVoid.isFake ? "(fake)" : "");
         break;
      default:
         vg_assert(0);
   }
}
コード例 #22
0
ファイル: hashtable.c プロジェクト: coder-chenzhi/aprof
void HT_ResetIter(HashTable * table) {
    vg_assert(table);
    table->iterNode = NULL;
    table->iterChain = 0;
    table->iterOK = True;
}
コード例 #23
0
ファイル: m_errormgr.c プロジェクト: githubzenganiu/toekn
/* Top-level entry point to the error management subsystem.
   All detected errors are notified here; this routine decides if/when the
   user should see the error. */
void VG_(maybe_record_error) ( ThreadId tid, 
                               ErrorKind ekind, Addr a, Char* s, void* extra )
{
          Error  err;
          Error* p;
          Error* p_prev;
          UInt   extra_size;
          VgRes  exe_res          = Vg_MedRes;
   static Bool   stopping_message = False;
   static Bool   slowdown_message = False;
   static Int    n_errs_shown     = 0;

   /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
      been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors
      have been found, just refuse to collect any more.  This stops
      the burden of the error-management system becoming excessive in
      extremely buggy programs, although it does make it pretty
      pointless to continue the Valgrind run after this point. */
   if (VG_(clo_error_limit) 
       && (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN
           || n_errs_found >= M_COLLECT_NO_ERRORS_AFTER_FOUND)
       && !VG_(clo_xml)) {
      if (!stopping_message) {
         VG_(message)(Vg_UserMsg, "");

	 if (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN) {
            VG_(message)(Vg_UserMsg, 
               "More than %d different errors detected.  "
               "I'm not reporting any more.",
               M_COLLECT_NO_ERRORS_AFTER_SHOWN );
         } else {
            VG_(message)(Vg_UserMsg, 
               "More than %d total errors detected.  "
               "I'm not reporting any more.",
               M_COLLECT_NO_ERRORS_AFTER_FOUND );
	 }

         VG_(message)(Vg_UserMsg, 
            "Final error counts will be inaccurate.  Go fix your program!");
         VG_(message)(Vg_UserMsg, 
            "Rerun with --error-limit=no to disable this cutoff.  Note");
         VG_(message)(Vg_UserMsg, 
            "that errors may occur in your program without prior warning from");
         VG_(message)(Vg_UserMsg, 
            "Valgrind, because errors are no longer being displayed.");
         VG_(message)(Vg_UserMsg, "");
         stopping_message = True;
      }
      return;
   }

   /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have
      been found, be much more conservative about collecting new
      ones. */
   if (n_errs_shown >= M_COLLECT_ERRORS_SLOWLY_AFTER
       && !VG_(clo_xml)) {
      exe_res = Vg_LowRes;
      if (!slowdown_message) {
         VG_(message)(Vg_UserMsg, "");
         VG_(message)(Vg_UserMsg, 
            "More than %d errors detected.  Subsequent errors",
            M_COLLECT_ERRORS_SLOWLY_AFTER);
         VG_(message)(Vg_UserMsg, 
            "will still be recorded, but in less detail than before.");
         slowdown_message = True;
      }
   }

   /* Build ourselves the error */
   construct_error ( &err, tid, ekind, a, s, extra, NULL );

   /* First, see if we've got an error record matching this one. */
   p      = errors;
   p_prev = NULL;
   while (p != NULL) {
      if (eq_Error(exe_res, p, &err)) {
         /* Found it. */
         p->count++;
	 if (p->supp != NULL) {
            /* Deal correctly with suppressed errors. */
            p->supp->count++;
            n_errs_suppressed++;	 
         } else {
            n_errs_found++;
         }

         /* Move p to the front of the list so that future searches
            for it are faster. */
         if (p_prev != NULL) {
            vg_assert(p_prev->next == p);
            p_prev->next = p->next;
            p->next      = errors;
            errors       = p;
	 }

         return;
      }
      p_prev = p;
      p      = p->next;
   }

   /* Didn't see it.  Copy and add. */

   /* OK, we're really going to collect it.  The context is on the stack and
      will disappear shortly, so we must copy it.  First do the main
      (non-'extra') part.
     
      Then VG_(tdict).tool_update_extra can update the 'extra' part.  This
      is for when there are more details to fill in which take time to work
      out but don't affect our earlier decision to include the error -- by
      postponing those details until now, we avoid the extra work in the
      case where we ignore the error.  Ugly.

      Then, if there is an 'extra' part, copy it too, using the size that
      VG_(tdict).tool_update_extra returned.  Also allow for people using
      the void* extra field for a scalar value like an integer.
   */

   /* copy main part */
   p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error));
   *p = err;

   /* update 'extra' */
   switch (ekind) {
     //      case ThreadErr:
     //      case MutexErr:
     //         vg_assert(VG_(needs).core_errors);
     //         extra_size = VG_(tm_error_update_extra)(p);
     //         break;
      default:
         vg_assert(VG_(needs).tool_errors);
         extra_size = VG_TDICT_CALL(tool_update_extra, p);
         break;
   }

   /* copy block pointed to by 'extra', if there is one */
   if (NULL != p->extra && 0 != extra_size) { 
      void* new_extra = VG_(malloc)(extra_size);
      VG_(memcpy)(new_extra, p->extra, extra_size);
      p->extra = new_extra;
   }

   p->next = errors;
   p->supp = is_suppressible_error(&err);
   errors  = p;
   if (p->supp == NULL) {
      n_errs_found++;
      if (!is_first_shown_context)
         VG_(message)(Vg_UserMsg, "");
      pp_Error(p);
      is_first_shown_context = False;
      n_errs_shown++;
      do_actions_on_error(p, /*allow_db_attach*/True);
   } else {
      n_errs_suppressed++;
      p->supp->count++;
   }
}
コード例 #24
0
/* 
   When a client clones, we need to keep track of the new thread.  This means:
   1. allocate a ThreadId+ThreadState+stack for the thread

   2. initialize the thread's new VCPU state

   3. create the thread using the same args as the client requested,
   but using the scheduler entrypoint for EIP, and a separate stack
   for ESP.
 */
static SysRes do_clone ( ThreadId ptid, 
                         ULong flags, Addr rsp, 
                         Long* parent_tidptr, 
                         Long* child_tidptr, 
                         Addr tlsaddr )
{
   static const Bool debug = False;

   ThreadId     ctid = VG_(alloc_ThreadState)();
   ThreadState* ptst = VG_(get_ThreadState)(ptid);
   ThreadState* ctst = VG_(get_ThreadState)(ctid);
   UWord*       stack;
   SysRes       res;
   Long         rax;
   vki_sigset_t blockall, savedmask;

   VG_(sigfillset)(&blockall);

   vg_assert(VG_(is_running_thread)(ptid));
   vg_assert(VG_(is_valid_tid)(ctid));

   stack = (UWord*)ML_(allocstack)(ctid);
   if (stack == NULL) {
      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
      goto out;
   }

   /* Copy register state

      Both parent and child return to the same place, and the code
      following the clone syscall works out which is which, so we
      don't need to worry about it.

      The parent gets the child's new tid returned from clone, but the
      child gets 0.

      If the clone call specifies a NULL rsp for the new thread, then
      it actually gets a copy of the parent's rsp.
   */
   setup_child( &ctst->arch, &ptst->arch );

   /* Make sys_clone appear to have returned Success(0) in the
      child. */
   ctst->arch.vex.guest_RAX = 0;

   if (rsp != 0)
      ctst->arch.vex.guest_RSP = rsp;

   ctst->os_state.parent = ptid;

   /* inherit signal mask */
   ctst->sig_mask = ptst->sig_mask;
   ctst->tmp_sig_mask = ptst->sig_mask;

   /* Start the child with its threadgroup being the same as the
      parent's.  This is so that any exit_group calls that happen
      after the child is created but before it sets its
      os_state.threadgroup field for real (in thread_wrapper in
      syswrap-linux.c), really kill the new thread.  a.k.a this avoids
      a race condition in which the thread is unkillable (via
      exit_group) because its threadgroup is not set.  The race window
      is probably only a few hundred or a few thousand cycles long.
      See #226116. */
   ctst->os_state.threadgroup = ptst->os_state.threadgroup;

   ML_(guess_and_register_stack) (rsp, ctst);

   /* Assume the clone will succeed, and tell any tool that wants to
      know that this thread has come into existence.  If the clone
      fails, we'll send out a ll_exit notification for it at the out:
      label below, to clean up. */
   vg_assert(VG_(owns_BigLock_LL)(ptid));
   VG_TRACK ( pre_thread_ll_create, ptid, ctid );

   if (flags & VKI_CLONE_SETTLS) {
      if (debug)
	 VG_(printf)("clone child has SETTLS: tls at %#lx\n", tlsaddr);
      ctst->arch.vex.guest_FS_CONST = tlsaddr;
   }

   flags &= ~VKI_CLONE_SETTLS;

   /* start the thread with everything blocked */
   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);

   /* Create the new thread */
   rax = do_syscall_clone_amd64_linux(
            ML_(start_thread_NORETURN), stack, flags, &VG_(threads)[ctid],
            child_tidptr, parent_tidptr, NULL
         );
   res = VG_(mk_SysRes_amd64_linux)( rax );

   VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);

  out:
   if (sr_isError(res)) {
      /* clone failed */
      VG_(cleanup_thread)(&ctst->arch);
      ctst->status = VgTs_Empty;
      /* oops.  Better tell the tool the thread exited in a hurry :-) */
      VG_TRACK( pre_thread_ll_exit, ctid );
   }

   return res;
}
コード例 #25
0
ファイル: readmacho.c プロジェクト: svn2github/valgrind-3
/* Map a given fat or thin object aboard, find the thin part if
   necessary, do some checks, and write details of both the fat and
   thin parts into *ii.  Returns False (and leaves the file unmapped)
   on failure.  Guarantees to return pointers to a valid(ish) Mach-O
   image if it succeeds. */
static Bool map_image_aboard ( DebugInfo* di, /* only for err msgs */
                               /*OUT*/ImageInfo* ii, UChar* filename )
{
   VG_(memset)(ii, 0, sizeof(*ii));

   /* First off, try to map the thing in. */
   { SizeT  size;
     SysRes fd, sres;
     struct vg_stat stat_buf;

     fd = VG_(stat)(filename, &stat_buf);
     if (sr_isError(fd)) {
        ML_(symerr)(di, True, "Can't stat image (to determine its size)?!");
        return False;
     }
     size = stat_buf.size;

     fd = VG_(open)(filename, VKI_O_RDONLY, 0);
     if (sr_isError(fd)) {
       ML_(symerr)(di, True, "Can't open image to read symbols?!");
        return False;
     }

     sres = VG_(am_mmap_file_float_valgrind)
               ( size, VKI_PROT_READ, sr_Res(fd), 0 );
     if (sr_isError(sres)) {
        ML_(symerr)(di, True, "Can't mmap image to read symbols?!");
        return False;
     }

     VG_(close)(sr_Res(fd));

     ii->img     = (UChar*)sr_Res(sres);
     ii->img_szB = size;
   }

   /* Now it's mapped in and we have .img and .img_szB set.  Look for
      the embedded Mach-O object.  If not findable, unmap and fail. */
   { struct fat_header*  fh_be;
     struct fat_header   fh;
     struct MACH_HEADER* mh;
     
     // Assume initially that we have a thin image, and update
     // these if it turns out to be fat.
     ii->macho_img     = ii->img;
     ii->macho_img_szB = ii->img_szB;

     // Check for fat header.
     if (ii->img_szB < sizeof(struct fat_header)) {
        ML_(symerr)(di, True, "Invalid Mach-O file (0 too small).");
        goto unmap_and_fail;
     }

     // Fat header is always BIG-ENDIAN
     fh_be = (struct fat_header *)ii->img;
     fh.magic = VG_(ntohl)(fh_be->magic);
     fh.nfat_arch = VG_(ntohl)(fh_be->nfat_arch);
     if (fh.magic == FAT_MAGIC) {
        // Look for a good architecture.
        struct fat_arch *arch_be;
        struct fat_arch arch;
        Int f;
        if (ii->img_szB < sizeof(struct fat_header)
                          + fh.nfat_arch * sizeof(struct fat_arch)) {
           ML_(symerr)(di, True, "Invalid Mach-O file (1 too small).");
           goto unmap_and_fail;
        }
        for (f = 0, arch_be = (struct fat_arch *)(fh_be+1); 
             f < fh.nfat_arch;
             f++, arch_be++) {
           Int cputype;
#          if defined(VGA_ppc)
           cputype = CPU_TYPE_POWERPC;
#          elif defined(VGA_ppc64)
           cputype = CPU_TYPE_POWERPC64;
#          elif defined(VGA_x86)
           cputype = CPU_TYPE_X86;
#          elif defined(VGA_amd64)
           cputype = CPU_TYPE_X86_64;
#          else
#            error "unknown architecture"
#          endif
           arch.cputype    = VG_(ntohl)(arch_be->cputype);
           arch.cpusubtype = VG_(ntohl)(arch_be->cpusubtype);
           arch.offset     = VG_(ntohl)(arch_be->offset);
           arch.size       = VG_(ntohl)(arch_be->size);
           if (arch.cputype == cputype) {
              if (ii->img_szB < arch.offset + arch.size) {
                 ML_(symerr)(di, True, "Invalid Mach-O file (2 too small).");
                 goto unmap_and_fail;
              }
              ii->macho_img     = ii->img + arch.offset;
              ii->macho_img_szB = arch.size;
              break;
           }
        }
        if (f == fh.nfat_arch) {
           ML_(symerr)(di, True,
                       "No acceptable architecture found in fat file.");
           goto unmap_and_fail;
        }
     }

     /* Sanity check what we found. */

     /* assured by logic above */
     vg_assert(ii->img_szB >= sizeof(struct fat_header));

     if (ii->macho_img_szB < sizeof(struct MACH_HEADER)) {
        ML_(symerr)(di, True, "Invalid Mach-O file (3 too small).");
        goto unmap_and_fail;
     }

     if (ii->macho_img_szB > ii->img_szB) {
        ML_(symerr)(di, True, "Invalid Mach-O file (thin bigger than fat).");
        goto unmap_and_fail;
     }

     if (ii->macho_img >= ii->img
         && ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB) {
        /* thin entirely within fat, as expected */
     } else {
        ML_(symerr)(di, True, "Invalid Mach-O file (thin not inside fat).");
        goto unmap_and_fail;
     }

     mh = (struct MACH_HEADER *)ii->macho_img;
     if (mh->magic != MAGIC) {
        ML_(symerr)(di, True, "Invalid Mach-O file (bad magic).");
        goto unmap_and_fail;
     }

     if (ii->macho_img_szB < sizeof(struct MACH_HEADER) + mh->sizeofcmds) {
        ML_(symerr)(di, True, "Invalid Mach-O file (4 too small).");
        goto unmap_and_fail;
     }
   }

   vg_assert(ii->img);
   vg_assert(ii->macho_img);
   vg_assert(ii->img_szB > 0);
   vg_assert(ii->macho_img_szB > 0);
   vg_assert(ii->macho_img >= ii->img);
   vg_assert(ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB);
   return True;  /* success */
   /*NOTREACHED*/

  unmap_and_fail:
   unmap_image(ii);
   return False; /* bah! */
}
コード例 #26
0
/* EXPORTED */
void VG_(sigframe_create)( ThreadId tid, 
                           Addr sp_top_of_frame,
                           const vki_siginfo_t *siginfo,
                           void *handler, 
                           UInt flags,
                           const vki_sigset_t *mask,
		           void *restorer )
{
   struct vg_sig_private *priv;
   Addr sp;
   ThreadState *tst;
   Int sigNo = siginfo->si_signo;
   Addr faultaddr;

   /* Stack must be 16-byte aligned */
   sp_top_of_frame &= ~0xf;

   if (flags & VKI_SA_SIGINFO) {
      sp = sp_top_of_frame - sizeof(struct rt_sigframe);
   } else {
      sp = sp_top_of_frame - sizeof(struct nonrt_sigframe);
   }

   tst = VG_(get_ThreadState)(tid);

   if (!extend(tst, sp, sp_top_of_frame - sp))
      return;

   vg_assert(VG_IS_16_ALIGNED(sp));

   /* Set up the stack chain pointer */
   VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
             sp, sizeof(UWord) );
   *(Addr *)sp = tst->arch.vex.guest_GPR1;
   VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 
             sp, sizeof(UWord) );

   faultaddr = (Addr)siginfo->_sifields._sigfault._addr;
   if (sigNo == VKI_SIGILL && siginfo->si_code > 0)
      faultaddr = tst->arch.vex.guest_CIA;

   if (flags & VKI_SA_SIGINFO) {
      struct rt_sigframe *frame = (struct rt_sigframe *) sp;
      struct vki_ucontext *ucp = &frame->ucontext;

      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame siginfo",
                (Addr)&frame->siginfo, sizeof(frame->siginfo) );
      VG_(memcpy)(&frame->siginfo, siginfo, sizeof(*siginfo));
      VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 
                (Addr)&frame->siginfo, sizeof(frame->siginfo) );

      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame ucontext",
                (Addr)ucp, offsetof(struct vki_ucontext, uc_pad) );
      ucp->uc_flags = 0;
      ucp->uc_link = 0;
      ucp->uc_stack = tst->altstack;
      VG_TRACK( post_mem_write, Vg_CoreSignal, tid, (Addr)ucp,
                offsetof(struct vki_ucontext, uc_pad) );

      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame ucontext",
                (Addr)&ucp->uc_regs,
                sizeof(ucp->uc_regs) + sizeof(ucp->uc_sigmask) );
      ucp->uc_regs = &ucp->uc_mcontext;
      ucp->uc_sigmask = tst->sig_mask;
      VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 
                (Addr)&ucp->uc_regs,
                sizeof(ucp->uc_regs) + sizeof(ucp->uc_sigmask) );

      stack_mcontext(&ucp->uc_mcontext, tst, __NR_rt_sigreturn, faultaddr);
      priv = &frame->priv;

      SET_SIGNAL_GPR(tid, 4, (Addr) &frame->siginfo);
      SET_SIGNAL_GPR(tid, 5, (Addr) ucp);
      /* the kernel sets this, though it doesn't seem to be in the ABI */
      SET_SIGNAL_GPR(tid, 6, (Addr) &frame->siginfo);

   } else {
コード例 #27
0
ファイル: readmacho.c プロジェクト: svn2github/valgrind-3
/* 'cand' is a bunch of candidate symbols obtained by reading
   nlist-style symbol table entries.  Their ends may overlap, so sort
   them and truncate them accordingly.  The code in this routine is
   copied almost verbatim from read_symbol_table() in readxcoff.c. */
static void tidy_up_cand_syms ( /*MOD*/XArray* /* of DiSym */ syms,
                                Bool trace_symtab )
{
   Word nsyms, i, j, k, m;

   nsyms = VG_(sizeXA)(syms);

   VG_(setCmpFnXA)(syms, cmp_DiSym_by_start_then_name);
   VG_(sortXA)(syms);

   /* We only know for sure the start addresses (actual VMAs) of
      symbols, and an overestimation of their end addresses.  So sort
      by start address, then clip each symbol so that its end address
      does not overlap with the next one along.

      There is a small refinement: if a group of symbols have the same
      address, treat them as a group: find the next symbol along that
      has a higher start address, and clip all of the group
      accordingly.  This clips the group as a whole so as not to
      overlap following symbols.  This leaves prefersym() in
      storage.c, which is not nlist-specific, to later decide which of
      the symbols in the group to keep.

      Another refinement is that we need to get rid of symbols which,
      after clipping, have identical starts, ends, and names.  So the
      sorting uses the name as a secondary key.
   */

   for (i = 0; i < nsyms; i++) {
      for (k = i+1;
           k < nsyms
             && ((DiSym*)VG_(indexXA)(syms,i))->addr
                 == ((DiSym*)VG_(indexXA)(syms,k))->addr;
           k++)
         ;
      /* So now [i .. k-1] is a group all with the same start address.
         Clip their ending addresses so they don't overlap [k].  In
         the normal case (no overlaps), k == i+1. */
      if (k < nsyms) {
         DiSym* next = (DiSym*)VG_(indexXA)(syms,k);
         for (m = i; m < k; m++) {
            DiSym* here = (DiSym*)VG_(indexXA)(syms,m);
            vg_assert(here->addr < next->addr);
            if (here->addr + here->size > next->addr)
               here->size = next->addr - here->addr;
         }
      }
      i = k-1;
      vg_assert(i <= nsyms);
   }

   j = 0;
   if (nsyms > 0) {
      j = 1;
      for (i = 1; i < nsyms; i++) {
         DiSym *s_j1, *s_j, *s_i;
         vg_assert(j <= i);
         s_j1 = (DiSym*)VG_(indexXA)(syms, j-1);
         s_j  = (DiSym*)VG_(indexXA)(syms, j);
         s_i  = (DiSym*)VG_(indexXA)(syms, i);
         if (s_i->addr != s_j1->addr
             || s_i->size != s_j1->size
             || 0 != VG_(strcmp)(s_i->name, s_j1->name)) {
            *s_j = *s_i;
            j++;
         } else {
            if (trace_symtab)
               VG_(printf)("nlist cleanup: dump duplicate avma %010lx  %s\n",
                           s_i->addr, s_i->name );
         }
      }
   }
   vg_assert(j >= 0 && j <= nsyms);
   VG_(dropTailXA)(syms, nsyms - j);
}
コード例 #28
0
ファイル: tytypes.c プロジェクト: sabinaya/valgrind-variant
void ML_(pp_TyEnt_C_ishly)( XArray* /* of TyEnt */ tyents,
                            UWord cuOff )
{
   TyEnt* ent = ML_(TyEnts__index_by_cuOff)( tyents, NULL, cuOff );
   if (!ent) {
      VG_(printf)("**type-has-invalid-cuOff**");
      return;
   }
   switch (ent->tag) {
      case Te_TyBase:
         if (!ent->Te.TyBase.name) goto unhandled;
         VG_(printf)("%s", ent->Te.TyBase.name);
         break;
      case Te_TyPtr:
         ML_(pp_TyEnt_C_ishly)(tyents, ent->Te.TyPorR.typeR);
         VG_(printf)("*");
         break;
      case Te_TyRef:
         ML_(pp_TyEnt_C_ishly)(tyents, ent->Te.TyPorR.typeR);
         VG_(printf)("&");
         break;
      case Te_TyPtrMbr:
         ML_(pp_TyEnt_C_ishly)(tyents, ent->Te.TyPorR.typeR);
         VG_(printf)("*");
         break;
      case Te_TyRvalRef:
         ML_(pp_TyEnt_C_ishly)(tyents, ent->Te.TyPorR.typeR);
         VG_(printf)("&&");
         break;
      case Te_TyEnum:
         if (!ent->Te.TyEnum.name) goto unhandled;
         VG_(printf)("enum %s", ent->Te.TyEnum.name);
         break;
      case Te_TyStOrUn:
         VG_(printf)("%s %s",
                     ent->Te.TyStOrUn.isStruct ? "struct" : "union",
                     ent->Te.TyStOrUn.name ? ent->Te.TyStOrUn.name
                                           : "<anonymous>" );
         break;
      case Te_TyArray:
         ML_(pp_TyEnt_C_ishly)(tyents, ent->Te.TyArray.typeR);
         if (ent->Te.TyArray.boundRs) {
            Word    w;
            XArray* xa = ent->Te.TyArray.boundRs;
            for (w = 0; w < VG_(sizeXA)(xa); w++) {
               pp_TyBound_C_ishly( tyents, *(UWord*)VG_(indexXA)(xa, w) );
            }
         } else {
            VG_(printf)("%s", "[??]");
         }
         break;
      case Te_TyTyDef:
         if (!ent->Te.TyTyDef.name) goto unhandled;
         VG_(printf)("%s", ent->Te.TyTyDef.name);
         break;
      case Te_TyFn:
         VG_(printf)("%s", "<function_type>");
         break;
      case Te_TyQual:
         switch (ent->Te.TyQual.qual) {
            case 'C': VG_(printf)("const "); break;
            case 'V': VG_(printf)("volatile "); break;
            default: goto unhandled;
         }
         ML_(pp_TyEnt_C_ishly)(tyents, ent->Te.TyQual.typeR);
         break;
      case Te_TyVoid:
         VG_(printf)("%svoid",
                     ent->Te.TyVoid.isFake ? "fake" : "");
         break;
      case Te_UNKNOWN:
         ML_(pp_TyEnt)(ent);
         break;
      default:
         goto unhandled;
   }
   return;

  unhandled:
   VG_(printf)("pp_TyEnt_C_ishly:unhandled: ");
   ML_(pp_TyEnt)(ent);
   vg_assert(0);
}
コード例 #29
0
/* EXPORTED */
void VG_(sigframe_create)( ThreadId tid, 
                           Addr sp_top_of_frame,
                           const vki_siginfo_t *siginfo,
                           const struct vki_ucontext *siguc,
                           void *handler, 
                           UInt flags,
                           const vki_sigset_t *mask,
                           void *restorer )
{
  Addr sp;
  ThreadState* tst = VG_(get_ThreadState)(tid);
  Int sigNo = siginfo->si_signo;
  struct vg_sig_private *priv;

  /* Stack must be 8-byte aligned */
  sp_top_of_frame &= ~0xf;

  if (flags & VKI_SA_SIGINFO)
    {
      sp = sp_top_of_frame - sizeof(struct rt_sigframe);
    }
  else
    {
      sp = sp_top_of_frame - sizeof(struct sigframe);
    }

  tst = VG_(get_ThreadState)(tid);
  if (!extend(tst, sp, sp_top_of_frame - sp))
    return;

  vg_assert(VG_IS_8_ALIGNED(sp));
      
  if (flags & VKI_SA_SIGINFO)
    {
      struct rt_sigframe *frame = (struct rt_sigframe *) sp;
      struct vki_ucontext *ucp = &frame->rs_uc;
      if (VG_(clo_trace_signals))
        VG_(printf)("rt_sigframe\n");
      /* Create siginfo.  */
      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame siginfo",
               (Addr)&frame->rs_info, sizeof(frame->rs_info) );

      VG_(memcpy)(&frame->rs_info, siginfo, sizeof(*siginfo));

      VG_TRACK( post_mem_write, Vg_CoreSignal, tid, 
               (Addr)&frame->rs_info, sizeof(frame->rs_info) );

      /* Create the ucontext.  */
      VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal frame ucontext",
               (Addr)ucp, offsetof(struct vki_ucontext, uc_mcontext) );

      ucp->uc_flags = 0;  
      ucp->uc_link = 0;
      ucp->uc_stack = tst->altstack;

      VG_TRACK( post_mem_write, Vg_CoreSignal, tid, (Addr)ucp,
               offsetof(struct vki_ucontext, uc_mcontext) );

      struct vki_sigcontext *scp = &(frame->rs_uc.uc_mcontext);
      setup_sigcontext2(tst, &(scp), siginfo);

      ucp->uc_sigmask = tst->sig_mask;

      priv = &frame->priv;

      /*
       * Arguments to signal handler:
       *
       *   a0 = signal number
       *   a1 = 0 (should be cause)
       *   a2 = pointer to ucontext
       *
       * $25 and c0_epc point to the signal handler, $29 points to
       * the struct rt_sigframe.
       */

      tst->arch.vex.guest_r4 = siginfo->si_signo;
      tst->arch.vex.guest_r5 = (Addr) &frame->rs_info;
      tst->arch.vex.guest_r6 = (Addr) &frame->rs_uc;
      tst->arch.vex.guest_r29 = (Addr) frame;
      tst->arch.vex.guest_r25 = (Addr) handler;

      if (flags & VKI_SA_RESTORER)
        {
          tst->arch.vex.guest_r31 = (Addr) restorer;  
        }
      else
        {
          tst->arch.vex.guest_r31 = (Addr)&VG_(mips32_linux_SUBST_FOR_rt_sigreturn);
        }

    }
  else
    {
      if (VG_(clo_trace_signals))
コード例 #30
0
ファイル: vg_memory.c プロジェクト: svn2github/valgrind-3
/* This unmaps all the segments in the range [addr, addr+len); any
   partial mappings at the ends are truncated. */
void VG_(unmap_range)(Addr addr, UInt len)
{
   Segment *s;
   Segment *next;
   static const Bool debug = False || mem_debug;
   Addr end;

   if (len == 0)
      return;

   len = PGROUNDUP(len);
   vg_assert(addr == PGROUNDDN(addr));

   if (debug)
      VG_(printf)("unmap_range(%p, %d)\n", addr, len);

   end = addr+len;

   /* Everything must be page-aligned */
   vg_assert((addr & (VKI_BYTES_PER_PAGE-1)) == 0);
   vg_assert((len  & (VKI_BYTES_PER_PAGE-1)) == 0);

   for(s = VG_(SkipList_Find)(&sk_segments, &addr); 
       s != NULL && s->addr < (addr+len); 
       s = next) {
      Addr seg_end = s->addr + s->len;

      /* fetch next now in case we end up deleting this segment */
      next = VG_(SkipNode_Next)(&sk_segments, s);

      if (debug)
	 VG_(printf)("unmap: addr=%p-%p s=%p ->addr=%p-%p len=%d\n",
		     addr, end, s, s->addr, seg_end, s->len);

      if (!VG_(seg_overlaps)(s, addr, len)) {
	 if (debug)
	    VG_(printf)("   (no overlap)\n");
	 continue;
      }

      /* 4 cases: */
      if (addr > s->addr &&
	  addr < seg_end &&
	  end >= seg_end) {
	 /* this segment's tail is truncated by [addr, addr+len)
	    -> truncate tail
	 */
	 s->len = addr - s->addr;

	 if (debug)
	    VG_(printf)("  case 1: s->len=%d\n", s->len);
      } else if (addr <= s->addr && end > s->addr && end < seg_end) {
	 /* this segment's head is truncated by [addr, addr+len)
	    -> truncate head
	 */
	 Int delta = end - s->addr;

	 if (debug)
	    VG_(printf)("  case 2: s->addr=%p s->len=%d delta=%d\n", s->addr, s->len, delta);

	 s->addr += delta;
	 s->offset += delta;
	 s->len -= delta;

	 vg_assert(s->len != 0);
      } else if (addr <= s->addr && end >= seg_end) {
	 /* this segment is completely contained within [addr, addr+len)
	    -> delete segment
	 */
	 Segment *rs = VG_(SkipList_Remove)(&sk_segments, &s->addr);
	 vg_assert(rs == s);
	 freeseg(s);

	 if (debug)
	    VG_(printf)("  case 3: s==%p deleted\n", s);
      } else if (addr > s->addr && end < seg_end) {
	 /* [addr, addr+len) is contained within a single segment
	    -> split segment into 3, delete middle portion
	  */
	 Segment *middle, *rs;

	 middle = VG_(split_segment)(addr);
	 VG_(split_segment)(addr+len);

	 vg_assert(middle->addr == addr);
	 rs = VG_(SkipList_Remove)(&sk_segments, &addr);
	 vg_assert(rs == middle);

	 freeseg(rs);

	 if (debug)
	    VG_(printf)("  case 4: subrange %p-%p deleted\n",
			addr, addr+len);
      }
   }
}