about summary refs log tree commit diff stats
path: root/src/libtools/signal32.c
blob: 99e09434e61e27973cac00e62dd26c600bbf02d5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <syscall.h>
#include <stddef.h>
#include <stdarg.h>
#include <ucontext.h>
#include <setjmp.h>
#include <sys/mman.h>
#include <pthread.h>
#ifndef ANDROID
#include <execinfo.h>
#endif

#include "x64_signals.h"
#include "os.h"
#include "box32context.h"
#include "debug.h"
#include "x64emu.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "signals.h"
#include "box64stack.h"
#include "box64cpu.h"
#include "callback.h"
#include "elfloader.h"
#include "threads.h"
#include "emu/x87emu_private.h"
#include "custommem.h"
#include "bridge.h"
#ifdef DYNAREC
#include "dynablock.h"
#include "../dynarec/dynablock_private.h"
#include "dynarec_native.h"
#if defined(ARM64)
#include "dynarec/arm64/arm64_mapping.h"
#define CONTEXT_REG(P, X)   P->uc_mcontext.regs[X]
#define CONTEXT_PC(P)       P->uc_mcontext.pc
#elif defined(LA64)
#include "dynarec/la64/la64_mapping.h"
#define CONTEXT_REG(P, X)   P->uc_mcontext.__gregs[X]
#define CONTEXT_PC(P)       P->uc_mcontext.__pc;
#elif defined(RV64)
#include "dynarec/rv64/rv64_mapping.h"
#define CONTEXT_REG(P, X)   P->uc_mcontext.__gregs[X]
#define CONTEXT_PC(P)       P->uc_mcontext.__gregs[REG_PC]
#else
#error Unsupported Architecture
#endif //arch
#endif


/* Definitions taken from the kernel headers.  */
enum
{
  I386_GS = 0,
# define I386_GS         I386_GS
  I386_FS,
# define I386_FS         I386_FS
  I386_ES,
# define I386_ES         I386_ES
  I386_DS,
# define I386_DS         I386_DS
  I386_EDI,
# define I386_EDI        I386_EDI
  I386_ESI,
# define I386_ESI        I386_ESI
  I386_EBP,
# define I386_EBP        I386_EBP
  I386_ESP,
# define I386_ESP        I386_ESP
  I386_EBX,
# define I386_EBX        I386_EBX
  I386_EDX,
# define I386_EDX        I386_EDX
  I386_ECX,
# define I386_ECX        I386_ECX
  I386_EAX,
# define I386_EAX        I386_EAX
  I386_TRAPNO,
# define I386_TRAPNO        I386_TRAPNO
  I386_ERR,
# define I386_ERR        I386_ERR
  I386_EIP,
# define I386_EIP        I386_EIP
  I386_CS,
# define I386_CS                I386_CS
  I386_EFL,
# define I386_EFL        I386_EFL
  I386_UESP,
# define I386_UESP        I386_UESP
  I386_SS
# define I386_SS        I386_SS
};

typedef uint32_t i386_gregset_t[19];
struct i386_fpreg
{
  uint16_t significand[4];
  uint16_t exponent;
}__attribute__((packed));

struct i386_fpxreg
{
  unsigned short significand[4];
  unsigned short exponent;
  unsigned short padding[3];
}__attribute__((packed));

struct i386_xmmreg
{
  uint32_t          element[4];
}__attribute__((packed));

struct i386_fpstate
{
  /* Regular FPU environment.  */
  uint32_t          cw;
  uint32_t          sw;
  uint32_t          tag;
  uint32_t          ipoff;
  uint32_t          cssel;
  uint32_t          dataoff;
  uint32_t          datasel;
  struct i386_fpreg _st[8];
  uint32_t          status_magic;
  /* FXSR FPU environment.  */
  uint32_t          _fxsr_env[6];
  uint32_t          mxcsr;
  uint32_t          reserved;
  struct i386_fpxreg _fxsr_st[8];
  struct i386_xmmreg _xmm[8];
  uint32_t          padding[56];
}__attribute__((packed));

typedef struct i386_fpstate *i386_fpregset_t;

static void save_fpreg(x64emu_t* emu, struct i386_fpstate* state)
{
    emu->sw.f.F87_TOP = emu->top&7;
    state->sw = emu->sw.x16;
    state->cw = emu->cw.x16;
    // save SSE and MMX regs
    fpu_fxsave32(emu, &state->_fxsr_env);
}
static void load_fpreg(x64emu_t* emu, struct i386_fpstate* state)
{
    // copy SSE and MMX regs
    fpu_fxrstor32(emu, &state->_fxsr_env);
    emu->cw.x16 = state->cw;
    emu->sw.x16 = state->sw;
    emu->top = emu->sw.f.F87_TOP&7;
}

typedef struct
  {
    ptr_t ss_sp;
    int ss_flags;
    long_t ss_size;
  } i386_stack_t;

typedef struct x64_stack_s
{
    void *ss_sp;
    int ss_flags;
    size_t ss_size;
} x64_stack_t;


