Esempio n. 1
0
// Do a three step traversal: by file, then fn, then line.
// In all cases prepends new nodes to their chain.  Returns a pointer to the
// line node, creates a new one if necessary.
static lineCC* get_lineCC(Addr origAddr)
{
   fileCC *curr_fileCC;
   fnCC   *curr_fnCC;
   lineCC *curr_lineCC;
   Char    file[FILE_LEN], fn[FN_LEN];
   Int     line;
   UInt    file_hash, fn_hash, line_hash;

   get_debug_info(origAddr, file, fn, &line);

   VGP_PUSHCC(VgpGetLineCC);

   // level 1
   file_hash = hash(file, N_FILE_ENTRIES);
   curr_fileCC   = CC_table[file_hash];
   while (NULL != curr_fileCC && !VG_STREQ(file, curr_fileCC->file)) {
      curr_fileCC = curr_fileCC->next;
   }
   if (NULL == curr_fileCC) {
      CC_table[file_hash] = curr_fileCC = 
         new_fileCC(file, CC_table[file_hash]);
      distinct_files++;
   }

   // level 2
   fn_hash = hash(fn, N_FN_ENTRIES);
   curr_fnCC   = curr_fileCC->fns[fn_hash];
   while (NULL != curr_fnCC && !VG_STREQ(fn, curr_fnCC->fn)) {
      curr_fnCC = curr_fnCC->next;
   }
   if (NULL == curr_fnCC) {
      curr_fileCC->fns[fn_hash] = curr_fnCC = 
         new_fnCC(fn, curr_fileCC->fns[fn_hash]);
      distinct_fns++;
   }

   // level 3
   line_hash   = line % N_LINE_ENTRIES;
   curr_lineCC = curr_fnCC->lines[line_hash];
   while (NULL != curr_lineCC && line != curr_lineCC->line) {
      curr_lineCC = curr_lineCC->next;
   }
   if (NULL == curr_lineCC) {
      curr_fnCC->lines[line_hash] = curr_lineCC = 
         new_lineCC(line, curr_fnCC->lines[line_hash]);
      distinct_lines++;
   }

   VGP_POPCC(VgpGetLineCC);
   return curr_lineCC;
}
Esempio n. 2
0
Bool SK_(error_matches_suppression)(Error* err, Supp* su)
{
   Int        su_size;
   MAC_Error* err_extra = VG_(get_error_extra)(err);
   ErrorKind  ekind     = VG_(get_error_kind )(err);

   switch (VG_(get_supp_kind)(su)) {
      case ParamSupp:
         return (ekind == ParamErr 
              && VG_STREQ(VG_(get_error_string)(err), 
                          VG_(get_supp_string)(su)));

      case CoreMemSupp:
         return (ekind == CoreMemErr
              && VG_STREQ(VG_(get_error_string)(err),
                          VG_(get_supp_string)(su)));

      case Value0Supp: su_size = 0; goto value_case;
      case Value1Supp: su_size = 1; goto value_case;
      case Value2Supp: su_size = 2; goto value_case;
      case Value4Supp: su_size = 4; goto value_case;
      case Value8Supp: su_size = 8; goto value_case;
      case Value16Supp:su_size =16; goto value_case;
      value_case:
         return (ekind == ValueErr && err_extra->size == su_size);

      case Addr1Supp: su_size = 1; goto addr_case;
      case Addr2Supp: su_size = 2; goto addr_case;
      case Addr4Supp: su_size = 4; goto addr_case;
      case Addr8Supp: su_size = 8; goto addr_case;
      case Addr16Supp:su_size =16; goto addr_case;
      addr_case:
         return (ekind == AddrErr && err_extra->size == su_size);

      case FreeSupp:
         return (ekind == FreeErr || ekind == FreeMismatchErr);

      case OverlapSupp:
         return (ekind = OverlapErr);

      case LeakSupp:
         return (ekind == LeakErr);

      default:
         VG_(printf)("Error:\n"
                     "  unknown suppression type %d\n",
                     VG_(get_supp_kind)(su));
         VG_(skin_panic)("unknown suppression type in "
                         "SK_(error_matches_suppression)");
   }
}
Esempio n. 3
0
Bool pc_is_recognised_suppression ( Char* name, Supp *su )
{
   SuppKind skind;

   if      (VG_STREQ(name, "SorG"))     skind = XS_SorG;
   else if (VG_STREQ(name, "Heap"))     skind = XS_Heap;
   else if (VG_STREQ(name, "Arith"))    skind = XS_Arith;
   else if (VG_STREQ(name, "SysParam")) skind = XS_SysParam;
   else
      return False;

   VG_(set_supp_kind)(su, skind);
   return True;
}
Esempio n. 4
0
static Bool match_executable(const HChar *entry) 
{
   HChar buf[VG_(strlen)(entry) + VG_(strlen)(executable_name_in) + 3];

   /* empty PATH element means '.' */
   if (*entry == '\0')
      entry = ".";

   VG_(snprintf)(buf, sizeof(buf), "%s/%s", entry, executable_name_in);

   // Don't match directories
   if (VG_(is_dir)(buf))
      return False;

   // If we match an executable, we choose that immediately.  If we find a
   // matching non-executable we remember it but keep looking for an
   // matching executable later in the path.
   if (VG_(access)(buf, True/*r*/, False/*w*/, True/*x*/) == 0) {
      VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 );
      executable_name_out[VKI_PATH_MAX-1] = 0;
      return True;      // Stop looking
   } else if (VG_(access)(buf, True/*r*/, False/*w*/, False/*x*/) == 0 
           && VG_STREQ(executable_name_out, "")) 
   {
      VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 );
      executable_name_out[VKI_PATH_MAX-1] = 0;
      return False;     // Keep looking
   } else { 
      return False;     // Keep looking
   }
}
Esempio n. 5
0
void VG_(assert_fail) ( Bool isCore, const HChar* expr, const HChar* file, 
                        Int line, const HChar* fn, const HChar* format, ... )
{
   va_list vargs;
   HChar buf[512];
   const HChar* component;
   const HChar* bugs_to;
   UInt written;

   static Bool entered = False;
   if (entered) 
      VG_(exit)(2);
   entered = True;

   va_start(vargs, format);
   written = VG_(vsnprintf) ( buf, sizeof(buf), format, vargs );
   va_end(vargs);

   if (written >= sizeof(buf)) {
      VG_(printf)("\nvalgrind: %s: buf is too small, sizeof(buf) = %u, "
                  "written = %d\n", __func__, (unsigned)sizeof(buf), written);
   }

   if (isCore) {
      component = "valgrind";
      bugs_to   = VG_BUGS_TO;
   } else { 
      component = VG_(details).name;
      bugs_to   = VG_(details).bug_reports_to;
   }

   if (VG_(clo_xml))
      VG_(printf_xml)("</valgrindoutput>\n");

   // Treat vg_assert2(0, "foo") specially, as a panicky abort
   if (VG_STREQ(expr, "0")) {
      VG_(printf)("\n%s: %s:%d (%s): the 'impossible' happened.\n",
                  component, file, line, fn );
   } else {
      VG_(printf)("\n%s: %s:%d (%s): Assertion '%s' failed.\n",
                  component, file, line, fn, expr );
   }
   if (!VG_STREQ(buf, ""))
      VG_(printf)("%s: %s\n", component, buf );

   report_and_quit(bugs_to, NULL);
}
Esempio n. 6
0
static void gen_suppression(Error* err)
{
   Int         i;
   static UChar buf[M_VG_ERRTXT];
   Bool        main_done = False;
   ExeContext* ec      = VG_(get_error_where)(err);
   Int         stop_at = VG_(clo_backtrace_size);

   /* At most VG_N_SUPP_CALLERS names */
   if (stop_at > VG_N_SUPP_CALLERS) stop_at = VG_N_SUPP_CALLERS;
   vg_assert(stop_at > 0);

   VG_(printf)("{\n");
   VG_(printf)("   <insert a suppression name here>\n");

   if (PThreadErr == err->ekind) {
      VG_(printf)("   core:PThread\n");

   } else {
      Char* name = SK_(get_error_name)(err);
      if (NULL == name) {
         VG_(message)(Vg_UserMsg, 
                      "(tool does not allow error to be suppressed)");
         return;
      }
      VG_(printf)("   %s:%s\n", VG_(details).name, name);
      SK_(print_extra_suppression_info)(err);
   }

   /* This loop condensed from VG_(mini_stack_dump)() */
   i = 0;
   do {
      Addr eip = ec->eips[i];
      if (i > 0) eip--;                 /* point to calling line */
      if ( VG_(get_fnname_nodemangle) (eip, buf,  M_VG_ERRTXT) ) {
         // Stop after "main";  if main() is recursive, stop after last main().

         if ( ! VG_(clo_show_below_main)) {
            if (VG_STREQ(buf, "main"))
               main_done = True;
            else if (main_done)
               break;
         }
         VG_(printf)("   fun:%s\n", buf);
      } else if ( VG_(get_objname)(eip, buf, M_VG_ERRTXT) ) {
         VG_(printf)("   obj:%s\n", buf);
      } else {
         VG_(printf)("   ???:???       "
                     "# unknown, suppression will not work, sorry\n");
      }
      i++;
   } while (i < stop_at && ec->eips[i] != 0);

   VG_(printf)("}\n");
}
Esempio n. 7
0
Bool MAC_(shared_recognised_suppression) ( Char* name, Supp* su )
{
   SuppKind skind;

   if      (VG_STREQ(name, "Param"))   skind = ParamSupp;
   else if (VG_STREQ(name, "CoreMem")) skind = CoreMemSupp;
   else if (VG_STREQ(name, "Addr1"))   skind = Addr1Supp;
   else if (VG_STREQ(name, "Addr2"))   skind = Addr2Supp;
   else if (VG_STREQ(name, "Addr4"))   skind = Addr4Supp;
   else if (VG_STREQ(name, "Addr8"))   skind = Addr8Supp;
   else if (VG_STREQ(name, "Addr16"))  skind = Addr16Supp;
   else if (VG_STREQ(name, "Free"))    skind = FreeSupp;
   else if (VG_STREQ(name, "Leak"))    skind = LeakSupp;
   else if (VG_STREQ(name, "Overlap")) skind = OverlapSupp;
   else
      return False;

   VG_(set_supp_kind)(su, skind);
   return True;
}
void VG_(assert_fail) ( Bool isCore, const Char* expr, const Char* file, 
                        Int line, const Char* fn, const HChar* format, ... )
{
   va_list vargs;
   Char buf[256];
   Char* component;
   Char* bugs_to;

   static Bool entered = False;
   if (entered) 
     VG_(exit)(2);
   entered = True;

   va_start(vargs, format);
   VG_(vsprintf) ( buf, format, vargs );
   va_end(vargs);

   if (isCore) {
      component = "valgrind";
      bugs_to   = VG_BUGS_TO;
   } else { 
      component = VG_(details).name;
      bugs_to   = VG_(details).bug_reports_to;
   }

   if (VG_(clo_xml))
      VG_(message)(Vg_UserMsg, "</valgrindoutput>\n");

   // Treat vg_assert2(0, "foo") specially, as a panicky abort
   if (VG_STREQ(expr, "0")) {
      VG_(printf)("\n%s: %s:%d (%s): the 'impossible' happened.\n",
                  component, file, line, fn, expr );
   } else {
      VG_(printf)("\n%s: %s:%d (%s): Assertion '%s' failed.\n",
                  component, file, line, fn, expr );
   }
   if (!VG_STREQ(buf, ""))
      VG_(printf)("%s: %s\n", component, buf );

   report_and_quit(bugs_to, 0,0,0,0);
}
Esempio n. 9
0
static Bool is_hash_bang_file(Char* f)
{
   SysRes res = VG_(open)(f, VKI_O_RDONLY, 0);
   if (!sr_isError(res)) {
      Char buf[3] = {0,0,0};
      Int fd = sr_Res(res);
      Int n  = VG_(read)(fd, buf, 2); 
      if (n == 2 && VG_STREQ("#!", buf))
         return True;
   }
   return False;
}
Esempio n. 10
0
void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
                            StackTrace ips, UInt n_ips )
{
   #define MYBUF_LEN 50  // only needs to be long enough for 
                         // the names specially tested for

   Bool main_done = False;
   Char mybuf[MYBUF_LEN];     // ok to stack allocate mybuf[] -- it's tiny
   Int i = 0;

   vg_assert(n_ips > 0);
   do {
      Addr ip = ips[i];
      if (i > 0) 
         ip -= VG_MIN_INSTR_SZB;   // point to calling line

      // Stop after the first appearance of "main" or one of the other names
      // (the appearance of which is a pretty good sign that we've gone past
      // main without seeing it, for whatever reason)
      if ( ! VG_(clo_show_below_main)) {
         VG_(get_fnname_nodemangle)( ip, mybuf, MYBUF_LEN );
         mybuf[MYBUF_LEN-1] = 0; // paranoia
         if ( VG_STREQ("main", mybuf)
#             if defined(VGO_linux)
              || VG_STREQ("__libc_start_main", mybuf)   // glibc glibness
              || VG_STREQ("generic_start_main", mybuf)  // Yellow Dog doggedness
#             endif
            )
            main_done = True;
      }

      // Act on the ip
      action(i, ip);

      i++;
   } while (i < n_ips && ips[i] != 0 && !main_done);

   #undef MYBUF_LEN
}
Esempio n. 11
0
void VG_(assert_fail) ( Bool isCore, const HChar* expr, const HChar* file, 
                        Int line, const HChar* fn, const HChar* format, ... )
{
   va_list vargs, vargs_copy;
   const HChar* component;
   const HChar* bugs_to;
   UInt written;

   static Bool entered = False;
   if (entered) 
      VG_(exit)(2);
   entered = True;

   if (isCore) {
      component = "valgrind";
      bugs_to   = VG_BUGS_TO;
   } else { 
      component = VG_(details).name;
      bugs_to   = VG_(details).bug_reports_to;
   }

   if (VG_(clo_xml))
      VG_(printf_xml)("</valgrindoutput>\n");

   // Treat vg_assert2(0, "foo") specially, as a panicky abort
   if (VG_STREQ(expr, "0")) {
      VG_(printf)("\n%s: %s:%d (%s): the 'impossible' happened.\n",
                  component, file, line, fn );
   } else {
      VG_(printf)("\n%s: %s:%d (%s): Assertion '%s' failed.\n",
                  component, file, line, fn, expr );
   }

   /* Check whether anything will be written */
   HChar buf[5];
   va_start(vargs, format);
   va_copy(vargs_copy, vargs);
   written = VG_(vsnprintf) ( buf, sizeof(buf), format, vargs );
   va_end(vargs);

   if (written > 0) {
      VG_(printf)("%s: ", component);
      VG_(vprintf)(format, vargs_copy);
      VG_(printf)("\n");
   }

   report_and_quit(bugs_to, NULL);
}
Esempio n. 12
0
// Returns NULL if it wasn't found.
const HChar* ML_(find_executable) ( const HChar* exec )
{
   vg_assert(NULL != exec);
   if (VG_(strchr)(exec, '/')) {
      // Has a '/' - use the name as is
      VG_(strncpy)( executable_name_out, exec, VKI_PATH_MAX-1 );
   } else {
      // No '/' - we need to search the path
      HChar* path;
      VG_(strncpy)( executable_name_in,  exec, VKI_PATH_MAX-1 );
      VG_(memset) ( executable_name_out, 0,    VKI_PATH_MAX );
      path = VG_(getenv)("PATH");
      scan_colsep(path, match_executable);
   }
   return VG_STREQ(executable_name_out, "") ? NULL : executable_name_out;
}
Esempio n. 13
0
/* Read suppressions from the file specified in VG_(clo_suppressions)
   and place them in the suppressions list.  If there's any difficulty
   doing this, just give up -- there's no point in trying to recover.  
*/
static void load_one_suppressions_file ( Char* filename )
{
#  define N_BUF 200
   SysRes sres;
   Int    fd, i;
   Bool   eof;
   Char   buf[N_BUF+1];
   Char*  tool_names;
   Char*  supp_name;
   Char*  err_str = NULL;
   SuppLoc tmp_callers[VG_MAX_SUPP_CALLERS];

   fd   = -1;
   sres = VG_(open)( filename, VKI_O_RDONLY, 0 );
   if (sres.isError) {
      if (VG_(clo_xml))
         VG_(message)(Vg_UserMsg, "</valgrindoutput>\n");
      VG_(message)(Vg_UserMsg, "FATAL: can't open suppressions file '%s'", 
                   filename );
      VG_(exit)(1);
   }
   fd = sres.res;

#  define BOMB(S)  { err_str = S;  goto syntax_error; }

   while (True) {
      /* Assign and initialise the two suppression halves (core and tool) */
      Supp* supp;
      supp        = VG_(arena_malloc)(VG_AR_CORE, sizeof(Supp));
      supp->count = 0;

      // Initialise temporary reading-in buffer.
      for (i = 0; i < VG_MAX_SUPP_CALLERS; i++) {
         tmp_callers[i].ty   = NoName;
         tmp_callers[i].name = NULL;
      }

      supp->string = supp->extra = NULL;

      eof = VG_(get_line) ( fd, buf, N_BUF );
      if (eof) break;

      if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
      
      eof = VG_(get_line) ( fd, buf, N_BUF );

      if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");

      supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf);

      eof = VG_(get_line) ( fd, buf, N_BUF );

      if (eof) BOMB("unexpected end-of-file");

      /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
      i = 0;
      while (True) {
         if (buf[i] == ':')  break;
         if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line");
         i++;
      }
      buf[i]    = '\0';    /* Replace ':', splitting into two strings */

      tool_names = & buf[0];
      supp_name  = & buf[i+1];

      if (VG_(needs).core_errors && tool_name_present("core", tool_names))
      {
         // A core suppression
         //(example code, see comment on CoreSuppKind above)
         //if (VG_STREQ(supp_name, "Thread"))
         //   supp->skind = ThreadSupp;
         //else
            BOMB("unknown core suppression type");
      }
      else if (VG_(needs).tool_errors && 
               tool_name_present(VG_(details).name, tool_names))
      {
         // A tool suppression
         if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) {
            /* Do nothing, function fills in supp->skind */
         } else {
            BOMB("unknown tool suppression type");
         }
      }
      else {
         // Ignore rest of suppression
         while (True) {
            eof = VG_(get_line) ( fd, buf, N_BUF );
            if (eof) BOMB("unexpected end-of-file");
            if (VG_STREQ(buf, "}"))
               break;
         }
         continue;
      }

      if (VG_(needs).tool_errors && 
          !VG_TDICT_CALL(tool_read_extra_suppression_info, fd, buf, N_BUF, supp))
      {
         BOMB("bad or missing extra suppression info");
      }

      i = 0;
      while (True) {
         eof = VG_(get_line) ( fd, buf, N_BUF );
         if (eof)
            BOMB("unexpected end-of-file");
         if (VG_STREQ(buf, "}")) {
            if (i > 0) {
               break;
            } else {
               BOMB("missing stack trace");
            }
         }
         if (i == VG_MAX_SUPP_CALLERS)
            BOMB("too many callers in stack trace");
         if (i > 0 && i >= VG_(clo_backtrace_size)) 
            break;
         tmp_callers[i].name = VG_(arena_strdup)(VG_AR_CORE, buf);
         if (!setLocationTy(&(tmp_callers[i])))
            BOMB("location should start with 'fun:' or 'obj:'");
         i++;
      }

      // If the num callers is >= VG_(clo_backtrace_size), ignore any extra
      // lines and grab the '}'.
      if (!VG_STREQ(buf, "}")) {
         do {
            eof = VG_(get_line) ( fd, buf, N_BUF );
         } while (!eof && !VG_STREQ(buf, "}"));
      }

      // Copy tmp_callers[] into supp->callers[]
      supp->n_callers = i;
      supp->callers = VG_(arena_malloc)(VG_AR_CORE, i*sizeof(SuppLoc));
      for (i = 0; i < supp->n_callers; i++) {
         supp->callers[i] = tmp_callers[i];
      }

      supp->next = suppressions;
      suppressions = supp;
   }
   VG_(close)(fd);
   return;

  syntax_error:
   if (VG_(clo_xml))
      VG_(message)(Vg_UserMsg, "</valgrindoutput>\n");
   VG_(message)(Vg_UserMsg, 
                "FATAL: in suppressions file '%s': %s", filename, err_str );
   
   VG_(close)(fd);
   VG_(message)(Vg_UserMsg, "exiting now.");
   VG_(exit)(1);

