#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <stdatomic.h>
#include <sys/mman.h>
#include <stdint.h>

#include "common.h"

#if defined(__x86_64__)

#define INSN_ENDBR64 0xf3, 0x0f, 0x1e, 0xfa

/* Skip the ULP prologue of a function, so that when 'func' is called it runs
   its original code.  This should save us from including libc headers and copy
   & pasting code from libc itself.  */
void *call_old_func(void *p1, void *p2, void *p3, void *p4,
                           void *p5, void *p6, void *func)
{
  /* Check if function contain the jump trampoline.  */

  const unsigned char *as_bytes = (const unsigned char *) func;
  const unsigned char insn_endbr64[] = {INSN_ENDBR64};
  unsigned int i;
  int bias = 0;
  void *(*ptr)(void *, void *, void *, void *, void *, void *);

  for (i = 0; i < sizeof(insn_endbr64); i++) {
    if (as_bytes[i] != insn_endbr64[i])
      break;
  }

  if (i == sizeof(insn_endbr64)) {
    /* Comparison successful.  */
    as_bytes += sizeof(insn_endbr64);
    bias += sizeof(insn_endbr64);
  }

  if (as_bytes[0] != 0xEB) {
    /* JMP rel8 opcode not found. Function definitely not livepatched.
       Check if it is livepatchable*/

    if (as_bytes[1] == 0x90) {
      if (as_bytes [0] == 0x90 || as_bytes[0] == 0x66) {
        printf("Function not livepatched\n");
        goto add;
      }
    }

    printf("Function not livepatchable. Patching it would break the application\n");
    abort();
  }

  /* On x86_64, the JMP insns used for redirecting the old function
     into the new one takes 2 bytes.  So add 2 bytes to skip it.  */
add:
  ptr = add_long_to_ptr(func, 2 + bias);
  return ptr(p1, p2, p3, p4, p5, p6);
}

#elif defined(__powerpc64__)
/* For the powerpc64le version, check common_ppc64le.c.in and common_ppc64le.S.  */
#endif