/*
another way to see the sigcontext
struct sigcontext
{
  unsigned short gs, __gsh;
  unsigned short fs, __fsh;
  unsigned short es, __esh;
  unsigned short ds, __dsh;
  unsigned long edi;
  unsigned long esi;
  unsigned long ebp;
  unsigned long esp;
  unsigned long ebx;
  unsigned long edx;
  unsigned long ecx;
  unsigned long eax;
  unsigned long trapno;
  unsigned long err;
  unsigned long eip;
  unsigned short cs, __csh;
  unsigned long eflags;
  unsigned long esp_at_signal;
  unsigned short ss, __ssh;
  struct _fpstate * fpstate;
  unsigned long oldmask;
  unsigned long cr2;
};
*/
typedef struct
  {
    i386_gregset_t gregs;
    ptr_t fpregs;   //i386_fpregset_t
    uint32_t oldmask;
    uint32_t cr2;
  } i386_mcontext_t;

// /!\ signal sig_set is different than glibc __sig_set
#define _NSIG_WORDS (64 / 32)
typedef unsigned long i386_old_sigset_t;
typedef struct {
    unsigned long sig[_NSIG_WORDS];
} i386_sigset_t;

struct i386_xsave_hdr_struct {
 	uint64_t xstate_bv;
 	uint64_t reserved1[2];
 	uint64_t reserved2[5];
};

struct i386_xstate {
	/*
	 * Applications need to refer to fpstate through fpstate pointer
	 * in sigcontext. Not here directly.
	 */
 	struct i386_fpstate fpstate;
 	struct i386_xsave_hdr_struct xsave_hdr;
 	/* new processor state extensions will go here */
} __attribute__ ((aligned (64)));

struct i386_xstate_cntxt {
	ptr_t               xstate; //struct  i386_xstate *xstate;
	uint32_t	        size;
	uint32_t 	        lmask;
	uint32_t	        hmask;
};

typedef struct i386_ucontext_s
{
    uint32_t uc_flags;
    ptr_t uc_link;  //struct i386_ucontext_s *uc_link;
    i386_stack_t uc_stack;
    i386_mcontext_t uc_mcontext;
    i386_sigset_t uc_sigmask;
	/* Allow for uc_sigmask growth.  Glibc uses a 1024-bit sigset_t.  */
	int		  unused[32 - (sizeof (sigset_t) / sizeof (int))];
	//struct i386_xstate_cntxt  uc_xstate;
    struct i386_xstate  xstate;
} i386_ucontext_t;

typedef struct i386_sigframe_s {
    ptr_t           pretcode;   // pointer to retcode
    int             sig;
    i386_mcontext_t cpustate;
    struct i386_xstate fpstate;
    ptr_t           extramask[64-1];
    char            retcode[8];
} i386_sigframe_t;

struct kernel_sigaction {
        void (*k_sa_handler) (int);
        unsigned long sa_flags;
        void (*sa_restorer) (void);
        unsigned long sa_mask;
        unsigned long sa_mask2;
};

typedef struct __attribute__((packed, aligned(4))) my_siginfo32_s
{
    int si_signo;
    int si_errno;
    int si_code;
    union {
	    int _pad[128/sizeof(int)-3];
	struct {
	    __pid_t __si_pid;
	    __uid_t __si_uid;
    } _kill;
	struct {
	    int si_tid;
	    int __si_overrun;
	    __sigval_t si_sigval;
    } _timer;
	struct {
	    __pid_t __si_pid;
	    __uid_t __si_uid;
	    __sigval_t si_sigval;
    } _rt;
	struct {
	    __pid_t __si_pid;
	    __uid_t __si_uid;
	    int __si_status;
	    __clock_t __si_utime;
	    __clock_t __si_stime;
    } _sigchld;
	struct {
	    ptr_t __si_addr;
	    __SI_SIGFAULT_ADDL
	    short int __si_addr_lsb;
	    union {
            struct {
                ptr_t _lower;
                ptr_t _upper;
            } _addr_bnd;
            __uint32_t _pkey;
        } _bounds;
    } _sigfault;
	struct
	  {
	    long int __si_band;
	    int __si_fd;
	  } _sigpoll;
	struct
	  {
	    ptr_t _call_addr;
	    int _syscall;
	    unsigned int _arch;
	  } _sigsys;
    } _sifields;
} my_siginfo32_t;

x64_stack_t* sigstack_getstack();
int my_sigaltstack(x64emu_t* emu, const x64_stack_t* ss, x64_stack_t* oss);
EXPORT int my32_sigaltstack(x64emu_t* emu, const i386_stack_t* ss, i386_stack_t* oss)
{
    x64_stack_t ss_ = {0};
    x64_stack_t oss_ = {0};
    if(ss) {
        ss_.ss_flags = ss->ss_flags;
        ss_.ss_sp = from_ptrv(ss->ss_sp);
        ss_.ss_size = ss->ss_size;
    }
    int ret = my_sigaltstack(emu, ss?(&ss_):NULL, oss?(&oss_):NULL);
    if(!ret && oss) {
        oss->ss_flags = oss_.ss_flags;
        oss->ss_sp = to_ptrv(oss_.ss_sp);
        oss->ss_size = oss_.ss_size;
    }
    return ret;
}