#  undef BOMB
#  undef N_BUF   
}
Esempio n. 14
0
void VG_(split_up_argv)( Int argc, HChar** argv )
{
          Int  i;
          Bool augment = True;
   static Bool already_called = False;

   XArrayStrings tmp_xarray = {0,0,NULL};

   /* This function should be called once, at startup, and then never
      again. */
   vg_assert(!already_called);
   already_called = True;

   /* Collect up the args-for-V. */
   i = 1; /* skip the exe (stage2) name. */
   for (; i < argc; i++) {
      vg_assert(argv[i]);
      if (0 == VG_(strcmp)(argv[i], "--")) {
         i++;
         break;
      }
      if (0 == VG_(strcmp)(argv[i], "--command-line-only=yes"))
         augment = False;
      if (argv[i][0] != '-')
	break;
      add_string( &tmp_xarray, argv[i] );
   }

   /* Should now be looking at the exe name. */
   if (i < argc) {
      vg_assert(argv[i]);
      VG_(args_the_exename) = argv[i];
      i++;
   }

   /* The rest are args for the client. */
   for (; i < argc; i++) {
      vg_assert(argv[i]);
      add_string( &VG_(args_for_client), argv[i] );
   }

   VG_(args_for_valgrind).size = 0;
   VG_(args_for_valgrind).used = 0;
   VG_(args_for_valgrind).strs = NULL;

   /* Get extra args from ~/.valgrindrc, $VALGRIND_OPTS and
      ./.valgrindrc into VG_(args_for_valgrind). */
   if (augment) {
      // read_dot_valgrindrc() allocates the return value with
      // VG_(malloc)().  We do not free f1_clo and f2_clo as they get
      // put into VG_(args_for_valgrind) and so must persist.
      HChar* home    = VG_(getenv)("HOME");
      HChar* f1_clo  = home ? read_dot_valgrindrc( home ) : NULL;
      HChar* env_clo = VG_(strdup)( VG_(getenv)(VALGRIND_OPTS) );
      HChar* f2_clo  = NULL;

      // Don't read ./.valgrindrc if "." is the same as "$HOME", else its
      // contents will be applied twice. (bug #142488)
      if (home) {
         HChar cwd[VKI_PATH_MAX+1];
         Bool  cwd_ok = VG_(getcwd)(cwd, VKI_PATH_MAX);
         f2_clo = ( (cwd_ok && VG_STREQ(home, cwd))
                       ? NULL : read_dot_valgrindrc(".") );
      }

      if (f1_clo)  add_args_from_string( f1_clo );
      if (env_clo) add_args_from_string( env_clo );
      if (f2_clo)  add_args_from_string( f2_clo );
   }

   /* .. and record how many extras we got. */
   VG_(args_for_valgrind_noexecpass) = VG_(args_for_valgrind).used;

   /* Finally, copy tmp_xarray onto the end. */
   for (i = 0; i < tmp_xarray.used; i++)
      add_string( &VG_(args_for_valgrind), tmp_xarray.strs[i] );

   if (tmp_xarray.strs)
      VG_(free)(tmp_xarray.strs);
}
Esempio n. 15
0
void test_VG_STREQ(void)
{
   CHECK( ! VG_STREQ(NULL,    NULL) );  
   CHECK( ! VG_STREQ(NULL,    "ab") );  
   CHECK( ! VG_STREQ("ab",    NULL) );  
   CHECK( ! VG_STREQ("",      "a")  );
   CHECK( ! VG_STREQ("a",     "")   );
   CHECK( ! VG_STREQ("abc",   "abcd"));
   CHECK( ! VG_STREQ("abcd",  "abc") );
   CHECK( ! VG_STREQ("Abcd",  "abcd"));
   CHECK( ! VG_STREQ("abcd",  "Abcd"));

   CHECK( VG_STREQ("",     "") );
   CHECK( VG_STREQ("a",    "a") );
   CHECK( VG_STREQ("abcd", "abcd") );
}
Esempio n. 16
0
// Prints a .disambig file entry for a given variable
// This consists of 2 lines:
//   variable name, disambig type
// e.g.,
// /foo       <-- variable name
// S          <-- disambig type
static TraversalResult
printDisambigAction(VariableEntry* var,
		    char* varName,
		    VariableOrigin varOrigin,
		    UInt numDereferences,
		    UInt layersBeforeBase,
		    Bool overrideIsInit,
		    DisambigOverride disambigOverride,
		    Bool isSequence,
		    Addr pValue,
		    Addr pValueGuest,
		    Addr* pValueArray,
		    Addr* pValueArrayGuest,
		    UInt numElts,
		    FunctionEntry* varFuncInfo,
		    Bool isEnter) {
  /* silence unused variable warnings */
  (void)varOrigin; (void)numDereferences; (void)layersBeforeBase;
  (void)overrideIsInit; (void)disambigOverride; (void)isSequence;
  (void)pValue; (void)pValueArray; (void)numElts; (void)varFuncInfo;
  (void)isEnter; (void)pValueGuest; (void)pValueArrayGuest;


  // If this is not a variable that's worthy of being outputted to the
  // .disambig file, then punt:
  if (!shouldOutputVarToDisambig(var)) {
    // We do not want to traverse any further than the surface level
    // for .disambig:
    return STOP_TRAVERSAL;
  }

  // Line 1: Variable name
  fputs(varName, disambig_fp);
  fputs("\n", disambig_fp);

  // Line 2: Disambig type

  /* Default values:
     Base type "char" and "unsigned char": 'I' for integer
     Pointer to "char": 'S' for string
     Pointer to all other types:
       - 'A' for array if var->disambigMultipleElts,
             which means that we've observed array
             behavior during program's execution
         or if !var->pointerHasEverBeenObserved,
            which means that the pointer has never
            been observed so a conservative guess
            of 'A' should be the default
         or if var->isStructUnionMember - don't try
            to be smart about member variables
            within structs/unions - just default to "A"
       - 'P' for pointer if (var->pointerHasEverBeenObserved &&
             !var->disambigMultipleElts)
  */

  if (0 == var->ptrLevels) {
    if ((D_CHAR == var->varType->decType) ||
        (D_UNSIGNED_CHAR == var->varType->decType)) {
      fputs("I", disambig_fp);
    }
  }
  // Special case for C++ 'this' parameter - always make it 'P'
  else if (VG_STREQ(var->name, "this")) {
    fputs("P", disambig_fp);
  }
  // Normal string, not pointer to string
  else if (IS_STRING(var) &&
           (1 == var->ptrLevels)) {
    fputs("S", disambig_fp);
  }
  else if (var->ptrLevels > 0) {
    if (IS_MEMBER_VAR(var)) {
      fputs("A", disambig_fp);
    }
    else {
      if (var->pointerHasEverBeenObserved) {
        if (var->disambigMultipleElts) {
          fputs("A", disambig_fp);
        }
        else {
          fputs("P", disambig_fp);
        }
      }
      // default behavior for variable that was
      // never observed during the execution
      else {
        fputs("A", disambig_fp);
      }
    }
  }

  fputs("\n", disambig_fp);

  // We do not want to traverse any further than the surface level for
  // .disambig:
  return STOP_TRAVERSAL;
}
/* This is an example of a variables output format:

----SECTION----
globals
StaticArraysTest_c/staticStrings
StaticArraysTest_c/staticStrings[]
StaticArraysTest_c/staticShorts
StaticArraysTest_c/staticShorts[]

----SECTION----
..f()
arg
strings
strings[]
return


----SECTION----
..b()
oneShort
manyShorts
manyShorts[]
return

----SECTION----
..main()
return

*/
void initializeVarsTree()
{
  char nextLineIsFunction = 0;
  FunctionTree* currentFunctionTree = 0;
  while (fgets(input_line, 200, trace_vars_input_fp))
    {
      int lineLen = VG_(strlen)(input_line);

      // Skip blank lines (those consisting of solely the newline character)
      // Also skip comment lines (those beginning with COMMENT_CHAR)
      if(('\n' == input_line[0]) ||
         (COMMENT_CHAR == input_line[0])) {
        //        VG_(printf)("skipping blank line ...\n");
        continue;
      }

      // Strip '\n' off the end of the line
      // NOTE: Only do this if the end of the line is a newline character.
      // If the very last line of a file is not followed by a newline character,
      // then blindly stripping off the last character will truncate the actual
      // string, which is undesirable.
      if (input_line[lineLen - 1] == '\n') {
        input_line[lineLen - 1] = '\0';
      }

      if (VG_STREQ(input_line, ENTRY_DELIMETER))
	{
	  nextLineIsFunction = 1;
	}
      else
	{
	  // Create a new FunctionTree and insert it into vars_tree
	  if (nextLineIsFunction)
	    {
	      currentFunctionTree = VG_(malloc)("fjalar_selec.c: initVT", sizeof(*currentFunctionTree));
	      currentFunctionTree->function_fjalar_name = VG_(strdup)("fjalar_selec.c: initVT.2", input_line);
	      currentFunctionTree->function_variables_tree = NULL; // Remember to initialize to null!

	      tsearch((void*)currentFunctionTree, (void**)&vars_tree, compareFunctionTrees);

	      // Keep a special pointer for global variables to trace
              if (VG_STREQ(input_line, GLOBAL_STRING))
		{
		  globalFunctionTree = currentFunctionTree;
                  //                  VG_(printf)("globalFunctionTree: %p\n", globalFunctionTree);
		}
              else {
                //                VG_(printf)("Function: %s\n", currentFunctionTree->function_fjalar_name);
              }
	    }
	  // Otherwise, create a new variable and stuff it into
	  // the function_variables_tree of the current function_tree
	  else
	    {
	      char* newString = VG_(strdup)("fjalar_selec.c: initVT.3", input_line);
	      tsearch((void*)newString, (void**)&(currentFunctionTree->function_variables_tree), compareStrings);
              //              VG_(printf)("variable: %s\n", newString);
	    }

	  nextLineIsFunction = 0;
	}
    }

  fclose(trace_vars_input_fp);
  trace_vars_input_fp = 0;
}
Esempio n. 18
0
/* Read suppressions from the file specified in vg_clo_suppressions
   and place them in the suppressions list.  If there's any difficulty
   doing this, just give up -- there's no point in trying to recover.  
*/
static void load_one_suppressions_file ( Char* filename )
{
#  define N_BUF 200
   Int   fd, i;
   Bool  eof, too_many_contexts = False;
   Char  buf[N_BUF+1];
   Char* tool_names;
   Char* supp_name;

   fd = VG_(open)( filename, VKI_O_RDONLY, 0 );
   if (fd < 0) {
      VG_(message)(Vg_UserMsg, "FATAL: can't open suppressions file `%s'", 
                   filename );
      VG_(exit)(1);
   }

   while (True) {
      /* Assign and initialise the two suppression halves (core and tool) */
      Supp* supp;
      supp        = VG_(arena_malloc)(VG_AR_CORE, sizeof(Supp));
      supp->count = 0;
      for (i = 0; i < VG_N_SUPP_CALLERS; i++) supp->caller[i] = NULL;
      supp->string = supp->extra = NULL;

      eof = VG_(get_line) ( fd, buf, N_BUF );
      if (eof) break;

      if (!VG_STREQ(buf, "{")) goto syntax_error;
      
      eof = VG_(get_line) ( fd, buf, N_BUF );
      if (eof || VG_STREQ(buf, "}")) goto syntax_error;
      supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf);

      eof = VG_(get_line) ( fd, buf, N_BUF );

      if (eof) goto syntax_error;

      /* Check it has the "skin1,skin2,...:supp" form (look for ':') */
      i = 0;
      while (True) {
         if (buf[i] == ':')  break;
         if (buf[i] == '\0') goto syntax_error;
         i++;
      }
      buf[i]    = '\0';    /* Replace ':', splitting into two strings */

      tool_names = & buf[0];
      supp_name  = & buf[i+1];

      /* Is it a core suppression? */
      if (VG_(needs).core_errors && tool_name_present("core", tool_names))
      {
         if (VG_STREQ(supp_name, "PThread"))
            supp->skind = PThreadSupp;
         else
            goto syntax_error;
      }

      /* Is it a tool suppression? */
      else if (VG_(needs).skin_errors && 
               tool_name_present(VG_(details).name, tool_names))
      {
         if (SK_(recognised_suppression)(supp_name, supp)) 
         {
            /* Do nothing, function fills in supp->skind */
         } else
            goto syntax_error;
      }

      else {
         /* Ignore rest of suppression */
         while (True) {
            eof = VG_(get_line) ( fd, buf, N_BUF );
            if (eof) goto syntax_error;
            if (VG_STREQ(buf, "}"))
               break;
         }
         continue;
      }

      if (VG_(needs).skin_errors && 
          !SK_(read_extra_suppression_info)(fd, buf, N_BUF, supp)) 
         goto syntax_error;

      /* "i > 0" ensures at least one caller read. */
      for (i = 0; i <= VG_N_SUPP_CALLERS; i++) {
         eof = VG_(get_line) ( fd, buf, N_BUF );
         if (eof) goto syntax_error;
         if (i > 0 && VG_STREQ(buf, "}")) 
            break;
         if (i == VG_N_SUPP_CALLERS)
            break;
         supp->caller[i] = VG_(arena_strdup)(VG_AR_CORE, buf);
         if (!setLocationTy(&(supp->caller[i]), &(supp->caller_ty[i])))
            goto syntax_error;
      }

      /* make sure to grab the '}' if the num callers is >=
         VG_N_SUPP_CALLERS */
      if (!VG_STREQ(buf, "}")) {
         // Don't just ignore extra lines -- abort.  (Someone complained
         // about silent ignoring of lines in bug #77922.)
         //do {
         //   eof = VG_(get_line) ( fd, buf, N_BUF );
         //} while (!eof && !VG_STREQ(buf, "}"));
         too_many_contexts = True;
         goto syntax_error;
      }

      supp->next = vg_suppressions;
      vg_suppressions = supp;
   }
   VG_(close)(fd);
   return;

  syntax_error:
   if (eof) {
      VG_(message)(Vg_UserMsg, 
                   "FATAL: in suppressions file `%s': unexpected EOF", 
                   filename );
   } else if (too_many_contexts) {
      VG_(message)(Vg_UserMsg, 
                   "FATAL: in suppressions file: `%s': at %s:", 
                   filename, buf );
      VG_(message)(Vg_UserMsg, 
                   "too many lines (limit of %d contexts in suppressions)",
                   VG_N_SUPP_CALLERS);
   } else {
      VG_(message)(Vg_UserMsg, 
                   "FATAL: in suppressions file: `%s': syntax error on: %s", 
                   filename, buf );
   }
   VG_(close)(fd);
   VG_(message)(Vg_UserMsg, "exiting now.");
   VG_(exit)(1);

