
//exceptionhandler routine for CE's {$try}/{$except} and jmp1 instructions
//Linux x86_64 version (todo: other systems)
#include <stdio.h>
#include <string.h>

typedef struct {
int bla;
} siginfo_t;

typedef void (*sa_sigaction) (int, siginfo_t *, void *);
typedef void (*sa_handler)(int);

#define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
  unsigned long int __val[_SIGSET_NWORDS];
} sigset_t;


struct sigaction
{
  /* Signal handler.  */
  void *handler;

  /* Additional set of signals to be blocked.  */
  sigset_t sa_mask; //128 bytes

  /* Special flags.  */
  int sa_flags; //if sa.sa_flags = SA_SIGINFO then sa_sigaction else sa_sighandler

  /* Restore handler.  */
  void (*sa_restorer) (void);
};

/* Bits in `sa_flags'.  */
#define	SA_NOCLDSTOP  1		 /* Don't send SIGCHLD when children stop.  */
#define SA_NOCLDWAIT  2		 /* Don't create zombie on child death.  */
#define SA_SIGINFO    4		 /* Invoke signal-catching function with three arguments instead of one.  */
#define SA_NODEFER	0x40000000

#define SIG_IGN         (void*)1
#define SIG_DFL         (void*)0

#define	SIGILL		4	/* Illegal instruction.  */
#define SIGTRAP		5
#define	SIGSEGV		11	/* Invalid access to storage.  */


int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
int sigemptyset(sigset_t *set);
int raise(int sig);
void * signal(int signum, void *handler);



int debugnr=0;
int exceptioncount=0;

/*

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



struct ucontext {
	unsigned long	  uc_flags;
	void* uc_link;
	stack_t		  uc_stack;
	struct sigcontext uc_mcontext;
};
*/

struct sigaction originalhandlersigtrap;
struct sigaction originalhandlersigill;
struct sigaction originalhandlersigsegv;


typedef struct
{
    unsigned long long origin;  ///tryaddress
    unsigned long long destination; //exceptionaddress
    unsigned long long entrytype; //0=changerip, 1=exception handler
} RedirectEntry, *PRedirectEntry;

typedef struct
{
  PRedirectEntry newList;
  int newListSize;
} *PNewListInfo;

static PRedirectEntry List = NULL;
static int ListSize = 0;


typedef struct
{
  char rwlockdata[64];
} pthread_rwlock_t;

pthread_rwlock_t RedirectMREW;// init to 0;

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

static void callOriginalHandler(struct sigaction *originalhandler, int signo, siginfo_t *info, void *ucontextRaw)
{

  //printf("callOriginalHandler(%d)\n",signo);
  if (originalhandler->handler)            
  {
    if (originalhandler->handler == SIG_IGN)
    {
     // printf("ignore\n");
      return;
    }
    
   // printf("calling original handler\n");
    if ((originalhandler->sa_flags & SA_SIGINFO)==SA_SIGINFO)
    {
      sa_sigaction bla=(sa_sigaction)(originalhandler->handler);
      bla(signo, info, ucontextRaw);
    }
    else
    {
      sa_handler bla=(sa_handler)(originalhandler->handler);
      bla(signo);
    }
  }
  else
  {
    //printf("there was no handler\n");
    signal(signo, SIG_DFL);
    raise(signo);
  }
}

unsigned long long getRedirect(unsigned long long currentAddress)
{
    unsigned long long result = 0;

    pthread_rwlock_rdlock(&RedirectMREW);

    for (int i = 0; i < ListSize; ++i)
    {
        if ((List[i].entrytype==1) && (List[i].origin == currentAddress))
        {
            result = List[i].destination;
            break;
        }
    }

    pthread_rwlock_unlock(&RedirectMREW);

    return result;
}

void setList(PNewListInfo nli)
{
  //printf("setList\n");
  pthread_rwlock_wrlock(&RedirectMREW);
  List=nli->newList;
  ListSize=nli->newListSize;
  pthread_rwlock_unlock(&RedirectMREW);
}

