Beispiel #1
0
/* helper for find_vm_areas_via_probe() and get_memory_info_from_os()
 * returns the passed-in pc if the probe was successful; else, returns
 * where the next probe should be (to skip DR memory).
 * if the probe was successful, returns in prot the results.
 */
static app_pc
probe_address(dcontext_t *dcontext, app_pc pc_in, byte *our_heap_start,
              byte *our_heap_end, OUT uint *prot)
{
    app_pc base;
    size_t size;
    app_pc pc = (app_pc)ALIGN_BACKWARD(pc_in, PAGE_SIZE);
    ASSERT(ALIGNED(pc, PAGE_SIZE));
    ASSERT(prot != NULL);
    *prot = MEMPROT_NONE;

    /* skip our own vmheap */
    if (pc >= our_heap_start && pc < our_heap_end)
        return our_heap_end;
    /* if no vmheap and we probe our own stack, the SIGSEGV handler will
     * report stack overflow as it checks that prior to handling TRY
     */
    if (is_stack_overflow(dcontext, pc))
        return pc + PAGE_SIZE;
#ifdef VMX86_SERVER
    /* Workaround for PR 380621 */
    if (is_vmkernel_addr_in_user_space(pc, &base)) {
        LOG(GLOBAL, LOG_VMAREAS, 4, "%s: skipping vmkernel region " PFX "-" PFX "\n",
            __func__, pc, base);
        return base;
    }
#endif
    /* Only for find_vm_areas_via_probe(), skip modules added by
     * dl_iterate_get_areas_cb.  Subsequent probes are about gettting
     * info from OS, so do the actual probe.  See PR 410907.
     */
    if (!dynamo_initialized && get_memory_info(pc, &base, &size, prot))
        return base + size;

    TRY_EXCEPT(dcontext, /* try */
               {
                   PROBE_READ_PC(pc);
                   *prot |= MEMPROT_READ;
               },
               /* except */
               {
                   /* nothing: just continue */
               });
Beispiel #2
0
/**
 * @param classRecord Record for method class.
 * @param methodRecord Calle's method record.
 * @param retAddr What the PC should be upon return.
 * @return true iff the stack frame was pushed.
 */
boolean dispatch_special (MethodRecord *methodRecord, byte *retAddr)
{
  #if DEBUG_METHODS
  int debug_ctr;
  #endif

  StackFrame *stackFrame;
  byte newStackFrameIndex;

  #if DEBUG_BYTECODE
  printf ("\n------ dispatch special - %d ------------------\n\n",
          methodRecord->signatureId);
  #endif

  #if DEBUG_METHODS
  printf ("dispatch_special: %d, %d\n", 
          (int) methodRecord, (int) retAddr);
  printf ("-- signature id = %d\n", methodRecord->signatureId);
  printf ("-- code offset  = %d\n", methodRecord->codeOffset);
  printf ("-- flags        = %d\n", methodRecord->mflags);
  printf ("-- num params   = %d\n", methodRecord->numParameters);
  printf ("-- stack ptr    = %d\n", (int) get_stack_ptr());
  printf ("-- max stack ptr= %d\n", (int) (currentThread->stackArray + (get_array_size(currentThread->stackArray))*2));
  #endif

  pop_words (methodRecord->numParameters);
  pc = retAddr;

  if (is_native (methodRecord))
  {
  #if DEBUG_METHODS
  printf ("-- native\n");
  #endif 
    dispatch_native (methodRecord->signatureId, get_stack_ptr() + 1);
    // Stack frame not pushed
    return false;
  }

  newStackFrameIndex = currentThread->stackFrameArraySize;
  
  if (newStackFrameIndex >= get_array_length((Object *) word2ptr (currentThread->stackFrameArray)))
  {
#if !FIXED_STACK_SIZE
  	// int len = get_array_length((Object *) word2ptr (currentThread->stackFrameArray));
  	int newlen = get_array_length((Object *) word2ptr (currentThread->stackFrameArray)) * 3 / 2;
  	JINT newStackFrameArray = JNULL;

	// Stack frames are indexed by a byte value so limit the size.  	
  	if (newlen <= 255)
  	{
  	    // increase the stack frame size
  		newStackFrameArray = ptr2word(reallocate_array(word2ptr(currentThread->stackFrameArray), newlen));
  	}
  	
  	// If can't allocate new stack, give in!
    if (newStackFrameArray == JNULL)
    {
#endif
      throw_exception (stackOverflowError);
      return false;
#if !FIXED_STACK_SIZE
    }
      	
  	// Assign new array
  	currentThread->stackFrameArray = newStackFrameArray;
#endif
  }
  
  if (newStackFrameIndex == 0)
  {
    // Assign NEW stack frame
    stackFrame = stackframe_array();
  }
  else
  {
    #if DEBUG_METHODS
    for (debug_ctr = 0; debug_ctr < methodRecord->numParameters; debug_ctr++)
      printf ("-- param[%d]    = %ld\n", debug_ctr, (long) get_stack_ptr()[debug_ctr+1]);  
    #endif

    // Save OLD stackFrame state
    stackFrame = stackframe_array() + (newStackFrameIndex - 1);
    update_stack_frame (stackFrame);
    // Push NEW stack frame
    stackFrame++;
  }
  // Increment size of stack frame array
  currentThread->stackFrameArraySize++;
  // Initialize rest of new stack frame
  stackFrame->methodRecord = methodRecord;
  stackFrame->monitor = null;
  stackFrame->localsBase = get_stack_ptr() + 1;
  // Initialize auxiliary global variables (registers)
  pc = get_code_ptr(methodRecord);

  #if DEBUG_METHODS
  printf ("pc set to 0x%X\n", (int) pc);
  #endif

  init_sp (stackFrame, methodRecord);
  update_constant_registers (stackFrame);
  
  //printf ("m %d stack = %d\n", (int) methodRecord->signatureId, (int) (localsBase - stack_array())); 
  
  // Check for stack overflow
  // (stackTop + methodRecord->maxOperands) >= (stack_array() + STACK_SIZE);
  if (is_stack_overflow (methodRecord))
  {
#if !FIXED_STACK_SIZE
    StackFrame *stackBase;
    int i;
    
    // Need at least this many bytes
    // int len = (int)(stackTop + methodRecord->maxOperands) - (int)(stack_array()) - HEADER_SIZE;
    
    // Need to compute new array size (as distinct from number of bytes in array).
  	int newlen = (((int)(stackTop + methodRecord->maxOperands) - (int)(stack_array()) - HEADER_SIZE + 1) / 4) * 3 / 2;
  	JINT newStackArray = ptr2word(reallocate_array(word2ptr(currentThread->stackArray), newlen));
  	
  	// If can't allocate new stack, give in!
    if (newStackArray == JNULL)
    {
#endif
      throw_exception (stackOverflowError);
      return false;
#if !FIXED_STACK_SIZE
    }
      	
    // Adjust pointers.
    newlen = newStackArray - currentThread->stackArray;
    stackBase = stackframe_array();
    stackTop = word2ptr(ptr2word(stackTop) + newlen);
    localsBase = word2ptr(ptr2word(localsBase) + newlen);
#if DEBUG_MEMORY
	printf("thread=%d, stackTop(%d), localsBase(%d)=%d\n", currentThread->threadId, (int)stackTop, (int)localsBase, (int)(*localsBase));
#endif
    for (i=currentThread->stackFrameArraySize-1;
         i >= 0;
         i--)
    {
    	stackBase[i].localsBase = word2ptr(ptr2word(stackBase[i].localsBase) + newlen);
   		stackBase[i].stackTop = word2ptr(ptr2word(stackBase[i].stackTop) + newlen);
#if DEBUG_MEMORY
	printf("stackBase[%d].localsBase(%d) = %d\n", i, (int)stackBase[i].localsBase, (int)(*stackBase[i].localsBase));
#endif
    }
    
  	// Assign new array
  	currentThread->stackArray = newStackArray;
#endif
  } 
  return true;
}
Beispiel #3
0
/**
 * @param classRecord Record for method class.
 * @param methodRecord Calle's method record.
 * @param retAddr What the PC should be upon return.
 * @return true iff the stack frame was pushed.
 */
boolean dispatch_special (MethodRecord *methodRecord, byte *retAddr)
{
  /**
   * Note: This code is a little tricky, particularly when used with
   * a garbage collector. It manipulates the stack frame and in some cases
   * may need to perform memory allocation. In all cases we must take care
   * to ensure that if an allocation can be made then any live objects
   * on the stack must be below the current stack pointer.
   * In addition to the above we take great care so that this function can
   * be restarted (to allow us to wait for available memory). To enable this
   * we avoid making any commitments to changes to global state until both
   * stacks have been commited.
   */
  #if DEBUG_METHODS
  int debug_ctr;
  #endif

  Object *stackFrameArray;
  StackFrame *stackFrame;
  StackFrame *stackBase;
  int newStackFrameIndex;
  STACKWORD *newStackTop;
  #if DEBUG_BYTECODE
  printf("call method %d ret %x\n", methodRecord - get_method_table(get_class_record(0)), retAddr);
  printf ("\n------ dispatch special - %d ------------------\n\n",
          methodRecord->signatureId);
  #endif

  #if DEBUG_METHODS
  printf ("dispatch_special: %d, %d\n",
          (int) methodRecord, (int) retAddr);
  printf ("-- signature id = %d\n", methodRecord->signatureId);
  printf ("-- code offset  = %d\n", methodRecord->codeOffset);
  printf ("-- flags        = %d\n", methodRecord->mflags);
  printf ("-- num params   = %d\n", methodRecord->numParameters);
  //printf ("-- stack ptr    = %d\n", (int) get_stack_ptr());
  //printf ("-- max stack ptr= %d\n", (int) (currentThread->stackArray + (get_array_size(currentThread->stackArray))*2));
  #endif


  // First deal with the easy case of a native call...
  if (is_native (methodRecord))
  {
  #if DEBUG_METHODS
  printf ("-- native\n");
  #endif
    // WARNING: Once the instruction below has been executed we may have
    // references on the stack that are above the stack pointer. If a GC
    // gets run when in this state the reference may get collected as
    // grabage. This means that any native functions that take a reference
    // parameter and that may end up allocating memory *MUST* protect that
    // reference before calling the allocator...
    pop_words_cur (methodRecord->numParameters);
    switch(dispatch_native (methodRecord->signatureId, get_stack_ptr_cur() + 1))
    {
      case EXEC_RETRY:
        // Need to re-start the instruction, so reset the state of the stack
        curStackTop += methodRecord->numParameters;
        break;
      case EXEC_CONTINUE:
        // Normal completion return to the requested point.
        curPc = retAddr;
        break;
      case EXEC_RUN:
        // We are running new code, curPc will be set. Nothing to do.
        break;
      case EXEC_EXCEPTION:
        // An exception has been thrown. The PC will be set correctly and
        // the stack may have been adjusted...
        break;
    }
    // Stack frame not pushed
    return false;
  }
  // Now start to build the new stack frames. We start by placing the
  // the new stack pointer below any params. The params will become locals
  // in the new frame.
  newStackTop = get_stack_ptr_cur() - methodRecord->numParameters;

  newStackFrameIndex = (int)(byte)currentThread->stackFrameIndex;
  if (newStackFrameIndex >=  255)
  {
      throw_new_exception (JAVA_LANG_STACKOVERFLOWERROR);
      return false;
  }
  #if DEBUG_METHODS
  //for (debug_ctr = 0; debug_ctr < methodRecord->numParameters; debug_ctr++)
  //  printf ("-- param[%d]    = %ld\n", debug_ctr, (long) get_stack_ptr()[debug_ctr+1]);
  #endif
  stackFrameArray = ref2obj(currentThread->stackFrameArray);
  stackBase = (StackFrame *)array_start(stackFrameArray);
  // Setup OLD stackframe ready for return
  stackFrame = stackBase + (newStackFrameIndex);
  stackFrame->stackTop = newStackTop;
  stackFrame->pc = retAddr;
  // Push NEW stack frame
  // Increment size of stack frame array but do not commit to it until we have
  // completely built both new stacks.
  newStackFrameIndex++;
  stackFrame++;
  if (((byte *)stackFrame - (byte *)stackBase) >= get_array_length(stackFrameArray))
  {
#if FIXED_STACK_SIZE
    throw_new_exception (JAVA_LANG_STACKOVERFLOWERROR);
    return false;
#else
    if (expand_call_stack(currentThread) < 0)
      return false;
    stackFrame = (StackFrame *)array_start(currentThread->stackFrameArray) + newStackFrameIndex;
#endif
  }

  // Initialize rest of new stack frame
  stackFrame->methodRecord = methodRecord;
  stackFrame->monitor = null;
  stackFrame->localsBase = newStackTop + 1;
  // Allocate space for locals etc.
  newStackTop = init_sp(stackFrame, methodRecord);
  stackFrame->stackTop = newStackTop;
  currentThread->stackFrameIndex = newStackFrameIndex;

  // Check for stack overflow
  if (is_stack_overflow (newStackTop, methodRecord))
  {
#if FIXED_STACK_SIZE
    throw_new_exception (JAVA_LANG_STACKOVERFLOWERROR);
    return false;
#else

    if (expand_value_stack(currentThread, methodRecord->maxOperands+methodRecord->numLocals) < 0)
    {
      currentThread->stackFrameIndex--;
      return false;
    }
    // NOTE at this point newStackTop is no longer valid!
    newStackTop = stackFrame->stackTop;
#endif
  }
  // All set. So now we can finally commit to the new stack frames
  update_constant_registers (stackFrame);
  curStackTop = newStackTop;
  // and jump to the start of the new code
  curPc = get_code_ptr(methodRecord);
  return true;
}
Beispiel #4
0
static void general_signal_handler(int signum, siginfo_t* info, void* context)
{
    Registers regs;

    if (!context)
        return;

    // Convert OS context to Registers
    port_thread_context_to_regs(&regs, (ucontext_t*)context);
    void* fault_addr = info ? info->si_addr : NULL;

    // Check if SIGSEGV is produced by port_read/write_memory
    port_tls_data_t* tlsdata = get_private_tls_data();
    if (tlsdata && tlsdata->violation_flag)
    {
        tlsdata->violation_flag = 0;
        regs.set_ip(tlsdata->restart_address);
        return;
    }

    if (!tlsdata) // Tread is not attached - attach thread temporarily
    {
        int res;
        tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t));

        if (tlsdata) // Try to attach the thread
            res = port_thread_attach_local(tlsdata, TRUE, TRUE, 0);

        if (!tlsdata || res != 0)
        {   // Can't process correctly; perform default actions
            if (FLAG_DBG)
            {
                bool result = gdb_crash_handler(&regs);
                _exit(-1); // Exit process if not sucessful...
            }

            if (FLAG_CORE &&
                    signum != SIGABRT) // SIGABRT can't be rethrown
            {
                signal(signum, SIG_DFL); // setup default handler
                return;
            }

            _exit(-1);
        }

        // SIGSEGV can represent SO which can't be processed out of signal handler
        if (signum == SIGSEGV && // This can occur only when a user set an alternative stack
                is_stack_overflow(tlsdata, fault_addr))
        {
            int result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, &regs, fault_addr, FALSE);

            if (result == 0)
            {
                if (port_thread_detach_temporary() == 0)
                    STD_FREE(tlsdata);
                return;
            }

            if (result > 0)
                tlsdata->debugger = TRUE;
            else
            {
                if (FLAG_CORE)
                {   // Rethrow crash to generate core
                    signal(signum, SIG_DFL); // setup default handler
                    return;
                }
                _exit(-1);
            }
        }
    }

    if (tlsdata->debugger)
    {
        bool result = gdb_crash_handler(&regs);
        _exit(-1); // Exit process if not sucessful...
    }

    if (signum == SIGABRT && // SIGABRT can't be trown again from c_handler
            FLAG_DBG)
    {   // So attaching GDB right here
        bool result = gdb_crash_handler(&regs);
        _exit(-1); // Exit process if not sucessful...
    }

    if (signum == SIGSEGV &&
            is_stack_overflow(tlsdata, fault_addr))
    {
        // Second SO while previous SO is not processed yet - is GPF
        if (tlsdata->restore_guard_page)
            tlsdata->restore_guard_page = FALSE;
        else
        {   // To process signal on protected stack area
            port_thread_clear_guard_page();
            // Note: the call above does not disable alternative stack
            // It can't be made while we are on alternative stack
            // Alt stack will be disabled explicitly in c_handler()
            tlsdata->restore_guard_page = TRUE;
        }
    }

    // Prepare registers for transfering control out of signal handler
    void* callback = (void*)&c_handler;

    port_set_longjump_regs(callback, &regs, 3,
                           &regs, (void*)(size_t)signum, fault_addr);

    // Convert prepared Registers back to OS context
    port_thread_regs_to_context((ucontext_t*)context, &regs);
    // Return from signal handler to go to C handler
}