コード例 #1
0
ファイル: fjalar_runtime.c プロジェクト: puppyofkosh/fjalar
// 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;
}
コード例 #2
0
// Prints a .dtrace entry for a sequence of variable values denoted by
// pValueArray (size numElts).  Returns 1 if variable successfully
// observed and printed, and 0 otherwise.
//
// Upon exit, if pFirstInitElt, then *pFirstInitElt contains the
// pointer to the first initialized element in the sequence, or 0 if
// there are no initialized elements in the sequence.  This is useful
// for DynComp to determine which memory location to use as the
// canonical one for the entire sequence in terms of getting tags.
static char printDtraceSequence(VariableEntry* var,
				Addr* pValueArray,
				Addr* pValueArrayGuest,
				UInt numElts,
				VariableOrigin varOrigin,
				char isHashcode,
				DisambigOverride disambigOverride,
				Addr* pFirstInitElt) {
  UInt i;

  char someEltNonZero = 0;
  char someEltInit = 0;

  char firstInitEltFound = 0;
  Addr firstInitElt = 0;

  DPRINTF("pValueArray: %p - pValueArrayGuest: %p\nnumElts: %d\n", (void *)pValueArray, (void *)pValueArrayGuest, numElts);

/*   if(numElts > 10) { */
/*     VG_(printf)("%s - numElts: %d\n", var->name, numElts); */
/*   } */

  if (pFirstInitElt) {
    *pFirstInitElt = 0;
  }

  tl_assert(var);

  // a pValueArray of 0 or numElts of 0 means nonsensical because
  // there is no content to dereference:
  if (!pValueArray || !numElts) {
    DPRINTF("Pointer null or 0 elements\n");
    DTRACE_PRINTF("%s\n%d\n",
		  NONSENSICAL,
		  mapInitToModbit(0));
    return 0;
  }

  // If all elements of pValueArray are 0, then this also means
  // nonsensical because there is no content to dereference:
  for (i = 0; i < numElts; i++) {
    if (pValueArray[i]) {
      someEltNonZero = 1;
      break;
    }
  }
  if (!someEltNonZero) {
    DPRINTF("All elements 0\n");
    DTRACE_PRINTF("%s\n%d\n",
		  NONSENSICAL,
		  mapInitToModbit(0));
    return 0;
  }


   // If all elements in pValueArray are uninit, then print out UNINIT
   // and return 0. (be conservative and only check the first byte so that
   // we don't mistakenly mark an array of shorts as uninitialized)
   for (i = 0; i < numElts; i++) {
     Addr pCurValue = pValueArray[i];
     char eltInit = addressIsInitialized(pCurValue, sizeof(char));
     if (eltInit) {
       someEltInit = 1;
       break;
     }
   }

  if (!someEltInit) {
    DPRINTF("All elements uninit\n");
    DTRACE_PRINTF("%s\n%d\n",
                  UNINIT,
                  mapInitToModbit(0));
    return 0;
  }


  // Pointer (put this check first before the IS_STRING(var) check so
  // that it will work even for pointers to strings):
  if (isHashcode) {
      int ind;
      int limit = numElts;
      DPRINTF("hashcode\n");
      if (fjalar_array_length_limit != -1) {
        limit = min(limit, fjalar_array_length_limit);
      }

      DTRACE_PRINTF( "[ ");

      for (ind = 0; ind < limit; ind++) {
        Addr pCurValue = pValueArray[ind];
        Addr pCurValueGuest = pValueArrayGuest[ind];
        char eltInit = addressIsInitialized(pCurValue, sizeof(void*));
	if(ind == 0) { // Lets print out the first element for debugging
	  DPRINTF("First element is: %x(GUEST) ", (UInt)pCurValueGuest);
	  DPRINTF("First element is: %x(ACTUAL) ", (UInt)(*((Addr*)pCurValue)));
	}


        if (eltInit) {
          if (!firstInitEltFound) {
            firstInitElt = pCurValue;
            firstInitEltFound = 1;
          }

          DTRACE_PRINTF("%u ", IS_STATIC_ARRAY_VAR(var) ?
                        (UInt)pCurValueGuest :
                        (UInt)(*((Addr*)pCurValue)));

          // Merge the tags of the 4-bytes of the observed pointer as
          // well as the tags of the first initialized address and the
          // current address because we are observing everything as a
          // sequence
          // TODO: This may cause unnecessarily large comparability
          // sets - watch out!
          if (kvasir_with_dyncomp && firstInitElt) {
            val_uf_union_tags_in_range((Addr)pCurValue, sizeof(void*));
            val_uf_union_tags_at_addr((Addr)firstInitElt, (Addr)pCurValue);
          }
        }
        else {
          // Daikon currently only supports 'nonsensical' values
          // inside of sequences, not 'uninit' value.
          if (!kvasir_repair_format) {
            DTRACE_PRINTF(NONSENSICAL);
            DTRACE_PRINTF(" ");
          }
        }
      }

      DTRACE_PRINTF( "]\n%d\n",
                     mapInitToModbit(1));
  }
  // String (not pointer to string)
  else if (IS_STRING(var)) {
    printDtraceStringSequence(var,
                              pValueArray,
                              numElts,
                              disambigOverride,
                              &firstInitElt);
  }
  // Base (non-hashcode) struct or union type
  // Simply print out its hashcode location
  else if (IS_AGGREGATE_TYPE(var->varType)) {
    int ind;
    int limit = numElts;
    if (fjalar_array_length_limit != -1) {
      limit = min(limit, fjalar_array_length_limit);
    }

    DTRACE_PRINTF( "[ ");

    for (ind = 0; ind < limit; ind++) {
      Addr pCurValueGuest = pValueArray[ind];
      DTRACE_PRINTF("%u ", (UInt)pCurValueGuest);
    }

    DTRACE_PRINTF( "]\n%d\n",
                   mapInitToModbit(1));
  }
  // Base type
  else {
    DeclaredType decType = var->varType->decType;

    // override float as double when printing
    // out function return variables because
    // return variables stored in registers are always doubles
    char overrideFloatAsDouble = (varOrigin == FUNCTION_RETURN_VAR);

    if (overrideFloatAsDouble && (decType == D_FLOAT)) {
      decType = D_DOUBLE;
    }

    printDtraceBaseValueSequence(decType,
                                 pValueArray,
                                 numElts,
                                 disambigOverride,
                                 &firstInitElt);
  }

  if (pFirstInitElt) {
    *pFirstInitElt = firstInitElt;
  }

  // Default return value:
  return 1;
}
コード例 #3
0
// Prints a .dtrace entry for a single variable value denoted by
// pValue.  Returns 1 if variable successfully observed and printed,
// and 0 otherwise.
static char printDtraceSingleVar(VariableEntry* var,
				 Addr pValue,
				 Addr pValueGuest,
				 VariableOrigin varOrigin,
				 char isHashcode,
				 char overrideIsInit,
				 DisambigOverride disambigOverride) {
  char allocated = 0;
  char initialized = 0;

  tl_assert(var);

  DPRINTF("  printDtraceSingleVar(): %p(guest %p) overrideisInit: %d\n", (void *)pValue, (void *)pValueGuest, overrideIsInit);

  // a pValue of 0 means nonsensical because there is no content to
  // dereference:
  if (!pValue) {
    DPRINTF("no address\n");
    DTRACE_PRINTF("%s\n%d\n",
		  NONSENSICAL,
		  mapInitToModbit(0));
    return 0;
  }

  // At minimum, check whether the first byte is allocated and/or
  // initialized
  allocated = (overrideIsInit ? 1 :
	       addressIsAllocated((Addr)pValue, sizeof(char)));

  if (!allocated) {
    DPRINTF("unallocated\n");
    DTRACE_PRINTF("%s\n%d\n",
		  NONSENSICAL,
		  mapInitToModbit(0));
    return 0;
  }

  initialized = (overrideIsInit ? 1 :
		 addressIsInitialized((Addr)pValue, sizeof(char)));

  if (!initialized) {
    DPRINTF("uninit\n");
    DTRACE_PRINTF("%s\n%d\n",
		  UNINIT,
		  mapInitToModbit(0));
    return 0;
  }

  // From this point onwards we know that pValue is safe to
  // dereference because it has been both allocated and initialized

  // Pointer (put this check first before the IS_STRING(var) check so
  // that it will work even for pointers to strings):
  if (isHashcode) {
    // Be careful of what to print depending on whether the
    // variable is a static array:
    // TODO: What about a pointer to a static array?
    //       var->isStaticArray says that the base variable is a
    //       static array after all dereferences are done.
    DTRACE_PRINTF("%u\n%d\n",
		  IS_STATIC_ARRAY_VAR(var) ? (UInt)pValueGuest
		  : (UInt)(*((Addr*)pValue)),
		  mapInitToModbit(1));

    // Since we observed all of these bytes as one value, we will
    // merge all of their tags in memory
    if (kvasir_with_dyncomp) {
      DYNCOMP_DPRINTF("dtrace call val_uf_union_tags_in_range(%p, %d) (pointer)\n",
		      (void *)pValue, sizeof(void*));
      val_uf_union_tags_in_range((Addr)pValue, sizeof(void*));
    }
  }
  // String (not pointer to string)
  else if (IS_STRING(var)) {
    char stringReadable = 0;

    // Depends on whether the variable is a static array or not:
    char * actualString = (IS_STATIC_ARRAY_VAR(var) ?
			   (char *)pValue :
			   *((char **)pValue));

    // If this address hasn't been initialized to anything valid,
    // then we shouldn't try to do anything further with it because
    // it's garbage!!!
    stringReadable = checkStringReadable(actualString);

    if (stringReadable) {
      printDtraceSingleString(actualString,
			      disambigOverride);
    }
    else {
      DTRACE_PRINTF("%s\n%d\n",
		    UNINIT,
		    mapInitToModbit(0));
      return 0;
    }
  }
  // Base (non-hashcode) struct or union type
  // Simply print out its hashcode location
  else if (IS_AGGREGATE_TYPE(var->varType)) {
    DTRACE_PRINTF("%u\n%d\n",
		  ((UInt)pValue),
		  mapInitToModbit(1));
  }
  // Base type
  else {
    DeclaredType decType = var->varType->decType;

    // override float as double when printing
    // out function return variables because
    // return variables stored in registers are always doubles
    char overrideFloatAsDouble = (varOrigin == FUNCTION_RETURN_VAR);

    if (overrideFloatAsDouble && (decType == D_FLOAT)) {
      decType = D_DOUBLE;
    }

    return printDtraceSingleBaseValue(pValue,
				      decType,
				      overrideIsInit,
				      disambigOverride);
  }

  // Default return value:
  return 1;
}
コード例 #4
0
ファイル: fjalar_runtime.c プロジェクト: puppyofkosh/fjalar
// 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;
}
コード例 #5
0
ファイル: fjalar_runtime.c プロジェクト: puppyofkosh/fjalar
// 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;
}