static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,

                                    int is_write, sigset_t *old_set)

{

    CPUState *cpu = current_cpu;

    CPUClass *cc;

    int ret;



    /* We must handle PC addresses from two different sources:

     * a call return address and a signal frame address.

     *

     * Within cpu_restore_state_from_tb we assume the former and adjust

     * the address by -GETPC_ADJ so that the address is within the call

     * insn so that addr does not accidentally match the beginning of the

     * next guest insn.

     *

     * However, when the PC comes from the signal frame, it points to

     * the actual faulting host insn and not a call insn.  Subtracting

     * GETPC_ADJ in that case may accidentally match the previous guest insn.

     *

     * So for the later case, adjust forward to compensate for what

     * will be done later by cpu_restore_state_from_tb.

     */

    if (helper_retaddr) {

        pc = helper_retaddr;

    } else {

        pc += GETPC_ADJ;

    }



    /* For synchronous signals we expect to be coming from the vCPU

     * thread (so current_cpu should be valid) and either from running

     * code or during translation which can fault as we cross pages.

     *

     * If neither is true then something has gone wrong and we should

     * abort rather than try and restart the vCPU execution.

     */

    if (!cpu || !cpu->running) {

        printf("qemu:%s received signal outside vCPU context @ pc=0x%"

               PRIxPTR "\n",  __func__, pc);

        abort();

    }



#if defined(DEBUG_SIGNAL)

    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",

           pc, address, is_write, *(unsigned long *)old_set);

#endif

    /* XXX: locking issue */

    if (is_write && h2g_valid(address)) {

        switch (page_unprotect(h2g(address), pc)) {

        case 0:

            /* Fault not caused by a page marked unwritable to protect

             * cached translations, must be the guest binary's problem.

             */

            break;

        case 1:

            /* Fault caused by protection of cached translation; TBs

             * invalidated, so resume execution.  Retain helper_retaddr

             * for a possible second fault.

             */

            return 1;

        case 2:

            /* Fault caused by protection of cached translation, and the

             * currently executing TB was modified and must be exited

             * immediately.  Clear helper_retaddr for next execution.

             */

            helper_retaddr = 0;

            cpu_exit_tb_from_sighandler(cpu, old_set);

            /* NORETURN */



        default:

            g_assert_not_reached();

        }

    }



    /* Convert forcefully to guest address space, invalid addresses

       are still valid segv ones */

    address = h2g_nocheck(address);



    cc = CPU_GET_CLASS(cpu);

    /* see if it is an MMU fault */

    g_assert(cc->handle_mmu_fault);

    ret = cc->handle_mmu_fault(cpu, address, is_write, MMU_USER_IDX);



    if (ret == 0) {

        /* The MMU fault was handled without causing real CPU fault.

         *  Retain helper_retaddr for a possible second fault.

         */

        return 1;

    }



    /* All other paths lead to cpu_exit; clear helper_retaddr

     * for next execution.

     */

    helper_retaddr = 0;



    if (ret < 0) {

        return 0; /* not an MMU fault */

    }



    /* Now we have a real cpu fault.  */

    cpu_restore_state(cpu, pc);



    sigprocmask(SIG_SETMASK, old_set, NULL);

    cpu_loop_exit(cpu);



    /* never comes here */

    return 1;

}

static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,

                                    int is_write, sigset_t *old_set)

{

    CPUState *cpu = current_cpu;

    CPUClass *cc;

    int ret;



    





























    if (helper_retaddr) {

        pc = helper_retaddr;

    } else {

        pc += GETPC_ADJ;

    }



    













    if (!cpu || !cpu->running) {

        printf("qemu:%s received signal outside vCPU context @ pc=0x%"

               PRIxPTR "\n",  __func__, pc);

        abort();

    }



#if defined(DEBUG_SIGNAL)

    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",

           pc, address, is_write, *(unsigned long *)old_set);