uint32_t RunFunctionHandler32(int* exit, int dynarec, i386_ucontext_t* sigcontext, ptr_t fnc, int nargs, ...)
{
    if(fnc==0 || fnc==1) {
        va_list va;
        va_start (va, nargs);
        int sig = va_arg(va, int);
        va_end (va);
        printf_log(LOG_NONE, "%04d|BOX32: Warning, calling Signal %d function handler %s\n", GetTID(), sig, fnc?"SIG_IGN":"SIG_DFL");
        if(fnc==0) {
            printf_log(LOG_NONE, "Unhandled signal caught, aborting\n");
            abort();
        }
        return 0;
    }
#ifdef HAVE_TRACE
    uintptr_t old_start = trace_start, old_end = trace_end;
#if 0
    trace_start = 0; trace_end = 1; // disabling trace, globably for now...
#endif
#endif
    x64emu_t *emu = thread_get_emu();
    #ifdef DYNAREC
    if (BOX64ENV(dynarec_test))
        emu->test.test = 0;
    #endif

    /*SetFS(emu, default_fs);*/
    for (int i=0; i<6; ++i)
        emu->segs_serial[i] = 0;

    int align = nargs&1;

    R_ESP -= nargs * sizeof(ptr_t);

    uint32_t *p = (uint32_t*)from_ptrv(R_ESP);

    va_list va;
    va_start (va, nargs);
    for (int i=0; i<nargs; ++i) {
        uint32_t v = va_arg(va, uint32_t);
        *p = v;
        p++;
    }
    va_end (va);

    printf_log(LOG_DEBUG, "%04d|signal #%d function handler %p called, RSP=%p\n", GetTID(), R_EDI, from_ptrv(fnc), from_ptrv(R_ESP));

    int oldquitonlongjmp = emu->flags.quitonlongjmp;
    emu->flags.quitonlongjmp = 2;
    int old_cs = R_CS;
    R_CS = 0x23;

    if(dynarec)
        DynaCall(emu, fnc);
    else
        EmuCall(emu, fnc);

    if(!emu->flags.longjmp)
        R_ESP+=nargs*sizeof(ptr_t);

    if(!emu->flags.longjmp && R_CS==0x23)
        R_CS = old_cs;

    emu->flags.quitonlongjmp = oldquitonlongjmp;

    #ifdef DYNAREC
    if (BOX64ENV(dynarec_test)) {
        emu->test.test = 0;
        emu->test.clean = 0;
    }
#endif

    if(emu->flags.longjmp) {
        // longjmp inside signal handler, lets grab all relevent value and do the actual longjmp in the signal handler
        emu->flags.longjmp = 0;
        if(sigcontext) {
            sigcontext->uc_mcontext.gregs[I386_EAX] = R_EAX;
            sigcontext->uc_mcontext.gregs[I386_ECX] = R_ECX;
            sigcontext->uc_mcontext.gregs[I386_EDX] = R_EDX;
            sigcontext->uc_mcontext.gregs[I386_EDI] = R_EDI;
            sigcontext->uc_mcontext.gregs[I386_ESI] = R_ESI;
            sigcontext->uc_mcontext.gregs[I386_EBP] = R_EBP;
            sigcontext->uc_mcontext.gregs[I386_ESP] = R_ESP;
            sigcontext->uc_mcontext.gregs[I386_EBX] = R_EBX;
            sigcontext->uc_mcontext.gregs[I386_EIP] = R_EIP;
            // flags
            sigcontext->uc_mcontext.gregs[I386_EFL] = emu->eflags.x64;
            // get segments
            sigcontext->uc_mcontext.gregs[I386_CS] = R_CS;
            sigcontext->uc_mcontext.gregs[I386_DS] = R_DS;
            sigcontext->uc_mcontext.gregs[I386_ES] = R_ES;
            sigcontext->uc_mcontext.gregs[I386_SS] = R_SS;
            sigcontext->uc_mcontext.gregs[I386_FS] = R_FS;
            sigcontext->uc_mcontext.gregs[I386_GS] = R_GS;
        } else {
            printf_log(LOG_NONE, "Warning, longjmp in signal but no sigcontext to change\n");
        }
    }
    if(exit)
        *exit = emu->exit;

    uint32_t ret = R_EAX;

#ifdef HAVE_TRACE
    trace_start = old_start; trace_end = old_end;
#endif

    return ret;
}
void convert_siginfo_to_32(void* d, void* s, int sig)
{
    if(!s || !d) return;
    my_siginfo32_t* dst = d;
    siginfo_t* src = s;

    memcpy(dst, src, sizeof(my_siginfo32_t));
    if(sig==X64_SIGILL || sig==X64_SIGFPE || sig==X64_SIGSEGV || sig==X64_SIGBUS)
        dst->_sifields._sigfault.__si_addr = to_ptr(((uintptr_t)src->si_addr)&0xffffffff);  // in case addr is not a 32bits value...
    if(sig==X64_SIGCHLD) {
        dst->_sifields._sigchld.__si_pid = src->si_pid;
        dst->_sifields._sigchld.__si_uid = src->si_uid;
        dst->_sifields._sigchld.__si_status = src->si_status;
        dst->_sifields._sigchld.__si_stime = src->si_stime;
        dst->_sifields._sigchld.__si_utime = src->si_utime;
    }
}

void relockMutex(int locks);
int unlockMutex();