int ListHandlerException(void *ucontextRaw)
{
  int handled=0;
  unsigned long long closestEntry=-1;
  int i;

  //printf("ListHandlerException\n");

  unsigned long long ctx = (unsigned long long)ucontextRaw;

  unsigned long long ripaddressaddress=ctx+16+20+4+16*sizeof(unsigned long long); //RIP_REG is 16
  unsigned long long ripaddress=*(unsigned long long*)ripaddressaddress;
  ripaddress--;
  
 // printf("RIP=%llx\n", ripaddress);
  
 // printf("ListSize=%d\n",ListSize);
  
  
    
  
  pthread_rwlock_rdlock(&RedirectMREW);
  for (i=0; i<ListSize; i++)
  {
    if ((List[i].entrytype==0) && (ripaddress>=List[i].origin) && (ripaddress<=List[i].destination))
    {
      //RIP falls within this range
      int distance=ripaddress-List[i].origin;
      if (closestEntry==-1)
        closestEntry=i;
      else
      {
        int olddistance=ripaddress-List[closestEntry].origin;
        if (distance<olddistance)
          closestEntry=i;
      }     
    }    
  }
  if (closestEntry!=-1)
  {
    *(unsigned long long*)ripaddressaddress=List[closestEntry].destination;
    handled=1;    
  }
  pthread_rwlock_unlock(&RedirectMREW);
  return handled;
}

void SIGILLHandler(int signo, siginfo_t *info, void *ucontextRaw)
{
//  printf("SIGILLHandler\n");
  int handled=ListHandlerException(ucontextRaw);
  
  if (handled==0)
    callOriginalHandler(&originalhandlersigill, signo, info, ucontextRaw);
}

void SIGSEGVHandler(int signo, siginfo_t *info, void *ucontextRaw)
{
  int handled;
//  printf("SIGSEGVHandler\n");
  handled=ListHandlerException(ucontextRaw);
  
  if (handled==0)
    callOriginalHandler(&originalhandlersigsegv, signo, info, ucontextRaw);
}


void Int3Handler(int signo, siginfo_t *info, void *ucontextRaw)
{
 // printf("Int3Handler");
  exceptioncount++;

  if (signo==SIGTRAP)
  {
    unsigned long long ctx = (unsigned long long)ucontextRaw;

    unsigned long long ripaddressaddress=ctx+16+20+4+16*sizeof(unsigned long long); //RIP_REG is 16
    unsigned long long ripaddress=*(unsigned long long*)ripaddressaddress;
    ripaddress--;

    unsigned long long newrip=getRedirect(ripaddress);
    if (newrip)
    {
      *(unsigned long long*)ripaddressaddress=newrip;
      return;
    }

  }

  callOriginalHandler(&originalhandlersigtrap, signo, info, ucontextRaw);

}

void registereh()
{
  debugnr=1;
  struct sigaction sa,saSIGILL,saSIGSEGV;
  memset(&sa, 0, sizeof(sa));

  sa.handler = Int3Handler;  //sa_sigaction
  sa.sa_flags = SA_SIGINFO | SA_NODEFER;

  sigemptyset(&sa.sa_mask);
  sigaction(SIGTRAP, &sa, &originalhandlersigtrap);


  saSIGILL.handler = SIGILLHandler;
  saSIGILL.sa_flags = SA_SIGINFO | SA_NODEFER;

  sigemptyset(&saSIGILL.sa_mask);
  sigaction(SIGILL, &saSIGILL, &originalhandlersigill);


  saSIGSEGV.handler = SIGSEGVHandler;
  saSIGSEGV.sa_flags = SA_SIGINFO | SA_NODEFER;

  sigemptyset(&saSIGSEGV.sa_mask);
  sigaction(SIGSEGV, &saSIGSEGV, &originalhandlersigsegv);


  debugnr=2;
}