#endif

    

    if (is_write && h2g_valid(address)) {

        switch (page_unprotect(h2g(address), pc)) {

        case 0:

            





            break;

        case 1:

            







            return 1;

        case 2:

            







            helper_retaddr = 0;

            cpu_exit_tb_from_sighandler(cpu, old_set);

            



        default:

            g_assert_not_reached();

        }

    }



    



    address = h2g_nocheck(address);



    cc = CPU_GET_CLASS(cpu);

    

    g_assert(cc->handle_mmu_fault);

    ret = cc->handle_mmu_fault(cpu, address, is_write, MMU_USER_IDX);



    if (ret == 0) {

        





        return 1;

    }



    





    helper_retaddr = 0;



    if (ret < 0) {

        return 0; 

    }



    

    cpu_restore_state(cpu, pc);



    sigprocmask(SIG_SETMASK, old_set, NULL);

    cpu_loop_exit(cpu);



    

    return 1;

}

static inline int FUNC_0(uintptr_t VAR_0, unsigned long VAR_1,

                                    int VAR_2, sigset_t *VAR_3)

{

    CPUState *cpu = current_cpu;

    CPUClass *cc;

    int VAR_4;



    





























    if (helper_retaddr) {

        VAR_0 = helper_retaddr;

    } else {

        VAR_0 += GETPC_ADJ;

    }



    













    if (!cpu || !cpu->running) {

        printf("qemu:%s received signal outside vCPU context @ VAR_0=0x%"

               PRIxPTR "\n",  __func__, VAR_0);

        abort();

    }



#if defined(DEBUG_SIGNAL)

    printf("qemu: SIGSEGV VAR_0=0x%08lx VAR_1=%08lx w=%d oldset=0x%08lx\n",

           VAR_0, VAR_1, VAR_2, *(unsigned long *)VAR_3);

#endif

    

    if (VAR_2 && h2g_valid(VAR_1)) {

        switch (page_unprotect(h2g(VAR_1), VAR_0)) {

        case 0:

            





            break;

        case 1:

            







            return 1;

        case 2:

            







            helper_retaddr = 0;

            cpu_exit_tb_from_sighandler(cpu, VAR_3);

            



        default:

            g_assert_not_reached();

        }

    }



    



    VAR_1 = h2g_nocheck(VAR_1);



    cc = CPU_GET_CLASS(cpu);

    

    g_assert(cc->handle_mmu_fault);

    VAR_4 = cc->handle_mmu_fault(cpu, VAR_1, VAR_2, MMU_USER_IDX);



    if (VAR_4 == 0) {

        





        return 1;

    }



    





    helper_retaddr = 0;



    if (VAR_4 < 0) {

        return 0; 

    }



    

    cpu_restore_state(cpu, VAR_0);



    sigprocmask(SIG_SETMASK, VAR_3, NULL);

    cpu_loop_exit(cpu);



    

    return 1;

}

static inline int FUNC_0(uintptr_t VAR_0, unsigned long VAR_1,
int VAR_2, sigset_t *VAR_3)
{ CPUState *cpu = current_cpu; CPUClass *cc; int VAR_4; if (helper_retaddr) { VAR_0 = helper_retaddr; } else { VAR_0 += GETPC_ADJ; } if (!cpu || !cpu->running) { printf("qemu:%s received signal outside vCPU context @ VAR_0=0x%"
PRIxPTR "\n",  __func__, VAR_0); abort(); } #if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV VAR_0=0x%08lx VAR_1=%08lx w=%d oldset=0x%08lx\n",
VAR_0, VAR_1, VAR_2, *(unsigned long *)VAR_3); #endif
if (VAR_2 && h2g_valid(VAR_1)) { switch (page_unprotect(h2g(VAR_1), VAR_0)) { case 0:
break; case 1:
return 1; case 2:
helper_retaddr = 0; cpu_exit_tb_from_sighandler(cpu, VAR_3); default:
g_assert_not_reached(); } } VAR_1 = h2g_nocheck(VAR_1); cc = CPU_GET_CLASS(cpu); g_assert(cc->handle_mmu_fault); VAR_4 = cc->handle_mmu_fault(cpu, VAR_1, VAR_2, MMU_USER_IDX); if (VAR_4 == 0) { return 1; } helper_retaddr = 0; if (VAR_4 < 0) { return 0; } cpu_restore_state(cpu, VAR_0); sigprocmask(SIG_SETMASK, VAR_3, NULL); cpu_loop_exit(cpu); return 1; }