int write_opcode(uintptr_t rip, uintptr_t native_ip, int is32bits);
#define is_memprot_locked (1<<1)
#define is_dyndump_locked (1<<8)
void my_sigactionhandler_oldcode_32(x64emu_t* emu, int32_t sig, int simple, siginfo_t* info, void * ucntx, int* old_code, void* cur_db)
{
    int Locks = unlockMutex();
    int log_minimum = (BOX64ENV(showsegv))?LOG_NONE:((sig==X64_SIGSEGV && my_context->is_sigaction[sig])?LOG_DEBUG:LOG_INFO);

    printf_log(LOG_DEBUG, "Sigactionhanlder32 for signal #%d called (jump to %p/%s)\n", sig, (void*)my_context->signals[sig], GetNativeName((void*)my_context->signals[sig]));

    uintptr_t restorer = my_context->restorer[sig];
    // get that actual ESP first!
    if(!emu)
        emu = thread_get_emu();
    uintptr_t frame = R_ESP;
#if defined(DYNAREC)
    dynablock_t* db = (dynablock_t*)cur_db;//FindDynablockFromNativeAddress(pc);
    ucontext_t *p = (ucontext_t *)ucntx;
    void* pc = NULL;
    if(p) {
        pc = (void*)CONTEXT_PC(p);
        if(db)
            frame = from_ptr((ptr_t)CONTEXT_REG(p, xRSP));
    }
#else
    (void)ucntx; (void)cur_db;
    void* pc = NULL;
#endif
    // setup libc context stack frame, on caller stack
    frame = frame&~15;

    // stack tracking
    x64_stack_t *new_ss = my_context->onstack[sig]?sigstack_getstack():NULL;
    int used_stack = 0;
    if(new_ss) {
        if(new_ss->ss_flags == SS_ONSTACK) { // already using it!
            frame = from_ptr(((ptr_t)emu->regs[_SP].q[0] - 128) & ~0x0f);
        } else {
            frame = from_ptr(((uintptr_t)new_ss->ss_sp + new_ss->ss_size - 16) & ~0x0f);
            used_stack = 1;
            new_ss->ss_flags = SS_ONSTACK;
        }
    } else {
        frame -= 0x200; // redzone
    }

    // TODO: do I need to really setup 2 stack frame? That doesn't seems right!
    // setup stack frame
    frame -= 512+64+16*16;
    void* xstate = (void*)frame;
    frame -= sizeof(my_siginfo32_t);
    my_siginfo32_t* info2 = (my_siginfo32_t*)frame;
    convert_siginfo_to_32(info2, info, sig);
    // try to fill some sigcontext....
    frame -= sizeof(i386_ucontext_t);
    i386_ucontext_t   *sigcontext = (i386_ucontext_t*)frame;
    // get general register
    sigcontext->uc_mcontext.gregs[I386_EAX] = R_EAX;
    sigcontext->uc_mcontext.gregs[I386_ECX] = R_ECX;
    sigcontext->uc_mcontext.gregs[I386_EDX] = R_EDX;
    sigcontext->uc_mcontext.gregs[I386_EDI] = R_EDI;
    sigcontext->uc_mcontext.gregs[I386_ESI] = R_ESI;
    sigcontext->uc_mcontext.gregs[I386_EBP] = R_EBP;
    sigcontext->uc_mcontext.gregs[I386_ESP] = R_ESP;
    sigcontext->uc_mcontext.gregs[I386_EBX] = R_EBX;
    sigcontext->uc_mcontext.gregs[I386_EIP] = R_EIP;//emu->old_ip;   // old_ip should be more accurate as the "current" IP, but it's not always up-to-date
    // flags
    sigcontext->uc_mcontext.gregs[I386_EFL] = emu->eflags.x64;
    CLEAR_FLAG(F_TF);   // now clear TF flags inside the signal handler
    // get segments
    sigcontext->uc_mcontext.gregs[I386_CS] = R_CS;
    sigcontext->uc_mcontext.gregs[I386_DS] = R_DS;
    sigcontext->uc_mcontext.gregs[I386_ES] = R_ES;
    sigcontext->uc_mcontext.gregs[I386_SS] = R_SS;
    sigcontext->uc_mcontext.gregs[I386_FS] = R_FS;
    sigcontext->uc_mcontext.gregs[I386_GS] = R_GS;
    // get FloatPoint status
    sigcontext->uc_mcontext.fpregs = to_ptrv(xstate);//(struct x64_libc_fpstate*)&sigcontext->xstate;
    fpu_xsave_mask(emu, xstate, 1, 0b111);
    memcpy(&sigcontext->xstate, xstate, sizeof(sigcontext->xstate));
    ((struct i386_fpstate*)xstate)->status_magic = 0x46505853;   // magic number to signal an XSTATE type of fpregs
    // get signal mask

    if(new_ss) {
        sigcontext->uc_stack.ss_sp = to_ptrv(new_ss->ss_sp);
        sigcontext->uc_stack.ss_size = new_ss->ss_size;
        sigcontext->uc_stack.ss_flags = new_ss->ss_flags;
    } else
        sigcontext->uc_stack.ss_flags = SS_DISABLE;
    // Try to guess some X64_TRAPNO
    /*
    TRAP_x86_DIVIDE     = 0,   // Division by zero exception
    TRAP_x86_TRCTRAP    = 1,   // Single-step exception
    TRAP_x86_NMI        = 2,   // NMI interrupt
    TRAP_x86_BPTFLT     = 3,   // Breakpoint exception
    TRAP_x86_OFLOW      = 4,   // Overflow exception
    TRAP_x86_BOUND      = 5,   // Bound range exception
    TRAP_x86_PRIVINFLT  = 6,   // Invalid opcode exception
    TRAP_x86_DNA        = 7,   // Device not available exception
    TRAP_x86_DOUBLEFLT  = 8,   // Double fault exception
    TRAP_x86_FPOPFLT    = 9,   // Coprocessor segment overrun
    TRAP_x86_TSSFLT     = 10,  // Invalid TSS exception
    TRAP_x86_SEGNPFLT   = 11,  // Segment not present exception
    TRAP_x86_STKFLT     = 12,  // Stack fault
    TRAP_x86_PROTFLT    = 13,  // General protection fault
    TRAP_x86_PAGEFLT    = 14,  // Page fault
    TRAP_x86_ARITHTRAP  = 16,  // Floating point exception
    TRAP_x86_ALIGNFLT   = 17,  // Alignment check exception
    TRAP_x86_MCHK       = 18,  // Machine check exception
    TRAP_x86_CACHEFLT   = 19   // SIMD exception (via SIGFPE) if CPU is SSE capable otherwise Cache flush exception (via SIGSEV)
    */
    uint32_t prot = getProtection((uintptr_t)info->si_addr);
    uint32_t mmapped = memExist((uintptr_t)info->si_addr);
    uint32_t sysmapped = (info->si_addr<(void*)box64_pagesize)?1:mmapped;
    uint32_t real_prot = 0;
    int skip = 1;   // in case sigjump is used to restore exectuion, 1 will switch to interpreter, 3 will switch to dynarec
    if(prot&PROT_READ) real_prot|=PROT_READ;
    if(prot&PROT_WRITE) real_prot|=PROT_WRITE;
    if(prot&PROT_EXEC) real_prot|=PROT_WRITE;
    if(prot&PROT_DYNAREC) real_prot|=PROT_WRITE;
    sigcontext->uc_mcontext.gregs[I386_ERR] = 0;
    sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 0;
    if(sig==X64_SIGBUS)
        sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 17;
    else if(sig==X64_SIGSEGV) {
        if((uintptr_t)info->si_addr == sigcontext->uc_mcontext.gregs[I386_EIP]) {
            if(info->si_errno==0xbad0) {
                //bad opcode
                sigcontext->uc_mcontext.gregs[I386_ERR] = 0;
                sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 13;
                info2->si_code = 128;
                info2->si_errno = 0;
                info2->_sifields._sigfault.__si_addr = 0;
            } else if (info->si_errno==0xecec) {
                // no excute bit on segment
                sigcontext->uc_mcontext.gregs[I386_ERR] = 0x14|((sysmapped && !(real_prot&PROT_READ))?0:1);
                sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 14;
                if(!mmapped) info2->si_code = 1;
                info2->si_errno = 0;
            }else {
                sigcontext->uc_mcontext.gregs[I386_ERR] = 0x14|((sysmapped && !(real_prot&PROT_READ))?0:1);
                sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 14;
            }
        } else {
            sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 14;
            sigcontext->uc_mcontext.gregs[I386_ERR] = 4|((sysmapped && !(real_prot&PROT_READ))?0:1);
            if(write_opcode(sigcontext->uc_mcontext.gregs[I386_EIP], (uintptr_t)pc, 1))
                sigcontext->uc_mcontext.gregs[I386_ERR] |= 2;
        }
        if(info->si_code == SEGV_ACCERR && old_code)
            *old_code = -1;
        if(info->si_errno==0x1234) {
            sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 13;
            info2->si_errno = 0;
        } else if(info->si_errno==0xdead) {
            // INT x
            uint8_t int_n = info->si_code;
            info2->si_errno = 0;
            info2->si_code = 128;
            info2->_sifields._sigfault.__si_addr = 0;
            sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 13;
            skip = 3;   // can resume in dynarec
            // some special cases...
            if(int_n==3) {
                info2->si_signo = X64_SIGTRAP;
                sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 3;
                sigcontext->uc_mcontext.gregs[I386_ERR] = 0;
            } else if(int_n==0x04) {
                sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 4;
                sigcontext->uc_mcontext.gregs[I386_ERR] = 0;
            } else if (int_n==0x29 || int_n==0x2c || int_n==0x2d) {
                sigcontext->uc_mcontext.gregs[I386_ERR] = 0x02|(int_n<<3);
            } else {
                sigcontext->uc_mcontext.gregs[I386_ERR] = 0x0a|(int_n<<3);
                sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 13;
            }
        } else if(info->si_errno==0xcafe) { //divide by 0
            info2->si_errno = 0;
            sigcontext->uc_mcontext.gregs[I386_ERR] = 0;
            sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 0;
            info2->si_signo = X64_SIGFPE;
            skip = 3; // can resume in dynarec
        }
    } else if(sig==X64_SIGFPE) {
        if (info->si_code == FPE_INTOVF)
            sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 4;
        else
            sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 19;
        skip = 3;
    } else if(sig==X64_SIGILL) {
        info2->si_code = 2;
        sigcontext->uc_mcontext.gregs[I386_TRAPNO] = 6;
        info2->_sifields._sigfault.__si_addr = sigcontext->uc_mcontext.gregs[I386_EIP];
    } else if(sig==X64_SIGTRAP) {
        if(info->si_code==1) {  //single step
            info2->si_code = 2;
            info2->_sifields._sigfault.__si_addr = sigcontext->uc_mcontext.gregs[I386_EIP];
        } else
            info2->si_code = 128;
        sigcontext->uc_mcontext.gregs[I386_TRAPNO] = info->si_code;
        sigcontext->uc_mcontext.gregs[I386_ERR] = 0;
    } else {
        skip = 3;   // other signal can resume in interpretor
    }
    //TODO: SIGABRT generate what?
    printf_log((sig==10)?LOG_DEBUG:log_minimum, "Signal32 %d: si_addr=%p, TRAPNO=%d, ERR=%d, RIP=%p, prot:%x, mmaped:%d\n", sig, from_ptrv(info2->_sifields._sigfault.__si_addr), sigcontext->uc_mcontext.gregs[I386_TRAPNO], sigcontext->uc_mcontext.gregs[I386_ERR],from_ptrv(sigcontext->uc_mcontext.gregs[I386_EIP]), prot, mmapped);
    // call the signal handler
    i386_ucontext_t sigcontext_copy = *sigcontext;
    // save old value from emu
    #define GO(A) uint32_t old_##A = R_##A
    GO(EAX);
    GO(EDI);
    GO(ESI);
    GO(EDX);
    GO(ECX);
    GO(EBP);
    #undef GO
    // set stack pointer
    R_ESP = frame;
    // set frame pointer
    R_EBP = sigcontext->uc_mcontext.gregs[I386_EBP];

    int exits = 0;
    int ret;
    int dynarec = 0;
    #ifdef DYNAREC
    if(sig!=X64_SIGSEGV && !(Locks&is_dyndump_locked) && !(Locks&is_memprot_locked))
        dynarec = 1;
    #endif
    ret = RunFunctionHandler32(&exits, dynarec, sigcontext, my_context->signals[info2->si_signo], 3, info2->si_signo, info2, sigcontext);
    // restore old value from emu
    if(used_stack)  // release stack
        new_ss->ss_flags = 0;
    #define GO(A) R_##A = old_##A
    GO(EAX);
    GO(EDI);
    GO(ESI);
    GO(EDX);
    GO(ECX);
    GO(EBP);
    #undef GO

    if(memcmp(sigcontext, &sigcontext_copy, sizeof(i386_ucontext_t))) {
        if(emu->jmpbuf) {
            #define GO(R)   emu->regs[_##R].q[0]=sigcontext->uc_mcontext.gregs[I386_E##R]
            GO(AX);
            GO(CX);
            GO(DX);
            GO(DI);
            GO(SI);
            GO(BP);
            GO(SP);
            GO(BX);
            #undef GO
            if((skip==1) && (emu->ip.q[0]!=sigcontext->uc_mcontext.gregs[I386_EIP]))
                skip = 3;   // if it jumps elsewhere, it can resume with dynarec...
            emu->ip.q[0]=sigcontext->uc_mcontext.gregs[I386_EIP];
            // flags
            emu->eflags.x64=sigcontext->uc_mcontext.gregs[I386_EFL];
            // get segments
            #define GO(S) if(emu->segs[_##S]!=sigcontext->uc_mcontext.gregs[I386_##S])  emu->segs[_##S]=sigcontext->uc_mcontext.gregs[I386_##S]
            GO(CS);
            GO(DS);
            GO(ES);
            GO(SS);
            GO(GS);
            GO(FS);
            #undef GO
            for(int i=0; i<6; ++i)
                emu->segs_serial[i] = 0;
            printf_log((sig==10)?LOG_DEBUG:log_minimum, "Context has been changed in Sigactionhanlder, doing siglongjmp to resume emu at %p, RSP=%p (resume with %s)\n", (void*)R_RIP, (void*)R_RSP, (skip==3)?"Dynarec":"Interp");
            if(old_code)
                *old_code = -1;    // re-init the value to allow another segfault at the same place
            //relockMutex(Locks);   // do not relock mutex, because of the siglongjmp, whatever was running is canceled
            #ifdef DYNAREC
            if(Locks & is_dyndump_locked)
                CancelBlock64(1);
            #endif
            #ifdef RV64
            emu->xSPSave = emu->old_savedsp;
            #endif
            #ifdef ANDROID
            siglongjmp(*emu->jmpbuf, skip);
            #else
            siglongjmp(emu->jmpbuf, skip);
            #endif
        }
        printf_log(LOG_INFO, "Warning, context has been changed in Sigactionhanlder%s\n", (sigcontext->uc_mcontext.gregs[I386_EIP]!=sigcontext_copy.uc_mcontext.gregs[I386_EIP])?" (EIP changed)":"");
    }
    // restore regs...
    #define GO(R)   R_##R=sigcontext->uc_mcontext.gregs[I386_##R]
    GO(EAX);
    GO(ECX);
    GO(EDX);
    GO(EDI);
    GO(ESI);
    GO(EBP);
    GO(ESP);
    GO(EBX);
    #undef GO
    emu->eflags.x64=sigcontext->uc_mcontext.gregs[I386_EFL];
    #define GO(R)   R_##R=sigcontext->uc_mcontext.gregs[I386_##R]
    GO(CS);
    GO(DS);
    GO(ES);
    GO(SS);
    GO(GS);
    GO(FS);
    #undef GO

    printf_log(LOG_DEBUG, "Sigactionhanlder main function returned (exit=%d, restorer=%p)\n", exits, (void*)restorer);
    if(exits) {
        //relockMutex(Locks);   // the thread will exit, so no relock there
        #ifdef DYNAREC
        if(Locks & is_dyndump_locked)
            CancelBlock64(1);
        #endif
        exit(ret);
    }
    if(restorer)
        RunFunctionHandler32(&exits, 0, NULL, restorer, 0);
    relockMutex(Locks);
}

