#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc,char**argv){ setbuf(stdout,NULL);
  const char*mode=argv[1]; const char*path=argv[2];
  int fd=open(path,O_RDONLY); struct stat st; fstat(fd,&st);
  size_t n=(st.st_size+16383)&~16383UL;
  void*p=mmap(NULL,n,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);
  if(p==MAP_FAILED){printf("mmap fail %d\n",errno);return 1;}
  /* parse mach-o: find __TEXT segment, mprotect it rx */
  unsigned int *hdr=p; unsigned int ncmds=hdr[4]; unsigned char *lc=(unsigned char*)(hdr+8);
  for(unsigned int i=0;i<ncmds;){
    unsigned int cmd=*(unsigned int*)lc; unsigned int size=*(unsigned int*)(lc+4);
    if(cmd==0x19){
      char seg[17]={0}; memcpy(seg,lc+8,16);
      unsigned long long vmaddr=*(unsigned long long*)(lc+24);
      unsigned long long vmsize=*(unsigned long long*)(lc+32);
      if(!strcmp(seg,"__TEXT")){
        unsigned long long off=vmaddr; /* vmaddr 0 for dylib */
        int r=mprotect((char*)p+off,(size_t)vmsize,PROT_READ|PROT_EXEC);
        printf("mprotect __TEXT %llx+%llx r=%d errno=%d\n",vmaddr,vmsize,r,errno);
      }
    }
    lc+=size; i+=size;
  }
  /* find symbol 'answer' in symtab */
  unsigned long long symoff=0,stroff=0; unsigned int nsyms=0;
  lc=(unsigned char*)(hdr+8);
  for(unsigned int i=0;i<ncmds;){
    unsigned int cmd=*(unsigned int*)lc; unsigned int size=*(unsigned int*)(lc+4);
    if(cmd==0x2){symoff=*(unsigned int*)(lc+8);nsyms=*(unsigned int*)(lc+12);stroff=*(unsigned int*)(lc+16);}
    lc+=size; i+=size;
  }
  void *ans=0; struct {unsigned int strx; unsigned char type,sect; unsigned short desc; unsigned long long value;} *sym=(void*)((char*)p+symoff);
  for(unsigned int i=0;i<nsyms;i++){
    const char*name=(char*)p+stroff+sym[i].strx;
    if(!strcmp(name,"_answer")) ans=(char*)p+sym[i].value;
  }
  printf("answer at %p\n",ans);
  int (*f)(void)=ans;
  printf("call -> %d\n",f());
  return 0;
}