#  undef N_BUF   
}
Esempio n. 19
0
void test_VG_STREQ(void)
{
   CHECK( ! VG_STREQ(NULL,    NULL) );  // Nb: strcmp() considers these equal
   CHECK( ! VG_STREQ(NULL,    "ab") );  // Nb: strcmp() seg faults on this
   CHECK( ! VG_STREQ("ab",    NULL) );  // Nb: strcmp() seg faults on this
   CHECK( ! VG_STREQ("",      "a")  );
   CHECK( ! VG_STREQ("a",     "")   );
   CHECK( ! VG_STREQ("abc",   "abcd"));
   CHECK( ! VG_STREQ("abcd",  "abc") );
   CHECK( ! VG_STREQ("Abcd",  "abcd"));
   CHECK( ! VG_STREQ("abcd",  "Abcd"));

   CHECK( VG_STREQ("",     "") );
   CHECK( VG_STREQ("a",    "a") );
   CHECK( VG_STREQ("abcd", "abcd") );
}
// Copies the string, prepending it with the startup working directory, and
// expanding %p and %q entries.  Returns a new, malloc'd string.
Char* VG_(expand_file_name)(Char* option_name, Char* format)
{
   static Char base_dir[VKI_PATH_MAX];
   Int len, i = 0, j = 0;
   Char* out;

   Bool ok = VG_(get_startup_wd)(base_dir, VKI_PATH_MAX);
   tl_assert(ok);

   if (VG_STREQ(format, "")) {
      // Empty name, bad.
      VG_(umsg)("%s: filename is empty", option_name);
      goto bad;
   }
   
   // If 'format' starts with a '~', abort -- the user probably expected the
   // shell to expand but it didn't (see bug 195268 for details).  This means
   // that we don't allow a legitimate filename beginning with '~' but that
   // seems very unlikely.
   if (format[0] == '~') {
      VG_(umsg)("%s: filename begins with '~'\n", option_name);
      VG_(umsg)("You probably expected the shell to expand the '~', but it\n");
      VG_(umsg)("didn't.  The rules for '~'-expansion "
                "vary from shell to shell.\n");
      VG_(umsg)("You might have more luck using $HOME instead.\n");
      goto bad;
   }

   // If 'format' starts with a '/', do not prefix with startup dir.
   if (format[0] != '/') {
      j += VG_(strlen)(base_dir);
   }

   // The 10 is slop, it should be enough in most cases.
   len = j + VG_(strlen)(format) + 10;
   out = VG_(malloc)( "options.efn.1", len );
   if (format[0] != '/') {
      VG_(strcpy)(out, base_dir);
      out[j++] = '/';
   }

#define ENSURE_THIS_MUCH_SPACE(x) \
   if (j + x >= len) { \
      len += (10 + x); \
      out = VG_(realloc)("options.efn.2(multiple)", out, len); \
   }

   while (format[i]) {
      if (format[i] != '%') {
         ENSURE_THIS_MUCH_SPACE(1);
         out[j++] = format[i++];
         
      } else {
         // We saw a '%'.  What's next...
         i++;
         if      ('%' == format[i]) {
            // Replace '%%' with '%'.
            ENSURE_THIS_MUCH_SPACE(1);
            out[j++] = format[i++];
         }
         else if ('p' == format[i]) {
            // Print the PID.  Assume that it's not longer than 10 chars --
            // reasonable since 'pid' is an Int (ie. 32 bits).
            Int pid = VG_(getpid)();
            ENSURE_THIS_MUCH_SPACE(10);
            j += VG_(sprintf)(&out[j], "%d", pid);
            i++;
         } 
         else if ('q' == format[i]) {
            i++;
            if ('{' == format[i]) {
               // Get the env var name, print its contents.
               Char* qualname;
               Char* qual;
               i++;
               qualname = &format[i];
               while (True) {
                  if (0 == format[i]) {
                     VG_(message)(Vg_UserMsg, "%s: malformed %%q specifier\n",
                        option_name);
                     goto bad;
                  } else if ('}' == format[i]) {
                     // Temporarily replace the '}' with NUL to extract var
                     // name.
                     format[i] = 0;
                     qual = VG_(getenv)(qualname);
                     if (NULL == qual) {
                        VG_(message)(Vg_UserMsg,
                           "%s: environment variable %s is not set\n",
                           option_name, qualname);
                        format[i] = '}';  // Put the '}' back.
                        goto bad;
                     }
                     format[i] = '}';     // Put the '}' back.
                     i++;
                     break;
                  }
                  i++;
               }
               ENSURE_THIS_MUCH_SPACE(VG_(strlen)(qual));
               j += VG_(sprintf)(&out[j], "%s", qual);
            } else {
               VG_(message)(Vg_UserMsg,
                  "%s: expected '{' after '%%q'\n", option_name);
               goto bad;
            }
         } 
         else {
            // Something else, abort.
            VG_(message)(Vg_UserMsg,
               "%s: expected 'p' or 'q' or '%%' after '%%'\n", option_name);
            goto bad;
         }
      }
   }
   ENSURE_THIS_MUCH_SPACE(1);
   out[j++] = 0;

   return out;

  bad: {
   Char* opt =    // 2:  1 for the '=', 1 for the NUL.
      VG_(malloc)( "options.efn.3",
                   VG_(strlen)(option_name) + VG_(strlen)(format) + 2 );
   VG_(strcpy)(opt, option_name);
   VG_(strcat)(opt, "=");
   VG_(strcat)(opt, format);
   VG_(err_bad_option)(opt);
  }
}
Esempio n. 21
0
// Copies the string, prepending it with the startup working directory, and
// expanding %p and %q entries.  Returns a new, malloc'd string.
HChar* VG_(expand_file_name)(const HChar* option_name, const HChar* format)
{
   const HChar *base_dir;
   Int len, i = 0, j = 0;
   HChar* out;
   const HChar *message = NULL;

   base_dir = VG_(get_startup_wd)();

   if (VG_STREQ(format, "")) {
      // Empty name, bad.
      message = "No filename given\n";
      goto bad;
   }
   
   // If 'format' starts with a '~', abort -- the user probably expected the
   // shell to expand but it didn't (see bug 195268 for details).  This means
   // that we don't allow a legitimate filename beginning with '~' but that
   // seems very unlikely.
   if (format[0] == '~') {
      message = 
         "Filename begins with '~'\n"
         "You probably expected the shell to expand the '~', but it\n"
         "didn't.  The rules for '~'-expansion vary from shell to shell.\n"
         "You might have more luck using $HOME instead.\n";
      goto bad;
   }

   len = VG_(strlen)(format) + 1;
   out = VG_(malloc)( "options.efn.1", len );

#define ENSURE_THIS_MUCH_SPACE(x) \
   if (j + x >= len) { \
      len += (10 + x); \
      out = VG_(realloc)("options.efn.2(multiple)", out, len); \
   }

   while (format[i]) {
      if (format[i] != '%') {
         ENSURE_THIS_MUCH_SPACE(1);
         out[j++] = format[i++];
         
      } else {
         // We saw a '%'.  What's next...
         i++;
         if      ('%' == format[i]) {
            // Replace '%%' with '%'.
            ENSURE_THIS_MUCH_SPACE(1);
            out[j++] = format[i++];
         }
         else if ('p' == format[i]) {
            // Print the PID.  Assume that it's not longer than 10 chars --
            // reasonable since 'pid' is an Int (ie. 32 bits).
            Int pid = VG_(getpid)();
            ENSURE_THIS_MUCH_SPACE(10);
            j += VG_(sprintf)(&out[j], "%d", pid);
            i++;
         } 
         else if ('n' == format[i]) {
            // Print a seq nr.
            static Int last_pid;
            static Int seq_nr;
            Int pid = VG_(getpid)();
            if (last_pid != pid)
               seq_nr = 0;
            last_pid = pid;
            seq_nr++;
            ENSURE_THIS_MUCH_SPACE(10);
            j += VG_(sprintf)(&out[j], "%d", seq_nr);
            i++;
         } 
         else if ('q' == format[i]) {
            i++;
            if ('{' == format[i]) {
               // Get the env var name, print its contents.
               HChar *qual;
               Int begin_qualname = ++i;
               while (True) {
                  if (0 == format[i]) {
                     message = "Missing '}' in %q specifier\n";
                     goto bad;
                  } else if ('}' == format[i]) {
                     Int qualname_len = i - begin_qualname;
                     HChar qualname[qualname_len + 1];
                     VG_(strncpy)(qualname, format + begin_qualname,
                                  qualname_len);
                     qualname[qualname_len] = '\0';
                     qual = VG_(getenv)(qualname);
                     if (NULL == qual) {
                        // This memory will leak, But we don't care because
                        // VG_(fmsg_bad_option) will terminate the process.
                        HChar *str = VG_(malloc)("options.efn.3",
                                                 100 + qualname_len);
                        VG_(sprintf)(str,
                                     "Environment variable '%s' is not set\n",
                                     qualname);
                        message = str;
                        goto bad;
                     }
                     i++;
                     break;
                  }
                  i++;
               }
               ENSURE_THIS_MUCH_SPACE(VG_(strlen)(qual));
               j += VG_(sprintf)(&out[j], "%s", qual);
            } else {
               message = "Expected '{' after '%q'\n";
               goto bad;
            }
         } 
         else {
            // Something else, abort.
            message = "Expected 'p' or 'q' or '%' after '%'\n";
            goto bad;
         }
      }
   }
   ENSURE_THIS_MUCH_SPACE(1);
   out[j++] = 0;

   // If 'out' is not an absolute path name, prefix it with the startup dir.
   if (out[0] != '/') {
      if (base_dir == NULL) {
         message = "Current working dir doesn't exist, use absolute path\n";
         goto bad;
      }
      len = VG_(strlen)(base_dir) + 1 + VG_(strlen)(out) + 1;

      HChar *absout = VG_(malloc)("options.efn.4", len);
      VG_(strcpy)(absout, base_dir);
      VG_(strcat)(absout, "/");
      VG_(strcat)(absout, out);
      VG_(free)(out);
      out = absout;
   }

   return out;

  bad: {
   vg_assert(message != NULL);
   // 2:  1 for the '=', 1 for the NUL.
   HChar opt[VG_(strlen)(option_name) + VG_(strlen)(format) + 2];
   VG_(sprintf)(opt, "%s=%s", option_name, format);
   VG_(fmsg_bad_option)(opt, "%s", message);
  }
}
Esempio n. 22
0
/* 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 );
   }
}
Esempio n. 23
0
Bool VG_(split_up_argv)( Int argc, HChar** argv )
{
    Int  i;
    Bool augment = True;
    static Bool already_called = False;

    HChar* hwArgs = HARDWIRED_ARGS_FOR_BGQ;
    if (hwArgs) {
        // This is never freed.  The strduping is necessary because
        // hwArgs is subsequently modified.
        hwArgs = VG_(strdup)("commandline.sua.5", hwArgs);
    }

    XArray* /* of HChar* */ tmp_xarray;

    /* This function should be called once, at startup, and then never
       again. */
    vg_assert(!already_called);
    already_called = True;

    tmp_xarray = VG_(newXA)( VG_(malloc), "commandline.sua.1",
                             VG_(free), sizeof(HChar*) );
    vg_assert(tmp_xarray);

    vg_assert( ! VG_(args_for_valgrind) );
    VG_(args_for_valgrind)
        = VG_(newXA)( VG_(malloc), "commandline.sua.2",
                      VG_(free), sizeof(HChar*) );
    vg_assert( VG_(args_for_valgrind) );

    vg_assert( ! VG_(args_for_client) );
    VG_(args_for_client)
        = VG_(newXA)( VG_(malloc), "commandline.sua.3",
                      VG_(free), sizeof(HChar*) );
    vg_assert( VG_(args_for_client) );

    /* Collect up the args-for-V. */
    i = 1; /* skip the exe (stage2) name. */
    for (; i < argc; i++) {
        vg_assert(argv[i]);
        if (hwArgs != NULL) {
            break;
        }
        if (0 == VG_(strcmp)(argv[i], "--")) {
            i++;
            break;
        }
        if (0 == VG_(strcmp)(argv[i], "--command-line-only=yes"))
            augment = False;
#     if !defined(VGPV_ppc64_linux_bgq)
        /* If we find an arg which doesn't start with '-', assume it is
           the executable name, so stop copying args for Valgrind at
           this point.  Except on statically-linked-in scenarios (BGQ),
           in which case the args for V must be terminated by "--", and
           the first arg that follows is the first arg for the client. */
        if (argv[i][0] != '-')
            break;
#     endif
        add_string( tmp_xarray, argv[i] );
    }

    /* Set VG_(args_the_exename).  Different in the
       statically-linked-in case (BGQ). */