void my32_sigactionhandler(int32_t sig, siginfo_t* info, void * ucntx)
{
    #ifdef DYNAREC
    ucontext_t *p = (ucontext_t *)ucntx;
    #ifdef ARM64
    void * pc = (void*)p->uc_mcontext.pc;
    #elif defined(LA64)
    void * pc = (void*)p->uc_mcontext.__pc;
    #elif defined(RV64)
    void * pc = (void*)p->uc_mcontext.__gregs[0];
    #else
    #error Unsupported architecture
    #endif
    dynablock_t* db = FindDynablockFromNativeAddress(pc);
    #else
    void* db = NULL;
    #endif

    my_sigactionhandler_oldcode_32(NULL, sig, 0, info, ucntx, NULL, db);
}


EXPORT int my32_sigaction(x64emu_t* emu, int signum, const i386_sigaction_t *act, i386_sigaction_t *oldact)
{
    printf_log(LOG_DEBUG, "Sigaction(signum=%d, act=%p(f=%p, flags=0x%x), old=%p)\n", signum, act, act?from_ptrv(act->_u._sa_handler):NULL, act?act->sa_flags:0, oldact);
    if(signum<0 || signum>MAX_SIGNAL) {
        errno = EINVAL;
        return -1;
    }

    if(signum==X64_SIGSEGV && emu->context->no_sigsegv)
        return 0;

    if(signum==X64_SIGILL && emu->context->no_sigill)
        return 0;
    struct sigaction newact = {0};
    struct sigaction old = {0};
    uintptr_t old_handler = my_context->signals[signum];
    if(act) {
        newact.sa_mask = act->sa_mask;
        newact.sa_flags = act->sa_flags&~0x04000000;  // No sa_restorer...
        if(act->sa_flags&0x04) {
            my_context->signals[signum] = (uintptr_t)act->_u._sa_sigaction;
            my_context->is_sigaction[signum] = 1;
            if(act->_u._sa_handler!=0 && act->_u._sa_handler!=(ptr_t)1) {
                newact.sa_sigaction = my32_sigactionhandler;
            } else
                newact.sa_sigaction = from_ptrv(act->_u._sa_sigaction);
        } else {
            my_context->signals[signum] = (uintptr_t)act->_u._sa_handler;
            my_context->is_sigaction[signum] = 0;
            if(act->_u._sa_handler!=0 && act->_u._sa_handler!=(ptr_t)1) {
                newact.sa_flags|=0x04;
                newact.sa_sigaction = my32_sigactionhandler;
            } else
                newact.sa_handler = from_ptrv(act->_u._sa_handler);
        }
        my_context->restorer[signum] = (act->sa_flags&0x04000000)?(uintptr_t)act->sa_restorer:0;
        my_context->onstack[signum] = (act->sa_flags&SA_ONSTACK)?1:0;
    }
    int ret = 0;
    if(signum!=X64_SIGSEGV && signum!=X64_SIGBUS && signum!=X64_SIGILL && signum!=X64_SIGABRT)
        ret = sigaction(signal_from_x64(signum), act?&newact:NULL, oldact?&old:NULL);
    if(oldact) {
        oldact->sa_flags = old.sa_flags;
        oldact->sa_mask = old.sa_mask;
        if(old.sa_flags & 0x04)
            oldact->_u._sa_sigaction = to_ptrv(old.sa_sigaction); //TODO should wrap...
        else
            oldact->_u._sa_handler = to_ptrv(old.sa_handler);  //TODO should wrap...
        if(oldact->_u._sa_sigaction == to_ptrv(my32_sigactionhandler) && old_handler)
            oldact->_u._sa_sigaction = to_ptr(old_handler);
        oldact->sa_restorer = 0; // no handling for now...
    }
    return ret;
}
EXPORT int my32___sigaction(x64emu_t* emu, int signum, const i386_sigaction_t *act, i386_sigaction_t *oldact)
__attribute__((alias("my32_sigaction")));

