/********************************************************************** * * ptrace breakpoint instruction x86 i386 i686 ia64 ia-64 SIGSTOP * ELF * * Only tested on Linux. * * This example program is part of several examples that I developed * to explore ptrace functionality. They are here to serve as * examples (possibly bad examples :) and are not intended to be * useful on their own. * * This program does the following: * * - checks that it's an ELF executable * - gets the address (addr) of the beginning if user code * - sets a breakpoint instruction at 'addr' in a running process * - continues the process until the breakpoint is hit * - removes the breakpoint by restoring the original intruction * - stops the process by sending a SIGSTOP signal * - detaches from the process * * After this program exits, the process still exists and can be * attached to using a debugger like gdb. On linux the 'ps' command * will show the process number of this process. * * This has been tested on linux ia32 and linux ia64. * * This example only serves to educate those that want to know * more about how to do this. * * Comments and questions can be sent to TMacD. * tmacd@evia.com * * Last modified: 2-June-2006 * **********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include enum archs { Neither, Script, Ia32, Ia64 }; /* Relevant architectures */ #ifdef __ia64__ # include # define INST_LEN 16 /* Instruction length */ # define BP_INST 0x00003333300UL /* Breakpoint instruction */ # define INST_BIT_LEN ((INST_LEN) * 8) /* Instruction bit length */ typedef Elf64_Ehdr Elf_Ehdr; #elif __i386__ # define INST_LEN sizeof(long) /* Instruction length */ # define BP_INST 0xcc /* Breakpoint instruction */ typedef Elf32_Ehdr Elf_Ehdr; #else # error unknown architecture #endif #define INST_BIT_LEN ((INST_LEN) * 8) /* Instruction bit length */ #if __ia64__ /* An instruction bundle is 128-bits and can contain up to * three 41-bit instructions. The format is: * * --------------------------------------------- * fields: | instr 1 | instr 2 | instr 3 | template | * |----------+----------+----------+----------| * bits: | 127 - 87 | 86 - 46 | 45 - 5 | 4 - 0 | * --------------------------------------------- * * The 'template' field is used to dispatch the instructions to * different hardware units. Templates can alse encode a 'stop' * after an instruction in a bundle to break parallel instruction * execution. See the 'template_list' below. * * * An instruction has three operand fields for immediate values or * register numbers. Some instructions combine all three operands * into a single 21-bit immediate value, and some instructions * append the following complete 41-bit instruction to form a * 64-bit immediate value (L+X instructions). * * In general a 41-bit instruction has the format: * * ------------------------------------------------------------- * | opcode | operand 1 | operand 2 | operand 3 | predicate | * |-----------+-----------+-----------+-----------+-----------| * | 40 - 27 | 26 - 20 | 19 - 13 | 12 - 6 | 5 - 0 | * ------------------------------------------------------------- * * The predicate field specifies a predicate register. Each * predicate register represents either 'true' or 'false' * and if 'false' then the instruction becomes a no-op. * Some instructions cannot be predicated. Complicated beast! */ typedef enum instr_type { A, /* ALU Integer: I-unit or M-unit */ I, /* non-ALU integer: I-unit */ M, /* memory: M-unit */ F, /* floating-point: F-unit */ B, /* branch: B-unit */ L, /* extended (L+X): extended I-unit */ X, /* extended (L+X): extended I-unit */ reserved /* reserved */ } instr_type; /* There are different instruction types, grouped by the hardware unit * they need. Only certain combinations are allowed in a single * bundle. See type 'instr_type' for the various instruction types. * The 'X' may contain both the break.i and noop.i instructions. * * A '|' represents a 'stop' that breaks parallel instruction execution. * */ static enum instr_type template_list[32][3] = { { M, I, I }, /* 00 */ { M, I, I /* | */ }, /* 01 */ { M, I, /* | */ I }, /* 02 */ { M, I, /* | */ I /* | */ }, /* 03 */ { M, L, X }, /* 04 */ { M, L, X /* | */ }, /* 05 */ { reserved, reserved, reserved }, /* 06 */ { reserved, reserved, reserved }, /* 07 */ { M, M, I }, /* 08 */ { M, M, I /* | */ }, /* 09 */ { M, /* | */ M, I }, /* 0A */ { M, /* | */ M, I /* | */ }, /* 0B */ { M, F, I }, /* 0C */ { M, F, I /* | */ }, /* 0D */ { M, M, F }, /* 0E */ { M, M, F /* | */ }, /* 0F */ { M, I, B }, /* 10 */ { M, I, B /* | */ }, /* 11 */ { M, B, B }, /* 12 */ { M, B, B /* | */ }, /* 13 */ { reserved, reserved, reserved }, /* 14 */ { reserved, reserved, reserved }, /* 15 */ { B, B, B }, /* 16 */ { B, B, B /* | */ }, /* 17 */ { M, M, B }, /* 18 */ { M, M, B /* | */ }, /* 19 */ { reserved, reserved, reserved }, /* 1A */ { reserved, reserved, reserved }, /* 1B */ { M, F, B }, /* 1C */ { M, F, B /* | */ }, /* 1D */ { reserved, reserved, reserved }, /* 1E */ { reserved, reserved, reserved }, /* 1F */ }; #endif /* __ia64__ */ /* Type for an instruction word address */ typedef unsigned long addr_t; static int debug = 1; static enum archs this_arch = Neither; static struct utsname mach_name; static int advance_pid(int, addr_t); addr_t check_application(const char *); /* * main - fork/exec an application, set a breakpoint in child, * continue to that breakpoint, detach from child. * * Only tested on redhat linux ia32 and redhat linux ia64 systems. */ int main(int argc, char *argv[]) { pid_t pid, cpid; char *p = NULL; int status = -1; addr_t addr = 0; char app_path[256] = { '\0' }; char *usage = "Usage: %s application\n"; if (argc != 2) { printf(usage, argv[0]); return 1; } if (uname(&mach_name) == 0) { /* Which architecture is this? */ p = mach_name.machine; if (strcmp(p, "i386") == 0 || strcmp(p, "i686") == 0) { this_arch = Ia32; } else if (strcmp(p, "ia64") == 0) { this_arch = Ia64; } } else { perror("unknwon architecture"); return 1; } strncpy(app_path, argv[1], 255); /* Check if this is an ELF executable and get 'addr', start of user code. */ if ((addr = check_application(app_path)) == 0) { return 1; } if (debug) { printf("Set breakpoint instruction at addr %#lx in application '%s'\n", addr, app_path); printf("Executing on architecture %s\n", p); } if ((pid = fork()) == -1) { perror("fork failed"); return 1; } /* Child process */ if (pid == 0) { if (debug) printf("Child process ready to execl\n"); fflush(stdout); ptrace(PTRACE_TRACEME, 0, NULL, NULL); execl(app_path, app_path, NULL); fprintf(stderr, "Should not get here, execl failed\n"); exit(2); } /* Parent process */ if ((cpid = waitpid(pid, &status, WUNTRACED)) != pid) { char errstr[255]; sprintf(errstr, "attach waitpid value is %d", (int) cpid); perror(errstr); } if (cpid != pid) { printf("Incorrect value (%d) returned from waitpid\n", (int) cpid); ptrace(PTRACE_DETACH, pid, NULL, NULL); return 1; } if (debug) printf("status %#x from child pid %d return value is %d\n", status, (int) pid, (int) cpid); fflush(stdout); /* advance the process to the beginning of user code */ if (! advance_pid(pid, addr)) { /* advance_pid takes care of the PTRACE_DETACH */ return 1; } return 0; } /* Read a word from the child process */ static int readWord(int pid, addr_t aligned_addr, addr_t *val) { if (val == NULL) { printf("cannot save word to NULL location\n"); exit(1); } errno = 0; *val = ptrace(PTRACE_PEEKDATA, pid, aligned_addr, 0); if (errno != 0) perror("ptrace peekdata"); /* Warning - 2's complement assumed! */ /* Value can be -1, so check errno to see if there is a failure. */ return (*val != ~0UL || errno == 0); } /* readWord */ /* Write a word into the child process */ static int writeWord(int pid, addr_t aligned_addr, addr_t val) { int res = ptrace(PTRACE_POKEDATA, pid, aligned_addr, val); if (res != 0) perror("ptrace pokedata"); return (res == 0); } /* writeWord */ #if __i386__ /*** *** IA-32 specific functions for setting a breakpoint in a *** 32-bit instruction. *** ***/ /* Read the Program Counter register of the child process */ static addr_t readPC(int pid) { addr_t r[17]; /* 17 registers on ia32 */ if (ptrace(PTRACE_GETREGS, pid, NULL, r) != 0) { perror("readPC ptrace getregs"); return 0; } return r[12]; } /* readPC */ /* Write a new Program Counter value to the child process */ static int writePC(int pid, addr_t newpc) { addr_t r[17]; /* 17 registers on ia32 */ if (ptrace(PTRACE_GETREGS, pid, NULL, &r) != 0) { perror("writePC ptrace getregs"); return 0; } r[12] = newpc; if (ptrace(PTRACE_SETREGS, pid, NULL, &r) != 0) { perror("writePC ptrace setregs"); return 0; } return 1; } /* writePC */ /* * Swap the instruction (1 byte for ia32) in 'new_val' with the current value * in the location given by 'addr'. Works with unaligned addresses (which * can happen on ia32). Return the swapped out instruction in '*old_val'. */ static int swapMemory(int pid, addr_t addr, addr_t new_val, addr_t *old_val) { const addr_t byte_offset = addr & 0x3; /* instruction offset */ const addr_t bit_shift_count = byte_offset * 8; const addr_t mask = 0xFF << bit_shift_count; if (old_val == NULL) { printf("cannot save instruction to NULL location"); exit(1); } addr &= ~0x3UL; /* clear rightmost 2 bits - word aligned */ if (! readWord(pid, addr, old_val)) { return 0; } if (debug) printf("Original instruction word is %#lx\n", *old_val); /* Swap the instructions. */ new_val = (*old_val & ~mask) | (new_val << bit_shift_count); *old_val = (*old_val & mask) >> bit_shift_count; /* Write modified instruction word back to child process */ if (! writeWord(pid, addr, new_val)) { return 0; } if (debug) printf("New instruction word is %#lx\n", new_val); return 1; } /* swapMemory */ #elif __ia64__ /*** *** IA-64 specific functions for setting a breakpoint in a *** 128-bit instruction bundle. *** ***/ /* For debugging - convert instruction type to a name */ static char instr_type_to_name(instr_type it) { static const char names[] = { 'A', 'I', 'M', 'F', 'B', 'L', 'X', 'R' }; return (it < A || it > reserved) ? '?' : names[it]; } /* Read a 128-bit bundle from the child process. */ static int readBundle(int pid, addr_t aligned_addr, char *bundle) { unsigned long val = 0; if (bundle == NULL) { printf("cannot save bundle to NULL location\n"); exit(1); } if (! readWord(pid, aligned_addr, &val)) { return 0; } memcpy(bundle, &val, sizeof(val)); if (! readWord(pid, aligned_addr + sizeof(val), &val)) { return 0; } memcpy(bundle + sizeof(val), &val, sizeof(val)); return 1; } /* read Bundle */ /* Write a 128-bit bundle to the child process. */ static int writeBundle(int pid, unsigned long aligned_addr, char *bundle) { unsigned long val; if (bundle == NULL) { printf("cannot save bundle from NULL location\n"); exit(1); } memcpy(&val, bundle, sizeof(val)); if (! writeWord(pid, aligned_addr, val)) { return 0; } memcpy(&val, bundle + sizeof(val), sizeof(val)); if (! writeWord(pid, aligned_addr + sizeof(val), val)) { return 0; } return 1; } /* writeBundle */ /* Read 'len' bits from 'bundle' starting at bit 'first_bit'. Store * the unsigned result in '*result'. 'len' must be in the range [1..64] * and "first-bit + len" must not exceed 128 (number of bits in a bundle). */ static int read_bundle_bits(const unsigned char *bundle, unsigned first_bit, unsigned len, long *result) { unsigned long res = 0L; const unsigned first_byte = first_bit >> 3; const unsigned fbib = first_bit & 0x7; /* first bit in byte */ const unsigned lim_bit = first_bit + len; const unsigned lim_byte = lim_bit >> 3; const unsigned lbib = lim_bit & 0x7; /* lim bit in byte */ const unsigned up_shift = 8 - lbib; unsigned char bits; unsigned lshift; int i; if (bundle == NULL || len ==0 || len > 64 || first_bit + len > INST_BIT_LEN || result == NULL) { printf("bad inputs detected for instruction read\n"); return 0; } bits = bundle[first_byte]; if (first_byte == lim_byte) { bits = ((bits << up_shift) & 0xFF) >> up_shift; } res = bits >> fbib; lshift = 8 - fbib; for (i = first_byte+1; i < lim_byte; i++) { res |= (unsigned long) bundle[i] << lshift; lshift += 8; } /* Check 'lbib' because 'lim_bit' might be one past the last bit in bundle */ if (first_byte < lim_byte && lbib != 0) { bits = ((bundle[lim_byte] << up_shift) & 0xFF) >> up_shift; res |= (unsigned long) bits << lshift; } *result = res; return 1; } /* read_bundle_bits */ /* Store 'len' bits into 'bundle' starting at bit 'first_bit'. * 'len' must be in the range [1..64] and "first-bit + len" * must not exceed 128 (number of bits in a bundle). */ static int store_bundle_bits(char *bundle, unsigned first_bit, unsigned len, unsigned long val) { const unsigned first_byte = first_bit >> 3; const unsigned fbib = first_bit & 0x7; /* first bit in byte */ const unsigned lim_bit = first_bit + len; const unsigned lbib = lim_bit & 0x7; /* lim bit in byte */ const unsigned lim_byte = lim_bit >> 3; const unsigned b_shift = 8 - fbib; const unsigned v_shift = 8 - lbib; int i; if (bundle == NULL || len == 0 || len > 64 || first_bit + len > INST_BIT_LEN) { printf("bad inputs detected for instruction store\n"); return 0; } if (first_byte == lim_byte) { unsigned char bits = val & 0xFF; unsigned char mask = (0xFF << (fbib + v_shift)) >> v_shift; /* shift the 'val' bits into the appropriate position */ bits = (bits << (fbib + v_shift)) >> v_shift; /* scalar merge: (mask-bit == 1 ? bundle-bit : val-bit) */ bits = (bundle[first_byte] & ~mask) | (bits & mask); bundle[first_byte] = bits; return 1; } bundle[first_byte] = (bundle[first_byte] << b_shift) >> b_shift; bundle[first_byte] |= val << fbib; val >>= b_shift; for (i = first_byte+1; i < lim_byte; i++) { bundle[i] = val & 0xFF; val >>= 8; } /* for */ if (lbib != 0) { val &= 0xFF; bundle[lim_byte] = (bundle[lim_byte] >> lbib) << lbib; bundle[lim_byte] |= ((val << v_shift) & 0xFF) >> v_shift; } return 1; } /* store_bundle_bits */ /* Store an instruction into an instruction bundle at location 'inum' */ static int store_instN_into_bundle(char *bundle, int inum) { int res; if (bundle == NULL) { printf("cannot store instruction into NULL location\n"); exit(1); } /* 5 template bits + three 41 instruction bits */ res = store_bundle_bits(bundle, 5+41*inum, 41, BP_INST); return res; } /* store_instN_into_bundle */ /* read instruction number 'inum' from 'bundle' */ static long read_instN_from_bundle(const unsigned char *bundle, int inum) { long result; if (bundle == NULL) { printf("cannot read instruction from NULL location\n"); exit(1); } /* 5 template bits + three 41 instruction bits */ if (! read_bundle_bits(bundle, 5+41*inum, 41, &result)) { return 0; } return result; } /* read_instN_from_bundle */ /* For debugging - print a bundle of instructions */ void prt_bundle(const char *pb, addr_t addr) { int i; unsigned char *p = (unsigned char *) pb; unsigned long *bndl = (unsigned long *) pb; if (p == NULL) { return; } printf("Instruction bundle = [ %#lx ][ %#lx ]\n\n",bndl[0], bndl[1]); printf("%lx:\t", addr); for (i = 0; i < 8; i++) { printf("%.2x ", p[i]); } printf("\n%lx:\t", addr+8); for (i = 8; i < 16; i++) { printf("%.2x ", p[i]); } printf("\n\n"); return; } /* prt_bundle */ /* For debugging - read and (partially) decode an instruction at 'addr' and return the address of the next instruction. */ static unsigned long read_instr(addr_t addr, char *bundle) { instr_type inst_temp; unsigned long instr; long template; unsigned inum = addr & 0xF; /* instruction number in bundle */ if (bundle == NULL || addr == 0) { printf("Incorrect arguments passed to function read_instr\n"); return 0; } /* Error if instruction number greater than 2. */ if (inum > 2) { printf("Instruction number %d requested but cannot read " "instructions for numbers greater than 2.\n", inum); return 0; } addr &= ~0xfUL; /* align address */ if ((instr = read_instN_from_bundle(bundle, inum)) == 0) { printf("Error reading instruction number %d in bundle\n", inum); } /* The 5 template bits are the 5 lowest bits */ if (! read_bundle_bits(bundle, 0, 5, &template)) { printf("Error reading template from bundle\n"); template = 0; } inst_temp = template_list[(int)template][inum]; printf("read_instr: inst# %d, instr=%#lx, template=%#lx, inst_temp=%c\n", inum, instr, template, instr_type_to_name(inst_temp)); addr += (inum==2 || (inum==1 && inst_temp==L)) ? INST_LEN : inum+1; return addr; } /* read_instr */ #endif /* __ia64__ */ /* Insert a breakpoint instruction into the instruction word (ia32) or the instruction bundle (ia64). Return the original instruction (ia3) or original bundle (ia32) so it can be restored later. */ static int insert_breakpoint(int pid, addr_t addr, void *save_instruction) { int res = 1; #if __i386__ if (! swapMemory(pid, addr, BP_INST, save_instruction)) { return 0; } #elif __ia64__ char bundle[INST_LEN]; unsigned inum = addr & 0xF; /* instruction number in bundle */ if (save_instruction == NULL) { printf("cannot save instruction to NULL location"); exit(1); } if (inum > 2) { printf("invalid instruction number %d found\n", inum); return 0; } if (! readBundle(pid, addr, bundle)) { perror("readBundle"); return 0; } if (debug) { addr_t temp; printf("Inserting breakpoint in instruction at %#lx\n", addr); prt_bundle(bundle, addr); temp = read_instr(addr, bundle); } memcpy(save_instruction, bundle, INST_LEN); res = store_instN_into_bundle(bundle, inum); if (debug) { addr_t temp; printf("Breakpoint set, instruction 0, bundle at addr %#lx\n", addr); prt_bundle(bundle, addr); temp = read_instr(addr, bundle); } if (! writeBundle(pid, addr, bundle)) { perror("set breakpoint"); ptrace(PTRACE_DETACH, pid, NULL, NULL); return 0; } #endif return res; } /* insert_breakpoint */ /* Replace a breakpoint instruction with the original instruction (ia32) * or the original instruction bundle (ia64). */ static int remove_breakpoint(int pid, addr_t addr, void *save_instruction) { #if __i386__ addr_t dummy; long *inst = save_instruction; if (inst == NULL) { printf("null instruction, cannot replace breakpoint\n"); exit(1); } if (! swapMemory(pid, addr, *inst, &dummy)) { return 0; } #elif __ia64__ /* 'writeBundle' checks to see there is a NULL pointer */ if (! writeBundle(pid, addr, save_instruction)) { perror("remove breakpoint"); return 0; } #endif return 1; } /* remove_breakpoint */ /* Check to see if child process hit the breakpoint instruction. * ia64 and ia32 are very different beasts. */ static int check_bp(int pid, addr_t addr) { #if __i386__ int i = 0; int sz; addr_t PCaddr = readPC(pid); if (PCaddr == 0) { return 0; /* Error - bad PC address */ } sz = sizeof(addr_t); for (i = -1; i < sz; i++) { if (PCaddr + i == addr) { if (debug) printf("Breakpoint hit=%#lx\n", PCaddr); break; /* Success at hitting the breakpoint. */ } } /* Adjust if not exact instruction address match */ if (i != 0 && i < sz) { if (debug) printf("Updating PC addr to be %#lx\n", addr); if (! writePC(pid, addr)) { return 0; /* Error writing new PC value */ } } /* Make sure we hit the breakpoint */ if (i==sz) printf("missed breakpoint: PCaddr=%#lx, addr=%#lx\n", PCaddr, addr); return (i < sz); #elif __ia64__ long IP; errno = 0; IP = ptrace(PTRACE_PEEKUSER, pid, PT_CR_IIP, NULL); if (IP == -1 && errno != 0) { perror("ptrace peekuser"); return 0; } if (IP != addr) { printf("missed breakpoint: IP=%#lx, addr=%#lx\n", IP, addr); return 0; } if (debug) printf("Breakpoint hit=%#lx\n", IP); return 1; #endif return 0; } /* check_bp */ /* Check the status returned by 'waitpid' */ static int check_status(int status) { if (WIFEXITED(status)) { printf("error, child pid exit status=%d\n", WEXITSTATUS(status)); return 0; } if (WIFSIGNALED(status)) { printf("child pid uncaught signal=%d\n", WTERMSIG(status)); } else if (! WIFSTOPPED(status)) { /* Make sure we stopped on breakpoint instruction */ printf("child pid not stopped, status=%#x\n", status); } else if (WSTOPSIG(status) != SIGTRAP) { printf("child pid WSTOPSIG(status)=%d\n", WSTOPSIG(status)); } return 1; } /* check_status */ /* Advance the child process to the breakpoint instruction */ static int cont_to_bp(int pid, addr_t addr) { int cpid; int status = 0; if (ptrace(PTRACE_CONT, pid, NULL, NULL) != 0) { perror("ptrace continue"); return 0; } /* wait for pid to stop */ if ((cpid = waitpid(pid, &status, WUNTRACED)) != pid) { char errstr[128] = { 0 }; sprintf(errstr, "continue waitpid %d", (int)cpid); perror(errstr); return 0; } if (! check_status(status)) { return 0; } status = check_bp(pid, addr); return status; } /* cont_to_bp */ /* * advance_pid performs the following steps: * * Insert breakpoint instruction at 'addr' (and save original instruction) * Continue child process * When child process halts, verify it's at the breakpoint instruction * Restore original instruction back into instruction stream of child process * Send a SIGSTOP signal to child process. * Detach from child process * * Process is now in a stopped state, ready for debugger/strace, etc. */ static int advance_pid(int pid, addr_t addr) { char instruction[INST_LEN]; void *save_instruction = instruction; /* Insert a breakpoint at location 'addr' */ if (! insert_breakpoint(pid, addr, save_instruction)) { ptrace(PTRACE_DETACH, pid, NULL, NULL); return 0; } if (debug) printf("Breakpoint set at addr %#lx\n", addr); /* Continue child pid to breakpoint */ if (! cont_to_bp(pid, addr)) { ptrace (PTRACE_DETACH, pid, NULL, NULL); return 0; } /* Restore the original instruction */ if (! remove_breakpoint(pid, addr, save_instruction)) { ptrace(PTRACE_DETACH, pid, NULL, NULL); return 0; } if (debug) printf("Breakpoint Removed at %#lx\n", addr); /* Pause launched application */ if (kill(pid, SIGSTOP) < 0) { perror("kill"); } if (ptrace(PTRACE_DETACH, pid, NULL, NULL) != 0) { perror("ptrace attach"); return 0; } return 1; } /* advance_pid */ /* Return Ia32, Ia64, or Neither */ enum archs elf_architecture(const Elf_Ehdr *e_hdr) { Elf32_Half mach; if (memcmp(e_hdr->e_ident, ELFMAG, SELFMAG) != 0) { return Script; /* not an ELF file */ } if (e_hdr->e_type != ET_EXEC) { return Neither; /* Not an executable file */ } mach = e_hdr->e_machine; return (mach==EM_386 ? Ia32 : (mach==EM_IA_64 ? Ia64 : Neither)); } /* elf_architecture */ /* Read the ELF header form the executable. */ int read_ELF_header(Elf_Ehdr *e_hdr, FILE *fp) { const int Ehdr_sz = sizeof(Elf_Ehdr); size_t sz = fread(e_hdr, 1, Ehdr_sz, fp); return (sz == Ehdr_sz); /* Wrong size means not ELF */ } /* read_ELF_header */ /* * Advance all the pids assigned to this launched application * if there is dynamic linking. */ addr_t check_application(const char *app_path) { FILE *fp = NULL; addr_t addr = 0; enum archs app_arch = Neither; Elf_Ehdr e_hdr; if (app_path == NULL) { return 0; /* Not a dynamic ELF execuatble */ } if ((fp = fopen(app_path, "rb")) == NULL) { perror("cannot open application"); return 0; /* Cannot find application */ } if (read_ELF_header(&e_hdr, fp) == 0 || (app_arch = elf_architecture(&e_hdr)) == Script) { fclose(fp); printf("'%s' is not a binary executable file.\n", app_path); return 0; /* File is not a binary executable file */ } if (app_arch != this_arch) { printf("Exec format type is different than " "this archtecture (%s)\n", mach_name.machine); fclose(fp); return 0; } addr = e_hdr.e_entry; /* Beginning of user code */ fclose(fp); return addr; } /* check_application */