#  if defined(VGPV_ppc64_linux_bgq)
    vg_assert(!VG_(args_the_exename));
    vg_assert(argv[0]);
    VG_(args_the_exename) = argv[0];
#  else
    /* Should now be looking at the exe name. */
    if (i < argc) {
        vg_assert(argv[i]);
        VG_(args_the_exename) = argv[i];
        i++;
    }
#  endif

    /* The rest are args for the client. */
    for (; i < argc; i++) {
        vg_assert(argv[i]);
        add_string( VG_(args_for_client), argv[i] );
    }

    /* Get extra args from ~/.valgrindrc, $VALGRIND_OPTS and
       ./.valgrindrc into VG_(args_for_valgrind). */
    if (augment) {
        // read_dot_valgrindrc() allocates the return value with
        // VG_(malloc)().  We do not free f1_clo and f2_clo as they get
        // put into VG_(args_for_valgrind) and so must persist.
        HChar* home    = VG_(getenv)("HOME");
        HChar* f1_clo  = home ? read_dot_valgrindrc( home ) : NULL;
        HChar* env_clo = VG_(strdup)( "commandline.sua.4",
                                      VG_(getenv)(VALGRIND_OPTS) );
        HChar* f2_clo  = NULL;

        // Don't read ./.valgrindrc if "." is the same as "$HOME", else its
        // contents will be applied twice. (bug #142488)
        if (home) {
            HChar cwd[VKI_PATH_MAX+1];
            Bool  cwd_ok = VG_(get_startup_wd)(cwd, VKI_PATH_MAX);
            f2_clo = ( (cwd_ok && VG_STREQ(home, cwd))
                       ? NULL : read_dot_valgrindrc(".") );
        }

        if (f1_clo)  add_args_from_string( f1_clo );
        if (env_clo) add_args_from_string( env_clo );
        if (f2_clo)  add_args_from_string( f2_clo );
        if (hwArgs)  add_args_from_string( hwArgs );
    }

    /* .. and record how many extras we got. */
    VG_(args_for_valgrind_noexecpass)
        = VG_(sizeXA)( VG_(args_for_valgrind) );

    /* Finally, copy tmp_xarray onto the end. */
    for (i = 0; i < VG_(sizeXA)( tmp_xarray ); i++)
        add_string( VG_(args_for_valgrind),
                    * (HChar**)VG_(indexXA)( tmp_xarray, i ) );

    VG_(deleteXA)( tmp_xarray );

    return hwArgs != NULL;
}
Esempio n. 24
0
// Copies the string, prepending it with the startup working directory, and
// expanding %p and %q entries.  Returns a new, malloc'd string.
HChar* VG_(expand_file_name)(const HChar* option_name, const HChar* format)
{
   const HChar *base_dir;
   Int len, i = 0, j = 0;
   HChar* out;

   base_dir = VG_(get_startup_wd)();

   if (VG_STREQ(format, "")) {
      // Empty name, bad.
      VG_(fmsg)("%s: filename is empty", option_name);
      goto bad;
   }
   
   // If 'format' starts with a '~', abort -- the user probably expected the
   // shell to expand but it didn't (see bug 195268 for details).  This means
   // that we don't allow a legitimate filename beginning with '~' but that
   // seems very unlikely.
   if (format[0] == '~') {
      VG_(fmsg)(
         "%s: filename begins with '~'\n"
         "You probably expected the shell to expand the '~', but it\n"
         "didn't.  The rules for '~'-expansion vary from shell to shell.\n"
         "You might have more luck using $HOME instead.\n",
         option_name
      );
      goto bad;
   }

   len = VG_(strlen)(format) + 1;
   out = VG_(malloc)( "options.efn.1", len );

#define ENSURE_THIS_MUCH_SPACE(x) \
   if (j + x >= len) { \
      len += (10 + x); \
      out = VG_(realloc)("options.efn.2(multiple)", out, len); \
   }

   while (format[i]) {
      if (format[i] != '%') {
         ENSURE_THIS_MUCH_SPACE(1);
         out[j++] = format[i++];
         
      } else {
         // We saw a '%'.  What's next...
         i++;
         if      ('%' == format[i]) {
            // Replace '%%' with '%'.
            ENSURE_THIS_MUCH_SPACE(1);
            out[j++] = format[i++];
         }
         else if ('p' == format[i]) {
            // Print the PID.  Assume that it's not longer than 10 chars --
            // reasonable since 'pid' is an Int (ie. 32 bits).
            Int pid = VG_(getpid)();
            ENSURE_THIS_MUCH_SPACE(10);
            j += VG_(sprintf)(&out[j], "%d", pid);
            i++;
         } 
         else if ('q' == format[i]) {
            i++;
            if ('{' == format[i]) {
               // Get the env var name, print its contents.
               HChar *qual;
               Int begin_qualname = ++i;
               while (True) {
                  if (0 == format[i]) {
                     VG_(fmsg)("%s: malformed %%q specifier\n", option_name);
                     goto bad;
                  } else if ('}' == format[i]) {
                     Int qualname_len = i - begin_qualname;
                     HChar qualname[qualname_len + 1];
                     VG_(strncpy)(qualname, format + begin_qualname,
                                  qualname_len);
                     qualname[qualname_len] = '\0';
                     qual = VG_(getenv)(qualname);
                     if (NULL == qual) {
                        VG_(fmsg)("%s: environment variable %s is not set\n",
                                  option_name, qualname);
                        goto bad;
                     }
                     i++;
                     break;
                  }
                  i++;
               }
               ENSURE_THIS_MUCH_SPACE(VG_(strlen)(qual));
               j += VG_(sprintf)(&out[j], "%s", qual);
            } else {
               VG_(fmsg)("%s: expected '{' after '%%q'\n", option_name);
               goto bad;
            }
         } 
         else {
            // Something else, abort.
            VG_(fmsg)("%s: expected 'p' or 'q' or '%%' after '%%'\n",
                      option_name);
            goto bad;
         }
      }
   }
   ENSURE_THIS_MUCH_SPACE(1);
   out[j++] = 0;

   // If 'out' is not an absolute path name, prefix it with the startup dir.
   if (out[0] != '/') {
      len = VG_(strlen)(base_dir) + 1 + VG_(strlen)(out) + 1;

      HChar *absout = VG_(malloc)("options.efn.4", len);
      VG_(strcpy)(absout, base_dir);
      VG_(strcat)(absout, "/");
      VG_(strcat)(absout, out);
      VG_(free)(out);
      out = absout;
   }

   return out;

  bad: {
   HChar* opt =    // 2:  1 for the '=', 1 for the NUL.
      VG_(malloc)( "options.efn.3",
                   VG_(strlen)(option_name) + VG_(strlen)(format) + 2 );
   VG_(strcpy)(opt, option_name);
   VG_(strcat)(opt, "=");
   VG_(strcat)(opt, format);
   VG_(fmsg_bad_option)(opt, "");
  }
}
void VG_(split_up_argv)( Int argc, HChar** argv )
{
          Int  i;
          Bool augment = True;
   static Bool already_called = False;

   XArray* /* of HChar* */ tmp_xarray;

   /* This function should be called once, at startup, and then never
      again. */
   vg_assert(!already_called);
   already_called = True;

   tmp_xarray = VG_(newXA)( VG_(malloc), "commandline.sua.1",
                            VG_(free), sizeof(HChar*) );

   vg_assert( ! VG_(args_for_valgrind) );
   VG_(args_for_valgrind)
      = VG_(newXA)( VG_(malloc), "commandline.sua.2",
                    VG_(free), sizeof(HChar*) );

   vg_assert( ! VG_(args_for_client) );
   VG_(args_for_client)
      = VG_(newXA)( VG_(malloc), "commandline.sua.3",
                    VG_(free), sizeof(HChar*) );

   /* Collect up the args-for-V. */
   i = 1; /* skip the exe (stage2) name. */
   for (; i < argc; i++) {
      vg_assert(argv[i]);
      if (0 == VG_(strcmp)(argv[i], "--")) {
         i++;
         break;
      }
      if (0 == VG_(strcmp)(argv[i], "--command-line-only=yes"))
         augment = False;
      if (argv[i][0] != '-')
	break;
      add_string( tmp_xarray, argv[i] );
   }

   /* Should now be looking at the exe name. */
   if (i < argc) {
      vg_assert(argv[i]);
      VG_(args_the_exename) = argv[i];
      i++;
   }

   /* The rest are args for the client. */
   for (; i < argc; i++) {
      vg_assert(argv[i]);
      add_string( VG_(args_for_client), argv[i] );
   }

   /* Get extra args from ~/.valgrindrc, $VALGRIND_OPTS and
      ./.valgrindrc into VG_(args_for_valgrind). */
   if (augment) {
      // read_dot_valgrindrc() allocates the return value with
      // VG_(malloc)().  We do not free f1_clo and f2_clo as they get
      // put into VG_(args_for_valgrind) and so must persist.
      HChar* home    = VG_(getenv)("HOME");
      HChar* f1_clo  = home ? read_dot_valgrindrc( home ) : NULL;
      HChar* env_clo = VG_(strdup)( "commandline.sua.4",
                                    VG_(getenv)(VALGRIND_OPTS) );
      HChar* f2_clo  = NULL;

      // Don't read ./.valgrindrc if "." is the same as "$HOME", else its
      // contents will be applied twice. (bug #142488)
      if (home) {
         const HChar *cwd = VG_(get_startup_wd)();
         f2_clo = ( VG_STREQ(home, cwd)
                       ? NULL : read_dot_valgrindrc(".") );
      }

      if (f1_clo)  add_args_from_string( f1_clo );
      if (env_clo) add_args_from_string( env_clo );
      if (f2_clo)  add_args_from_string( f2_clo );
   }

   /* .. and record how many extras we got. */
   VG_(args_for_valgrind_noexecpass) 
      = VG_(sizeXA)( VG_(args_for_valgrind) );

   /* Finally, copy tmp_xarray onto the end. */
   for (i = 0; i < VG_(sizeXA)( tmp_xarray ); i++)
      add_string( VG_(args_for_valgrind), 
                  * (HChar**)VG_(indexXA)( tmp_xarray, i ) );

   VG_(deleteXA)( tmp_xarray );
}