EXPORT int my32_getcontext(x64emu_t* emu, void* ucp)
{
//    printf_log(LOG_NONE, "Warning: call to partially implemented getcontext\n");
    i386_ucontext_t *u = (i386_ucontext_t*)ucp;
    // stack traking
    u->uc_stack.ss_sp = 0;
    u->uc_stack.ss_size = 0;    // this need to filled
    // get general register
    u->uc_mcontext.gregs[I386_EAX] = R_EAX;
    u->uc_mcontext.gregs[I386_ECX] = R_ECX;
    u->uc_mcontext.gregs[I386_EDX] = R_EDX;
    u->uc_mcontext.gregs[I386_EDI] = R_EDI;
    u->uc_mcontext.gregs[I386_ESI] = R_ESI;
    u->uc_mcontext.gregs[I386_EBP] = R_EBP;
    u->uc_mcontext.gregs[I386_EIP] = *(uint32_t*)from_ptrv(R_ESP);
    u->uc_mcontext.gregs[I386_ESP] = R_ESP+4;
    u->uc_mcontext.gregs[I386_EBX] = R_EBX;
    // get segments
    u->uc_mcontext.gregs[I386_GS] = R_GS;
    u->uc_mcontext.gregs[I386_FS] = R_FS;
    u->uc_mcontext.gregs[I386_ES] = R_ES;
    u->uc_mcontext.gregs[I386_DS] = R_DS;
    u->uc_mcontext.gregs[I386_CS] = R_CS;
    u->uc_mcontext.gregs[I386_SS] = R_SS;
    // get FloatPoint status
    u->uc_mcontext.fpregs = to_ptrv(ucp + 236);    // magic offset of fpregs in an actual i386 u_context
    fpu_savenv(emu, from_ptrv(u->uc_mcontext.fpregs), 1);   // it seems getcontext only save fpu env, not fpu regs
    // get signal mask
    sigprocmask(SIG_SETMASK, NULL, (sigset_t*)&u->uc_sigmask);

    return 0;
}

