Exemple #1
0
// Tries to find a static array within structVar whose address is within
// range of targetAddr.  The struct's base addr is structVarBaseAddr.
// The return value is the static array variable.
// Remember to recurse on non-pointer struct variables within structVar
// and repeat this same process because they themselves might contain
// static arrays
// *baseAddr = base address of the array variable
// Pre: VAR_IS_BASE_STRUCT(structVar)
static VariableEntry* searchForArrayWithinStruct(VariableEntry* structVar,
                                                  Addr structVarBaseAddr,
                                                  Addr targetAddr,
                                                  Addr* baseAddr) {
  VarNode* v = 0;

  tl_assert(structVar->varType->aggType);

  FJALAR_DPRINTF("searchForArrayWithinStruct: %s, structVarBaseAddr: %p, targetAddr: %p, baseAddr: %p\n",
                 structVar->name, (void*)structVarBaseAddr, (void*)targetAddr, (void*)baseAddr);

//  FJALAR_DPRINTF("aggType: %p, memberVarList: %p\n",
//                 structVar->varType->aggType,
//                (structVar->varType->aggType ? structVar->varType->aggType->memberVarList : 0));

  if (structVar->varType->aggType->memberVarList) {
    for (v = structVar->varType->aggType->memberVarList->first;
         v != 0;
         v = v->next) {
      VariableEntry* potentialVar;
      Addr potentialVarBaseAddr;

      potentialVar = v->var;
      tl_assert(IS_MEMBER_VAR(potentialVar));
      FJALAR_DPRINTF("examining: %s, offset: %ld\n", potentialVar->name,
                      potentialVar->memberVar->data_member_location);

//      FJALAR_DPRINTF("staticArr: %p, ptrLevels: %d, varType: %d\n",
//                      potentialVar->staticArr, potentialVar->ptrLevels,
//                     (potentialVar->varType ? potentialVar->varType->decType : 0));

      potentialVarBaseAddr = structVarBaseAddr + potentialVar->memberVar->data_member_location;

      if (IS_STATIC_ARRAY_VAR(potentialVar) &&
          (potentialVarBaseAddr <= targetAddr) &&
          (targetAddr < (potentialVarBaseAddr +
                         (potentialVar->staticArr->upperBounds[0] *
                          getBytesBetweenElts(potentialVar))))) {
        *baseAddr = potentialVarBaseAddr;
        FJALAR_DPRINTF("Wins: %s\n", potentialVar->name);
        return potentialVar;
      }
      // Recursive step (be careful to avoid infinite recursion)
      else if VAR_IS_BASE_STRUCT(potentialVar) {
        VariableEntry* targetVar =
          searchForArrayWithinStruct(potentialVar,
                                     potentialVarBaseAddr,
                                     targetAddr, baseAddr);

        if (targetVar) {
          FJALAR_DPRINTF("wins: %s\n", potentialVar->name);
          return targetVar;
        }
      }
    }
  }

  *baseAddr = 0;
  return 0;
}
Exemple #2
0
// Takes a pointer to a variable of size typeSize starting at startAddr
// and probes ahead to see how many contiguous blocks of memory are allocated
// (using memcheck check_writable()) for that variable starting at startAddr.
// This is used to determine whether a pointer points to one variable
// (return 1) or whether it points to an array (return > 1).
// We can use this function to determine the array size at runtime
// so that we can properly output the variable as either a single
// variable or an array
// NOTE!  If you pass a pointer to the MIDDLE of an array as startAddr,
// this function will return the number of entries in the array AFTER
// the pointer since it only probes AHEAD and NOT BEHIND!
//
// This is very flaky!!!  It only works properly for heap allocated
// arrays since the stack and global space contain lots of squished-together
// contiguous variables
//
// Now we do a two-pass approach which first goes FORWARD until it
// hits a set of bytes of size typeSize whose A-bits are all unset and
// then BACKWARDS until it hits the first set of bytes of size
// typeSize with at least ONE byte whose V-bit is SET.  This avoids
// printing out large chunks of garbage values when most elements of
// an array are uninitialized.  For example, this function will return
// 10 for an int array allocated to hold 1000 elements but only with
// the first 10 elements initialized.
int probeAheadDiscoverHeapArraySize(Addr startAddr, UInt typeSize)
{
  int arraySize = 0;
  /*tl_assert(typeSize > 0);*/
  if (typeSize == 0)
    return 0;
  FJALAR_DPRINTF ( "typeSize: 0x%x\n", typeSize);
  while (mc_check_writable( startAddr, typeSize, 0))
    {
      if (arraySize % 1000 == 0)
        FJALAR_DPRINTF ( "Made it to %d elements at 0x%x\n", arraySize,
                         (unsigned int)startAddr);
      /* Cut off the search if we can already see it's really big:
         no need to look further than we're going to print. */
      // RUDD TEMP
/*       if (fjalar_array_length_limit != -1 && */
/*           arraySize > fjalar_array_length_limit) */
/*         break; */

      arraySize++;
      startAddr+=typeSize;
    }

  startAddr -= typeSize;
  // Now do a SECOND pass and probe BACKWARDS until we reach the
  // first set of bytes with at least one byte whose V-bit is SET
  while ((arraySize > 0) &&
         // If at least ONE byte within the element of size typeSize
         // is initialized, then consider the entire element to be
         // initialized.  This is done because sometimes only certain
         // members of a struct are initialized, and if we perform the
         // more stringent check for whether ALL members are
         // initialized, then we will falsely mark
         // partially-initialized structs as uninitialized and lose
         // information.  For instance, consider struct point{int x;
         // int y;} - Let's say you had struct point foo[10] and
         // initialized only the 'x' member var. in every element of
         // foo (foo[0].x, foo[1].x, etc...)  but left the 'y' member
         // var uninitialized.  Every element of foo has typeSize = 2
         // * sizeof(int) = 8, but only the first 4 bytes are
         // initialized ('x') while the last 4 are uninitialized
         // ('y').  This function should return 10 for the size of
         // foo, so it must mark each element as initialized when at
         // least ONE byte is initialized (in this case, a byte within
         // 'x').
         !mc_are_some_bytes_initialized(startAddr, typeSize)) {
    arraySize--;
    startAddr-=typeSize;
  }

  return arraySize;
}
Exemple #3
0
// Return the number of bytes between elements of this variable
// if it were used as an array
int getBytesBetweenElts(VariableEntry* var)
{
  tl_assert(var);

  if (var->ptrLevels > 1)
    {
      FJALAR_DPRINTF("getBytesBetweenElts returning sizeof(void*) (%zu)\n",
              sizeof(void*));
      return sizeof(void*);
    }
  else
    {
      FJALAR_DPRINTF("getBytesBetweenElts returning %d\n", var->varType->byteSize);
      return var->varType->byteSize;
    }
}
Exemple #4
0
// If the first basic block of a function ends before entryPC, use
// the last instruction of that basic block as our entrypoint. Otherwise
// use entryPC
static void find_entry_pt(IRSB* bb_orig, FunctionEntry *f) {
  int i;
  Addr entry_pt = 0;

  if(gencontains(funcs_handled, f))
    return;

  if (dyncomp_delayed_trace) {
    dyncomp_print_trace_info = True;
    dyncomp_delayed_trace = False;
  }

  if (dyncomp_delayed_print_IR) {
    fjalar_print_IR = True;
    dyncomp_delayed_print_IR = False;
  }

  FJALAR_DPRINTF("[find_entry_pt] Searching %s for entry address %x\n", f->fjalar_name, (UInt)f->entryPC);
  for(i=0 ; i <  bb_orig->stmts_used; i++) {
    IRStmt *st = bb_orig->stmts[i];
    if(st->tag == Ist_IMark) {
      FJALAR_DPRINTF("\tEncountered IMark for address %x\n", (UInt)st->Ist.IMark.addr);
      if(st->Ist.IMark.addr <= f->entryPC) {
	entry_pt = st->Ist.IMark.addr;
      }
    }
  }
  tl_assert( entry_pt );

  FJALAR_DPRINTF("\t%x chosen for entry\n", (UInt)entry_pt);

  genputtable(funcs_handled, (void *)f, (void *)1);

  genputtable(FunctionTable_by_endOfBb,
	      (void *)entry_pt,
	      (void *)f);

}
Exemple #5
0
// Return a pointer to a FunctionExecutionState which contains the address
// specified by "a" in its stack frame
// Assumes: The stack grows DOWNWARD on all supported platforms so this
//          returns the function entry with the smallest FP that is HIGHER
//          than "a" and a lowestSP that is LOWER than "a"
// Returns 0 if no function found
static
FunctionExecutionState* returnFunctionExecutionStateWithAddress(Addr a)
{
  Int i;

  ThreadId tid = VG_(get_running_tid)();

  FunctionExecutionState* cur_fn = 0;
  FunctionExecutionState* next_fn = 0;

  FJALAR_DPRINTF("Looking for function corresponding "
                 "to stack variable 0x%p\n", (void *)a);

  // Traverse the function stack from the function with
  // the highest ESP to the one with the lowest ESP
  // but DON'T LOOK at the function that's the most
  // recent one on the stack yet - hence 0 <= i <= (fn_stack_first_free_index - 2)
  for (i = 0; i <= fn_stack_first_free_index[tid] - 2; i++)
    {
      cur_fn = &FunctionExecutionStateStack[tid][i];
      next_fn = &FunctionExecutionStateStack[tid][i + 1];

      if (!cur_fn || !next_fn)
        {
          printf( "Error in returnFunctionExecutionStateWithAddress()");
          my_abort();
        }

      FJALAR_DPRINTF("cur_fn->FP: %p\n", (void *)cur_fn->FP);
      FJALAR_DPRINTF("next_fn->FP: %p\n", (void *)next_fn->FP);

      // If it is not the most recent function pushed on the stack,
      // then the stack frame of this function lies in between
      // the EBP of that function and the function immediately
      // following it on the stack
      if ((cur_fn->FP >= a) && (next_fn->FP <= a)) {
        FJALAR_DPRINTF("Returning functionEntry: %p\n", cur_fn);
        return cur_fn;
      }
    }

  // If a function hasn't been found yet, now
  // look at the most recent function on the stack:
  // If it is the most recent function on the stack,
  // then the stack frame can only be approximated to lie
  // in between its FP and lowestSP
  // (this isn't exactly accurate because there are issues
  //  with lowestSP, but at least it'll give us some info.)
  cur_fn = fnStackTop(tid);

  if ((cur_fn->FP >= a) && (cur_fn->lowestSP <= a)) {
    FJALAR_DPRINTF("Returning functionEntry: %zx\n", (ptrdiff_t)cur_fn);
    return cur_fn;
  }

  FJALAR_DPRINTF("  EXIT FAILURE returnFunctionExecutionStateWithAddress\n");
  return 0;
}
// Call this AFTER initializeAllFjalarData() so that all relevant data
// structures are already initialized.
// Try to open a .disambig file for reading, but if it doesn't exist,
// create a new file by writing to it.
// Pre: fjalar_disambig_filename is non-null
void handleDisambigFile() {
  tl_assert(fjalar_disambig_filename);

  if ((disambig_fp = fopen(fjalar_disambig_filename, "r"))) {
    FJALAR_DPRINTF("\n\nREADING %s\n", fjalar_disambig_filename);
    disambig_writing = False;

    VG_(printf)( "\nBegin processing disambiguation file \"%s\" ...\n",
                 fjalar_disambig_filename);

    processDisambigFile();

    VG_(printf)( "Done processing disambiguation file \"%s\"\n",
                 fjalar_disambig_filename);
  }
  else if ((disambig_fp = fopen(fjalar_disambig_filename, "wx"))) {
    FJALAR_DPRINTF("\n\nWRITING %s\n", fjalar_disambig_filename);
    disambig_writing = True;

    // If we are writing a .disambig file, then we always want to
    // visit all the struct variables so that we can generate
    // .disambig entries for them:
    fjalar_output_struct_vars = True;

    // If fjalar_smart_disambig is on, then we need to wait until the
    // END of program execution before printing out the .disambig
    // information (see fjalar_finish()):
    if (!fjalar_smart_disambig) {
      generateDisambigFile();
      VG_(printf)("\nDone generating .disambig file %s\n",
                  fjalar_disambig_filename);
      fclose(disambig_fp);
      disambig_fp = 0;
      VG_(exit)(0);
    }
  }
}
Exemple #7
0
void exit_function(FunctionEntry* f)
{
  ThreadId currentTID = VG_(get_running_tid)();
  FunctionExecutionState* top = fnStackTop(currentTID);
  extern FunctionExecutionState* curFunctionExecutionStatePtr;
  int i;
  ULong FPUshadow;
  double fpuReturnVal;
  Addr xAX, xDX, xAXshadow, xDXshadow;
  Bool foundFunc;

  FJALAR_DPRINTF("Exit function: %s\n", f->fjalar_name);


  top->func->guestStackStart = top->lowSP - VG_STACK_REDZONE_SZB;
  top->func->guestStackEnd = top->func->guestStackStart + top->virtualStackByteSize;
  top->func->lowestVirtSP = (Addr)top->virtualStack;
  top->func->FP  = top->FP;
  top->func->lowestSP  = top->func->guestStackStart;

  FJALAR_DPRINTF("\tState of Guest Stack [%p - %p] \n", (void *)top->lowestSP, (void *)(top->lowestSP + top->virtualStackByteSize));

  // Ok, in Valgrind 2.X, we needed to directly code some assembly to
  // grab the top of the floating-point stack, but Valgrind 3.0
  // provides a virtual FPU stack, so we can just grab that.  Plus, we
  // now have shadow V-bits for the FPU stack.

#if defined(VGA_amd64)
  // XMM registers are represented as a 128-bit integer
  // (Actually an array of 4 32-bit integers), so reinterpret
  // cast it as a double.
  FPUshadow = (VG_(get_shadow_XMM_N)(currentTID, 0))[0];
  fpuReturnVal = *(double *)VG_(get_XMM_N)(currentTID, 0);
  //RUDD DEBUG
  /* for(i=0 ; i < 4; i++) { */
  /*   printf("Testing %d\n", test[i]); */
  /*   printf("shadow: %x\n", testing[i]); */
  /* }    */

#else
  fpuReturnVal = VG_(get_FPU_stack_top)(currentTID);
  FPUshadow = VG_(get_shadow_FPU_stack_top)(currentTID);
#endif


  //RUDD DEBUG
  /* printf("%.16g\n", fpuReturnVal); */
  /* printf("shadow: %x\n", FPUshadow); */
  // Get the value at the simulated %EAX (integer and pointer return
  // values are stored here upon function exit)
  xAX = VG_(get_xAX)(currentTID);

  // Get the value of the simulated %EDX (the high 32-bits of the long
  // long int return value is stored here upon function exit)
  xDX = VG_(get_xDX)(currentTID);


  // 64 bits
  // Use SHADOW values of Valgrind simulated registers to get V-bits
  xAXshadow = VG_(get_shadow_xAX)(currentTID);
  xDXshadow = VG_(get_shadow_xDX)(currentTID);

  FJALAR_DPRINTF("Value of eax: %d, edx: %d\n",(int)xAX, (int)xDX);

  FJALAR_DPRINTF("Exit function: %s\n", f->fjalar_name);

  // Only do something if top->func matches func
  if (!top->func) {
    printf("More exit_function()s than entry_function()s!\n");
    // RUDD EXCEPTION
    VG_(get_and_pp_StackTrace) (currentTID, 15);
    return;
  } else if (!(top->func->fjalar_name) || (top->func != f)) {
    // There are a couple reasons why the function at the top
    // of the Function Execution State Stack would not be the
    // function we expected. All of them are related to a non-
    // local exit of the function. Situations where this might
    // come up include:

    // (1) C++ Exceptions
    // (2) setjmp/longjmp

    // For Fjalar to resume normal operation, we need to pop
    // off functions off the Function Execution State Stack
    // (these would be all the functions that had non-local
    // exits) until we encounter the Function Execution State
    // Stack corresponding to our function.
    printf("MISMATCHED on exit_function! f: %s !=  %s\nDetectedEntryIP: %p - AssumedEntryIP: %p\nDetctedExitIP: %p - AssumedExitIp: %p\n",
                f->fjalar_name,
                top->func->fjalar_name,
                (void *)top->func->entryPC,
                (void *)f->entryPC,
                (void *)top->func->endPC,
                (void *)f->endPC);


    // This is probably being overconservative. However let's revert
    // to Fjalar's old behavior (do nothing) if we can't find an
    // instance of our function in the function stack.
    for(i = fn_stack_first_free_index[currentTID] - 1; i >= 0; i-- ) {
      FunctionExecutionState* curFuncExecPtr = &FunctionExecutionStateStack[currentTID][i];
      if(curFuncExecPtr->func == f) {
        foundFunc = True;
        break;
      }
    }

    if(!foundFunc) {
      VG_(get_and_pp_StackTrace) (currentTID, 15);
      return;
    }

    while(top->func) {
      top = fnStackTop(currentTID);
      if(top->func == f) {
        break;
      }
      fnStackPop(currentTID);
    }

    tl_assert(top->func == f);
  }

  top->xAX = xAX;
  top->xDX = xDX;
  top->FPU = fpuReturnVal;

  // Very important!  Set the A and V bits of the appropriate
  // FunctionExecutionState object and the tags from the (x86) guest
  // state as well:
  for (i = 0; i < sizeof(Addr); i++) {
    set_abit_and_vbyte((Addr)(&top->xAX) + (Addr)i, VGM_BIT_VALID,
                      (xAXshadow & 0xff) << (i * 8));
    set_abit_and_vbyte((Addr)(&top->xDX) + (Addr)i, VGM_BIT_VALID,
                      (xDXshadow & 0xff) << (i * 8));
    set_abit_and_vbyte((Addr)(&top->FPU) + (Addr)i, VGM_BIT_VALID,
                      (FPUshadow & 0xff) << (i * 8));
  }

  for (i = 0; i < 8; i++) {
    set_abit_and_vbyte((Addr)(&top->FPU) + (Addr)i, VGM_BIT_VALID,
                       (FPUshadow & 0xff) << (i * 8));
  }

  curFunctionExecutionStatePtr = top;
  top->func->nonce = top->invocation_nonce;

  fjalar_tool_handle_function_exit(top);

  // Destroy the memory allocated by virtualStack
  // AFTER the tool has handled the exit
  if (top->virtualStack) {
    /* We were previously using the V bits associated with the area to
       store guest V bits, but Memcheck doesn't normally expect
       VG_(malloc)'ed memory to be client accessible, so we have to
       make it inaccessible again before allowing Valgrind's malloc to
       use it, lest assertions fail later. */
    mc_make_noaccess((Addr)top->virtualStack, top->virtualStackByteSize);
    VG_(free)(top->virtualStack);
  }

  // Pop at the VERY end after the tool is done handling the exit.
  // This is subtle but important - this must be done AFTER the tool
  // runs all of it's function exit code, as functions in fjalar_traversal
  // and fjalar_runtime may make use of the function stack. If we fail to
  // pop the function, however, the stack will be left in an inconsistant
  // state and the "!top->func == f" check will fail causing no more
  // program points to be printed.
  fnStackPop(currentTID);

}
Exemple #8
0
void enter_function(FunctionEntry* f)
{
  FunctionExecutionState* newEntry;
  extern FunctionExecutionState* curFunctionExecutionStatePtr;

  ThreadId tid = VG_(get_running_tid)();
  Addr stack_ptr= VG_(get_SP)(tid);
  Addr frame_ptr = 0; /* E.g., %ebp */
  int local_stack, size;

  FJALAR_DPRINTF("[enter_function] startPC is: %x, entryPC is: %x, cu_base: %p\n",
                 (UInt)f->startPC, (UInt)f->entryPC,(void *)f->cuBase);
  FJALAR_DPRINTF("Value of edi: %lx, esi: %lx, edx: %lx, ecx: %lx\n",
      (long)VG_(get_xDI)(tid), (long)VG_(get_xSI)(tid), (long)VG_(get_xDX)(tid), (long)VG_(get_xCX)(tid));

  // Determine the frame pointer for this function using DWARF
  // location lists. This is a "virtual frame pointer" in that it is
  // used by the DWARF debugging information in providing the address
  // of formal parameters and local variables, but it may or may not
  // correspond to an actual frame pointer in the architecture. For
  // example: This will not always return %xbp on x86{-64} platforms
  // and *SHOULD*(untested) work with the -fomit-frame-pointer flag in GCC
  //
  // It usually points just above the function return address.  The
  // .debug_loc info tells how to find (calculate) the frame base
  // at any point in the program.   (markro)
  if(f->locList) {
    Addr eip = f->entryPC;
    location_list *ll;
    eip =  eip - f->cuBase;

    FJALAR_DPRINTF("\tCurrent EIP is: %x\n", (UInt)eip);
    FJALAR_DPRINTF("\tLocation list based function(offset from base: %x). offset is %lu\n",(UInt)eip, f->locListOffset);

    if (gencontains(loc_list_map, (void *)f->locListOffset)) {
      ll = gengettable(loc_list_map, (void *)f->locListOffset);

      // (comment added 2009)  
      // HACK. g++ and GCC handle location lists differently. GCC puts lists offsets
      // relative to the compilation unit, g++ uses the actual address. I'm going to
      // compare the location list ranges both to the cu_base offset, as well as
      // the function's entry point. This might break if there's every a case
      // where the compilation unit offset is a valid address in the program
      while(ll &&
            !(((ll->begin <= eip) && (ll->end >= eip)) ||
              ((ll->begin <= f->entryPC) && (ll->end >= f->entryPC)))) {
        FJALAR_DPRINTF("\tExamining loc list entry: %x - %x - %x\n", (UInt)ll->offset, (UInt)ll->begin, (UInt)ll->end);
        ll = ll->next;
      }

      if(ll) {
        FJALAR_DPRINTF("\tFound location list entry, finding location corresponding to dwarf #: %d with offset: %lld\n", ll->atom, ll->atom_offset);

        // (comment added 2013)  
        // It turns out it might not be just the contents of a register.  Some
        // 32bit x86 code does some tricky stack alignment and has to save a
        // pointer to the orginal stack frame.  This means we get passed a 
        // DW_OP_deref instead of a DW_OP_breg.  The tricky bit is we don't
        // want to go back to that address because it probably won't be equal
        // to the local frame pointer due to the stack alignment.  So the HACK
        // is to just assume the frame pointer is at EBP+8 like normal.  (markro)
        if (ll->atom == DW_OP_deref) {
            ll->atom = DW_OP_breg5;
            ll->atom_offset = 8;
        }    
        if(get_reg[ll->atom - DW_OP_breg0]) {
          frame_ptr = (*get_reg[ll->atom - DW_OP_breg0])(tid) + ll->atom_offset;
        }
      }
    }
  }


  // This is the old code to determine the frame. Fallback to it if we don't
  // have a frame_base from the location_list path. This should keep GCC 3 working
  // fine.
  if(frame_ptr == 0) {
    if (f != primed_function) {
      printf("No location list or frame pointer giving up(Mangled name: %s)\n", f->mangled_name);
      return;
    }
    primed_function = 0;

    if (f->entryPC != f->startPC) {
      /* Prolog has run, so just use the real %ebp */
      frame_ptr = VG_(get_FP)(VG_(get_running_tid)());
    } else {
      FJALAR_DPRINTF("Faking prolog\n");
      /* Don't know about prolog, so fake its effects, given we know that
         ESP hasn't yet been modified: */
      // Looks like we never get here for amd64 as -4 is clearly wrong. (10/26/2015)
      frame_ptr = stack_ptr - 4;
    }
  }

  FJALAR_DPRINTF("\tEnter function: %s - StartPC: %p, EntryPC: %p, frame_ptr: %p\n",
		 f->fjalar_name, (void *)f->startPC, (void *)f->entryPC, (void *)frame_ptr);

  newEntry  = fnStackPush(tid);
  newEntry->func = f;
  newEntry->func->FP = frame_ptr;
  newEntry->func->lowestSP = stack_ptr;
  newEntry->FP = frame_ptr;
  newEntry->lowSP = stack_ptr;
  newEntry->lowestSP = stack_ptr;
  newEntry->xAX = 0;
  newEntry->xDX = 0;
  newEntry->FPU = 0;
  newEntry->invocation_nonce = cur_nonce++;
  newEntry->func->nonce = newEntry->invocation_nonce;


  // FJALAR VIRTUAL STACK
  // Fjalar maintains a virtual stack for invocation a function. This
  // allows Fjalar to provide tools with unaltered values of formal
  // parameters at both function entry and exit, regardless of whether
  // or not the compiler chooses to use the original formal parameter
  // locations as storage for local values.

  // Initialize virtual stack and copy parts of the Valgrind stack
  // into that virtual stack
  local_stack = frame_ptr - stack_ptr + VG_STACK_REDZONE_SZB; /* in our frame */
  tl_assert(local_stack >= 0);
  FJALAR_DPRINTF("frame_ptr: %p, stack_ptr: %p, VG_STACK_REDZONE: %d\n", (void *)frame_ptr, (void *)stack_ptr, VG_STACK_REDZONE_SZB);

  // The virtual stack consists of:
  // (1) local_stack: the entirety of the function's local stack (the
  // memory between the frame pointer and the stack pointer (including the extra
  // redzone)
  // (2) The return pointer, which is sizeof(Addr) bytes
  // (3) The saved base pointer, which is sizeof(Addr) bytes
  // (4) All formal parameters passed on the stack, which is
  //     f->formalParamStackByteSize bytes

  // Let's be conservative in how much we copy over to the Virtual stack. Due to the
  // stack alignment operations in main, we may need  as much as 16 bytes over the above.
  size = local_stack + f->formalParamStackByteSize + sizeof(Addr)*2 + 32;/* plus stuff in caller's*/
  FJALAR_DPRINTF("local_stack: %p, arg_size: %x\n", (void *)(frame_ptr - f->formalParamLowerStackByteSize),
                                                    f->formalParamLowerStackByteSize);
  int delta = stack_ptr - (frame_ptr - f->formalParamLowerStackByteSize);
  if (delta < 0 )
      delta = 0;

  tl_assert(size >= 0);
  if (size != 0) {
    newEntry->virtualStack = VG_(calloc)("fjalar_main.c: enter_func",  size, sizeof(char));
    newEntry->virtualStackByteSize = size;
    newEntry->virtualStackFPOffset = local_stack;

    clear_all_tags_in_range(stack_ptr - VG_STACK_REDZONE_SZB, VG_STACK_REDZONE_SZB - delta);

    VG_(memcpy)(newEntry->virtualStack,
		(char*)stack_ptr - VG_STACK_REDZONE_SZB, size);

    // VERY IMPORTANT!!! Copy all the A & V bits over the real stack to
    // virtualStack!!!  (As a consequence, this copies over the tags
    // as well - look in mc_main.c). Note that the way do this means
    // that the copy is now guest-accessible, if they guessed the
    // VG_(calloc)ed address, which is a bit weird. It would be more
    // elegant to copy the metadata to an inaccessible place, but that
    // would be more work.
    FJALAR_DPRINTF("Copying over stack [%p] -> [%p] %d bytes\n",(void *)(stack_ptr - VG_STACK_REDZONE_SZB),  (void *)newEntry->virtualStack, size);
    mc_copy_address_range_state(stack_ptr - VG_STACK_REDZONE_SZB,
				(Addr)(newEntry->virtualStack), size);


    newEntry->func->guestStackStart = stack_ptr - VG_STACK_REDZONE_SZB;
    newEntry->func->guestStackEnd = newEntry->func->guestStackStart + size;
    newEntry->func->lowestVirtSP = (Addr)newEntry->virtualStack;

  }
  else {
    printf("Obtained a stack size of 0 for Function: %s. Aborting\n", f->fjalar_name);
    tl_assert(0);
  }


  // Do this AFTER initializing virtual stack and lowestSP
  curFunctionExecutionStatePtr = newEntry;
  fjalar_tool_handle_function_entrance(newEntry);
}
Exemple #9
0
// Handle a function exit statement, which contains a jump kind of
// 'Ret'.  It seems pretty accurate to cue off of currentAddr, a value
// that is updated every time an Ist_IMark statement is translated,
// which is quite often
void handle_possible_exit(MCEnv* mce, IRJumpKind jk) {
  if (Ijk_Ret == jk) {
    IRDirty  *di;

    FunctionEntry* curFuncPtr = getFunctionEntryFromAddr(currentAddr);

    if (curFuncPtr &&
	// Also, if fjalar_trace_prog_pts_filename is on (we are
	// reading in a ppt list file), then DO NOT generate IR code
	// to call helper functions for functions whose names are NOT
	// located in prog_pts_tree.  This will greatly speed up
	// processing because these functions are filtered out at
	// translation-time, not at run-time
	(!fjalar_trace_prog_pts_filename ||
	 prog_pts_tree_entry_found(curFuncPtr))) {

      FJALAR_DPRINTF("[handle_possible_exit] %s - %x\n", curFuncPtr->fjalar_name, (UInt)currentAddr);

      // The only argument to exit_function() is a pointer to the
      // FunctionEntry for the function that we are exiting
      di = unsafeIRDirty_0_N(1/*regparms*/,
			     "exit_function",
			     &exit_function,
			     mkIRExprVec_1(IRExpr_Const(IRConst_UWord((Addr)curFuncPtr))));

      // For function exit, we are interested in observing  all general purpose
      // integer registers,  FTOP, and FPREG[], so make sure that they are
      // updated by setting the proper annotations.
      di->nFxState = 11;
      vex_bzero(&di->fxState, sizeof(di->fxState));

      di->fxState[0].fx     = Ifx_Read;
      di->fxState[0].offset = mce->layout->offset_SP;
      di->fxState[0].size   = mce->layout->sizeof_SP;
      di->fxState[1].fx     = Ifx_Read;
      di->fxState[1].offset = mce->layout->offset_FP;
      di->fxState[1].size   = mce->layout->sizeof_FP;
      di->fxState[2].fx     = Ifx_Read;
      di->fxState[2].offset = mce->layout->offset_IP;
      di->fxState[2].size   = mce->layout->sizeof_IP;

      di->fxState[3].fx     = Ifx_Read;
      di->fxState[3].offset = mce->layout->offset_xAX;
      di->fxState[3].size   = mce->layout->sizeof_xAX;
      di->fxState[4].fx     = Ifx_Read;
      di->fxState[4].offset = mce->layout->offset_xBX;
      di->fxState[4].size   = mce->layout->sizeof_xBX;
      di->fxState[5].fx     = Ifx_Read;
      di->fxState[5].offset = mce->layout->offset_xCX;
      di->fxState[5].size   = mce->layout->sizeof_xCX;

      di->fxState[6].fx     = Ifx_Read;
      di->fxState[6].offset = mce->layout->offset_xDX;
      di->fxState[6].size   = mce->layout->sizeof_xDX;
      di->fxState[7].fx     = Ifx_Read;
      di->fxState[7].offset = mce->layout->offset_xSI;
      di->fxState[7].size   = mce->layout->sizeof_xSI;
      di->fxState[8].fx     = Ifx_Read;
      di->fxState[8].offset = mce->layout->offset_xDI;
      di->fxState[8].size   = mce->layout->sizeof_xDI;

      di->fxState[9].fx     = Ifx_Read;
      di->fxState[9].offset = offsetof(VexGuestArchState, guest_FTOP);
      di->fxState[9].size   = sizeof(UInt); /* FTOP is 4 bytes even on x64 */
      di->fxState[10].fx     = Ifx_Read;
      di->fxState[10].offset = offsetof(VexGuestArchState, guest_FPREG);
      di->fxState[10].size   = 8 * sizeof(ULong);

      stmt('V',  mce, IRStmt_Dirty(di) );
    }
  }
}
Exemple #10
0
// This inserts an IR Statement responsible for calling func
// code before the instruction at addr is executed. This is primarily
// used for inserting the call to enter_function on function entry.
// It is also used for handling of 'function priming' for GCC 3 (see
// comment above prime_function). The result of looking up addr in
// table will be passed to func as it's only argument. This function
// does nothing if it is unable to successfully look up addr in the
// provided table.
static void handle_possible_entry_func(MCEnv *mce, Addr64 addr,
				       struct genhashtable *table,
				       const char *func_name,
				       entry_func func) {
  IRDirty  *di;
  FunctionEntry *entry = gengettable(table, (void *)(Addr)addr);

  if(!entry) {
      return;
  }

  // If fjalar_trace_prog_pts_filename is on (we are using a ppt list
  // file), then DO NOT generate IR code to call helper functions for
  // functions whose name is NOT located in prog_pts_tree. It's faster
  // to filter them out at translation-time instead of run-time
  if (entry && (!fjalar_trace_prog_pts_filename ||
		prog_pts_tree_entry_found(entry))) {
    UWord entry_w = (UWord)entry;
    di = unsafeIRDirty_0_N(1/*regparms*/, func_name, func,
			 mkIRExprVec_1(IRExpr_Const(IRConst_UWord(entry_w))));

    // For function entry, we are interested in observing the stack
    // and frame pointers so make sure that they're updated by setting
    // the proper annotations:

    entry->entryPC = addr;

    FJALAR_DPRINTF("Found a valid entry point at %x for\n", (UInt)addr);

    // We need all general purpose registers.
    di->nFxState = 9;
    vex_bzero(&di->fxState, sizeof(di->fxState));

    di->fxState[0].fx     = Ifx_Read;
    di->fxState[0].offset = mce->layout->offset_SP;
    di->fxState[0].size   = mce->layout->sizeof_SP;
    di->fxState[1].fx     = Ifx_Read;
    di->fxState[1].offset = mce->layout->offset_FP;
    di->fxState[1].size   = mce->layout->sizeof_FP;
    di->fxState[2].fx     = Ifx_Read;
    di->fxState[2].offset = mce->layout->offset_IP;
    di->fxState[2].size   = mce->layout->sizeof_IP;

    di->fxState[3].fx     = Ifx_Read;
    di->fxState[3].offset = mce->layout->offset_xAX;
    di->fxState[3].size   = mce->layout->sizeof_xAX;
    di->fxState[4].fx     = Ifx_Read;
    di->fxState[4].offset = mce->layout->offset_xBX;
    di->fxState[4].size   = mce->layout->sizeof_xBX;
    di->fxState[5].fx     = Ifx_Read;
    di->fxState[5].offset = mce->layout->offset_xCX;
    di->fxState[5].size   = mce->layout->sizeof_xCX;

    di->fxState[6].fx     = Ifx_Read;
    di->fxState[6].offset = mce->layout->offset_xDX;
    di->fxState[6].size   = mce->layout->sizeof_xDX;
    di->fxState[7].fx     = Ifx_Read;
    di->fxState[7].offset = mce->layout->offset_xSI;
    di->fxState[7].size   = mce->layout->sizeof_xSI;
    di->fxState[8].fx     = Ifx_Read;
    di->fxState[8].offset = mce->layout->offset_xDI;
    di->fxState[8].size   = mce->layout->sizeof_xDI;

    stmt('V',  mce, IRStmt_Dirty(di) );
  }
}
Exemple #11
0
// Initialize Fjalar after command-line options are processed
void fjalar_post_clo_init()
{
  const char* DISAMBIG = ".disambig";
  int DISAMBIG_LEN = VG_(strlen)(DISAMBIG);

  // We need to turn off some VEX IR optimizations (primarily the one which
  // causes separate basic blocks to be stitched together) for the purpose of
  // detecting entry in main. see "HANDLING FUNCTION ENTRY" in find_entry_pt()
  VG_(clo_vex_control).iropt_unroll_thresh = 0;
  VG_(clo_vex_control).guest_chase_thresh = 0;

  executable_filename = VG_(args_the_exename);

  if (fjalar_with_gdb) {
    int x = 0;
    while (!x) {} /* In GDB, say "p x=1" and then "c" to continue */
  }


  funcs_handled= genallocatehashtable(0,(int (*)(void *,void *)) &equivalentIDs);

  // Handle variables set by command-line options:
  // Assumes that filename is first argument in client_argv
  FJALAR_DPRINTF("\nReading binary file \"%s\" [0x%p]\n\n",
	  executable_filename, executable_filename);

  // --disambig results in the disambig filename being ${executable_filename}.disambig
  // (overrides --disambig-file option)
  if (fjalar_default_disambig) {
    char* disambig_filename =
      VG_(calloc)("fjalar_main.c: fj_po_clo_init", VG_(strlen)(executable_filename) + DISAMBIG_LEN + 1,
	     sizeof(*disambig_filename));

    VG_(strcpy)(disambig_filename, executable_filename);
    VG_(strcat)(disambig_filename, DISAMBIG);
    fjalar_disambig_filename = disambig_filename;
  }

  // There is a bug in my_libc.c that keeps printf and
  // putchar from intermixing properly.  Using NOBUF
  // on stdout keeps putchar from buffering incorrectly.
  setNOBUF(stdout);

  FJALAR_DPRINTF("\n%s\n\n", fjalar_disambig_filename);

  // Calls into typedata.c:
  initialize_typedata_structures();

  FJALAR_DPRINTF("Typedata structures completed\n");

  // Calls into readelf.c:
  process_elf_binary_data(executable_filename);

  FJALAR_DPRINTF("Process elf binary completed\n");
  // Call this BEFORE initializeAllFjalarData() so that the vars_tree
  // objects can be initialized for the --var-list-file option:
  loadAuxiliaryFileData();

  // Calls into generate_fjalar_entries.c:
  initializeAllFjalarData();
  FJALAR_DPRINTF("Fjalar data initialized\n");
  if (fjalar_disambig_filename) {
    handleDisambigFile();
  }

  // Call this AFTER initializeAllFjalarData() so that all of the
  // proper data is ready:
  outputAuxiliaryFilesAndExit();

  FJALAR_DPRINTF("Files output\n");
  // Make sure to execute this last!
  fjalar_tool_post_clo_init();
  FJALAR_DPRINTF("Tool clo initialized\n");
}
Exemple #12
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,
                    const HChar* 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;


  FJALAR_DPRINTF(" printDisambigAction: %s\n", varName);

  // 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;
}
Exemple #13
0
// Pre: disambig_fp has been initialized and disambig_writing is True
void generateDisambigFile() {
  FuncIterator* funcIt;
  TypeIterator* typeIt;

  FJALAR_DPRINTF("\n=> generateDisambigFile: Start Processing\n");

  // Write entries for global variables:
  fputs(ENTRY_DELIMETER, disambig_fp);
  fputs("\n", disambig_fp);
  fputs(GLOBAL_STRING, disambig_fp);
  fputs("\n", disambig_fp);

  visitVariableGroup(GLOBAL_VAR,
                     0,
                     0,
                     0,
                     0,
                     &printDisambigAction);

  FJALAR_DPRINTF("=> generateDisambigFile: Finished Globals\n\n");

  fputs("\n", disambig_fp);

  // Write entries for function parameters and return values:
  funcIt = newFuncIterator();

  while (hasNextFunc(funcIt)) {
    FunctionEntry* cur_entry = nextFunc(funcIt);

    tl_assert(cur_entry);

    // Only write .disambig entries for program points that are listed
    // in prog-pts-file, if we are using the --prog-pts-file option:
    if (!fjalar_trace_prog_pts_filename ||
        // If fjalar_trace_prog_pts_filename is on (we are reading in
        // a ppt list file), then DO NOT OUTPUT entries for program
        // points that we are not interested in.
        prog_pts_tree_entry_found(cur_entry)) {
      fputs(ENTRY_DELIMETER, disambig_fp);
      fputs("\n", disambig_fp);
      fputs(FUNCTION_PREFIX, disambig_fp);
      fputs(cur_entry->fjalar_name, disambig_fp);
      fputs("\n", disambig_fp);

      // Print out all function parameter return value variable names:
      visitVariableGroup(FUNCTION_FORMAL_PARAM,
                         cur_entry,
                         0,
                         0,
                         0,
                         &printDisambigAction);

      visitVariableGroup(FUNCTION_RETURN_VAR,
                         cur_entry,
                         0,
                         0,
                         0,
                         &printDisambigAction);

      fputs("\n", disambig_fp);
    }
  }
  deleteFuncIterator(funcIt);

  FJALAR_DPRINTF("=> generateDisambigFile: Finished Functions\n\n");

  // Write entries for every struct/class in TypesTable, with the
  // type's name prefixed by 'usertype.':
  typeIt = newTypeIterator();

  while (hasNextType(typeIt)) {
    TypeEntry* cur_entry = nextType(typeIt);

    tl_assert(cur_entry && cur_entry->typeName);

    fputs(ENTRY_DELIMETER, disambig_fp);
    fputs("\n", disambig_fp);
    fputs(USERTYPE_PREFIX, disambig_fp);
    fputs(cur_entry->typeName, disambig_fp);
    fputs("\n", disambig_fp);

    visitClassMembersNoValues(cur_entry,
                              &printDisambigAction);

    fputs("\n", disambig_fp);
  }
  deleteTypeIterator(typeIt);

  FJALAR_DPRINTF("=> generateDisambigFile: Finished Types\n\n");
}
Exemple #14
0
// Takes a location and a VariableEntry and tries to determine
// the UPPER BOUND of the array which the pointer refers to.
// CAUTION: This function is still fairly primitive and untested
//
// This now uses a two-pass scheme which first searches to the end of the
// array and then goes backwards until it finds the first byte whose V-bit
// is valid so that it can avoid printing out tons of garbage values and
// cluttering up the .dtrace file.
//
// This also now has support to find statically-sized arrays within structs
// declared as global and local variables as well as statically-sized arrays
// which are themselves global and local variables
int returnArrayUpperBoundFromPtr(VariableEntry* var, Addr varLocation)
{
  VariableEntry* targetVar = 0;
  Addr baseAddr = 0;
  char foundGlobalArrayVariable = 0;

  FJALAR_DPRINTF("Checking for upper bound of %p\n", (void *)varLocation);

  // 1. Search if varLocation is within a global variable
  if (addressIsGlobal(varLocation)) {
    targetVar = returnArrayVariableWithAddr(&globalVars,
                                            varLocation,
                                            1, 0, &baseAddr);

    if (targetVar) {
      foundGlobalArrayVariable = 1;
    }
    else {
      // UNCONDITIONALLY RETURN 0 IF WE CANNOT FIND A GLOBAL ARRAY
      // VARIABLE.  WE DO NOT WANT TO PROBE IN THE GLOBAL SPACE
      // BECAUSE ALL OF IT MAY POSSIBLY BE INITIALIZED.

      //      targetVar = returnGlobalSingletonWithAddress(varLocation);
      //      if (targetVar) {
      return 0;
        //      }
    }
  }
  // 2. If not found, then search if varLocation is within the stack
  //    frame of a function currently on the stack
  if (!targetVar) {
    FunctionExecutionState* e;
    FJALAR_DPRINTF("Not found in globals area, checking on stack\n");

    e = returnFunctionExecutionStateWithAddress(varLocation);

    FJALAR_DPRINTF("Found function entry %p\n", e);

    if (e) {
      VarList* localArrayAndStructVars = &(e->func->localArrayAndStructVars);
      FJALAR_DPRINTF(" e->FP is %p\n", (void *)e->FP);
      FJALAR_DPRINTF(" localArrayAndSTructVars: %p, numVars: %d\n", localArrayAndStructVars, localArrayAndStructVars->numVars);

      tl_assert(!localArrayAndStructVars || (Addr)localArrayAndStructVars > 0x100);

      if (localArrayAndStructVars &&
          // hopefully ensures that it's not totally bogus
          ((Addr)localArrayAndStructVars > 0x100) &&
          (localArrayAndStructVars->numVars > 0)) {
        targetVar = returnArrayVariableWithAddr(localArrayAndStructVars,
                                                varLocation,
                                                0, e, &baseAddr);
      }
    }
  }

  // 3. If still not found, then search the heap for varLocation
  //    if it is lower than the current frame pointer
  // This is a last-ditch desperation attempt and won't yield valid-looking
  // results in cases like when you have a pointer to an int which is located
  // within a struct malloc'ed on the heap.
  if (!targetVar) {
    FJALAR_DPRINTF("Not found on stack, checking in heap\n");

    tl_assert(curFunctionExecutionStatePtr);

    FJALAR_DPRINTF("Checking if the variable is on the stack:\n");
    FJALAR_DPRINTF("\tCurrent Stackframe: [%p - %p]\n", (void*)curFunctionExecutionStatePtr->FP, (void*)curFunctionExecutionStatePtr->lowestSP);

    // Make sure the address is not in the stack or global region
    // before probing so that we don't accidentally make a mistake
    // where we erroneously conclude that the array size is HUGE
    // since all areas on the stack and global regions are ALLOCATED
    // so probing won't do us much good
    if ((varLocation < curFunctionExecutionStatePtr->lowestSP) &&
        !addressIsGlobal(varLocation)) {
      int size;
      FJALAR_DPRINTF("Location looks reasonable, probing at %p\n",
             (void *)varLocation);

      size =
        probeAheadDiscoverHeapArraySize(varLocation,
                                        getBytesBetweenElts(var));

      FJALAR_DPRINTF("Size is %d\n", size);

      // We want an upper-bound on the array, not the actual size
      if (size > 0)
        return (size - 1);
      else
        return 0;
    }
  }
  // This is a less strict match which only compares rep. types
  // ... we will do more checking later to really determine the relative sizes.
  // This leniency allows an int* to reference a char[] and so forth ...
  // see below for translation
  //  else if (baseAddr &&
  //           (targetVar->varType->repType == var->varType->repType)) {

  // (comment added 2005)  
  // TODO: Hmmmm, what are we gonna do without repTypes???  I need to
  // investigate this 'if' condition more carefully later:
  else if (baseAddr) {
    int targetVarSize = 0;
    int targetVarBytesBetweenElts = getBytesBetweenElts(targetVar);
    int varBytesBetweenElts = getBytesBetweenElts(var);
    Addr highestAddr;

    tl_assert(IS_STATIC_ARRAY_VAR(targetVar));
    FJALAR_DPRINTF("varLocation: %p\n", (void *)varLocation);

    highestAddr = baseAddr + ((targetVar->staticArr->upperBounds[0]) * targetVarBytesBetweenElts);

    FJALAR_DPRINTF("baseAddr is: %p, highestAddr is %p\n", (void *)baseAddr, (void *)highestAddr);

    // NEW!: Probe backwards until you find the first address whose V-bit is SET:
    // but ONLY do this for globals and NOT for stuff on the stack because
    // V-bits for stack variables are FLAKY!!!  During function exit, all the V-bits
    // are wiped out :(

    if (foundGlobalArrayVariable) {
      while ((highestAddr > varLocation) &&
              (MC_Ok != mc_check_readable(highestAddr, targetVarBytesBetweenElts, 0))) {
        highestAddr -= targetVarBytesBetweenElts;
      }
    }

    // This is IMPORTANT that we subtract from varLocation RATHER than baseAddr
    // because of the fact that varLocation can point to the MIDDLE of an array
    targetVarSize = (highestAddr - varLocation) / targetVarBytesBetweenElts;
    FJALAR_DPRINTF("targetVarBytesBetweenElts is %d, varBytesBetweenElts is %d, targetVarSize is %d\n",
                    targetVarBytesBetweenElts, varBytesBetweenElts, targetVarSize);


    FJALAR_DPRINTF("Target : [%s - %d] Source : [%s - %d]\n",
                    targetVar->varType->typeName, targetVarBytesBetweenElts,
                    var->varType->typeName, varBytesBetweenElts);

    if (targetVarBytesBetweenElts == varBytesBetweenElts) {
      return targetVarSize;
    } else {
      return (targetVarSize * targetVarBytesBetweenElts) / varBytesBetweenElts;
    }

  }
  return 0;
}
Exemple #15
0
// Returns an array or struct variable within varList
// that encompasses the address provided by "a".
// Properties for return value r = &(returnNode.var):
// location(r) <= "a" < location(r) + (r->upperBounds[0] * getBytesBetweenElts(r))
//   [if array]
// location(r) <= "a" < location(r) + (getBytesBetweenElts(r))
//   [if struct]
// where location(.) is the global location if isGlobal and stack location
// based on FP or SP if !isGlobal
// *baseAddr = the base address of the variable returned
static VariableEntry*
returnArrayVariableWithAddr(VarList* varList,
                            Addr a,
                            char isGlobal,
                            FunctionExecutionState* e,
                            Addr* baseAddr) {
  VarNode* cur_node = 0;
  ThreadId tid = VG_(get_running_tid)();
  Addr var_loc = 0;

  FJALAR_DPRINTF("[returnArrayVariableWithAddr] varList: %p, Addr: %p, %s\n", varList, (void *)a, (isGlobal)?"Global":"NonGlobal");
  if (!isGlobal) {
    FJALAR_DPRINTF("frame_ptr: %p, stack_ptr: %p\n", (void *)e->FP, (void *)e->lowSP);
  }

  for (cur_node = varList->first;
       cur_node != 0;
       cur_node = cur_node->next) {
    VariableEntry* potentialVar = cur_node->var;
    Addr potentialVarBaseAddr = 0;

    if (!potentialVar)
      continue;

    FJALAR_DPRINTF("Examining potential var: %s, offset: 0x%x, locType: 0x%x\n",
                    potentialVar->name, potentialVar->byteOffset, potentialVar->locationType);

    if (isGlobal) {
      tl_assert(IS_GLOBAL_VAR(potentialVar));
      potentialVarBaseAddr = potentialVar->globalVar->globalLocation;
      FJALAR_DPRINTF("Examining potential var address: %p\n",(void *) potentialVarBaseAddr);
    } else {
      if (potentialVar->locationType == FP_OFFSET_LOCATION) {
        potentialVarBaseAddr = e->FP + potentialVar->byteOffset;
      } else {  
        // (comment added 2014)  
        // Potential bug!  We are ignoring other locationTypes
        // and just assuming it is ESP.  This is the only case
        // we've seen (i386 only) so far.  (markro)
        potentialVarBaseAddr = e->lowSP + potentialVar->byteOffset;
      }
    }
    if (potentialVar->location_expression_size) {
      unsigned int i = 0;
      for(i = 0; i < potentialVar->location_expression_size; i++ ) {
        dwarf_location *dloc  = &(potentialVar->location_expression[i]);
        unsigned int  op = dloc->atom;
        int reg_val;

        if(op == DW_OP_addr) {
          // DWARF supplied address
          var_loc = dloc->atom_offset;

        } else if(op == DW_OP_deref) {
          // Dereference result of last DWARF operation
          tl_assert(var_loc);
          var_loc = *(Addr *)var_loc;

        } else if((op >= DW_OP_const1u) && (op <= DW_OP_consts)) {
          // DWARF supplied constant
          var_loc = dloc->atom_offset;

        } else if((op >= DW_OP_plus) && (op <= DW_OP_plus_uconst)) {
          // Add DWARF supplied constant to value to result of last DWARF operation
          var_loc += dloc->atom_offset;

        } else if((op >= DW_OP_reg0) && (op <= DW_OP_reg31)) {
          // Get value located in architectural register
          reg_val = (*get_reg[dloc->atom - DW_OP_reg0])(tid);
          FJALAR_DPRINTF("\tObtaining register value: [%%%s]: %x\n", dwarf_reg_string[dloc->atom - DW_OP_reg0], reg_val);
          var_loc = (Addr)&reg_val;

        } else if((op >= DW_OP_breg0) && (op <= DW_OP_breg31)) {
          // Get value pointed to by architectural register
          reg_val = (*get_reg[dloc->atom - DW_OP_breg0])(tid);
          FJALAR_DPRINTF("\tObtaining register value: [%%%s]: %x\n", dwarf_reg_string[dloc->atom - DW_OP_breg0], reg_val);
          var_loc = reg_val + dloc->atom_offset;
          FJALAR_DPRINTF("\tAdding %lld to the register value for %p\n", dloc->atom_offset, (void *)var_loc);
          tl_assert(var_loc);

        } else if(op == DW_OP_fbreg) {
          // Get value located at an offset from the FRAME_BASE.
          FJALAR_DPRINTF("atom offset: %lld vs. byteOffset: %d\n", dloc->atom_offset, potentialVar->byteOffset);
          var_loc = e->FP + dloc->atom_offset;

        } else {
          // There's a fair number of DWARF operations still unsupported. There is a full list
          // in fjalar_debug.h
          FJALAR_DPRINTF("\tUnsupported DWARF stack OP: %s\n", location_expression_to_string(op));
          tl_assert(0);
        }
        FJALAR_DPRINTF("\tApplying DWARF Stack Operation %s - %p\n",location_expression_to_string(op), (void *)var_loc);
      }
    }
    FJALAR_DPRINTF("addr: %p, potential var_loc: %p, staticArr: %p, ptrLevels: %d, varType: %d\n",
                   (void*)a, (void*)potentialVarBaseAddr, potentialVar->staticArr, potentialVar->ptrLevels,
                   (potentialVar->varType ? potentialVar->varType->decType : 0));

    // array
    if (IS_STATIC_ARRAY_VAR(potentialVar) &&
        (potentialVarBaseAddr <= a) &&
        (a < (potentialVarBaseAddr + (potentialVar->staticArr->upperBounds[0] *
                                      getBytesBetweenElts(potentialVar))))) {

      FJALAR_DPRINTF("returnArrayVar: found matching array with upperBounds[0]: %d\n", potentialVar->staticArr->upperBounds[0]);
      *baseAddr = potentialVarBaseAddr;
      return potentialVar;
    }
    // struct
    else if (VAR_IS_BASE_STRUCT(potentialVar) &&
             (potentialVarBaseAddr <= a) &&
             (a < (potentialVarBaseAddr + getBytesBetweenElts(potentialVar)))) {
      return searchForArrayWithinStruct(potentialVar,
                                        potentialVarBaseAddr,
                                        a, baseAddr);
    }
  }

  *baseAddr = 0;
  return 0;
}