EXPORT int my32_setcontext(x64emu_t* emu, void* ucp)
{
//    printf_log(LOG_NONE, "Warning: call to partially implemented setcontext\n");
    i386_ucontext_t *u = (i386_ucontext_t*)ucp;
    // stack tracking
    emu->init_stack = from_ptrv(u->uc_stack.ss_sp);
    emu->size_stack = from_ulong(u->uc_stack.ss_size);
    // set general register
    R_RAX = u->uc_mcontext.gregs[I386_EAX];
    R_RCX = u->uc_mcontext.gregs[I386_ECX];
    R_RDX = u->uc_mcontext.gregs[I386_EDX];
    R_RDI = u->uc_mcontext.gregs[I386_EDI];
    R_RSI = u->uc_mcontext.gregs[I386_ESI];
    R_RBP = u->uc_mcontext.gregs[I386_EBP];
    R_RIP = u->uc_mcontext.gregs[I386_EIP];
    R_RSP = u->uc_mcontext.gregs[I386_ESP];
    R_RBX = u->uc_mcontext.gregs[I386_EBX];
    // get segments
    R_GS = u->uc_mcontext.gregs[I386_GS];
    R_FS = u->uc_mcontext.gregs[I386_FS];
    R_ES = u->uc_mcontext.gregs[I386_ES];
    R_DS = u->uc_mcontext.gregs[I386_DS];
    R_CS = u->uc_mcontext.gregs[I386_CS];
    R_SS = u->uc_mcontext.gregs[I386_SS];
    // set FloatPoint status
    fpu_loadenv(emu, from_ptrv(u->uc_mcontext.fpregs), 1);
    // set signal mask
    sigprocmask(SIG_SETMASK, (sigset_t*)&u->uc_sigmask, NULL);

    errno = 0;
    return R_EAX;
}

void vFEv_32(x64emu_t *emu, uintptr_t fnc);
EXPORT void my32_start_context(x64emu_t* emu)
{
    // this is call indirectly by swapcontext from a makecontext, and will link context or just exit
    i386_ucontext_t *u = (i386_ucontext_t*)from_ptriv(R_EBX);
    if(u)
        my32_setcontext(emu, u);
    else
        emu->quit = 1;
}

EXPORT void my32_makecontext(x64emu_t* emu, void* ucp, void* fnc, int32_t argc, int32_t* argv)
{
//    printf_log(LOG_NONE, "Warning: call to unimplemented makecontext\n");
    i386_ucontext_t *u = (i386_ucontext_t*)ucp;
    // setup stack
    u->uc_mcontext.gregs[I386_ESP] = to_ptr(u->uc_stack.ss_sp + u->uc_stack.ss_size - 4);
    // setup the function
    u->uc_mcontext.gregs[I386_EIP] = to_ptrv(fnc);
    uint32_t* esp = (uint32_t*)from_ptr(u->uc_mcontext.gregs[I386_ESP]);
    // setup return to private start_context uc_link
    *esp = u->uc_link;
    u->uc_mcontext.gregs[I386_EBX] = (uintptr_t)esp;
    --esp;
    // setup args
    for (int i=0; i<argc; ++i) {
        // push value
        --esp;
        *esp = argv[(argc-1)-i];
    }
    // push the return value
    --esp;
    *esp = AddCheckBridge(my_context->system, vFEv_32, my32_start_context, 0, "my_start_context");//my_context->exit_bridge;//to_ptr(my_context->exit_bridge);
    u->uc_mcontext.gregs[I386_ESP] = (uintptr_t)esp;
}

EXPORT int my32_swapcontext(x64emu_t* emu, void* ucp1, void* ucp2)
{
//    printf_log(LOG_NONE, "Warning: call to unimplemented swapcontext\n");
    // grab current context in ucp1
    my32_getcontext(emu, ucp1);
    // activate ucp2
    my32_setcontext(emu, ucp2);
    return 0;
}