/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * author chenyu * teawater add elf load function in 2005.08.30 */ //#include "armdefs.h" //#include "armemu.h" #ifdef __CYGWIN__ #include #else #include #endif #include #include #include #include #include // Anthony Lee 2006-08-22 : for win32_std_* #ifdef __MINGW32__ #include #endif #include "skyeye_types.h" #include "skyeye_defs.h" #include "skyeye_config.h" #include generic_arch_t *arch_instance; char *skyeye_config_filename = NULL; extern int skyeye_net_on; static int verbosity; int big_endian; static int mem_size = (1 << 21); static FILE *pf; int global_argc; char **global_argv; int stop_simulator = 0; int debugmode = 0; jmp_buf ctrl_c_cleanup; ARMword ARMul_Debug (ARMul_State * state, ARMword pc, ARMword instr) { } void ARMul_ConsolePrint (ARMul_State * state, const char *format, ...) { } void ARMul_CallCheck (ARMul_State * state, ARMword cur_pc, ARMword to_pc, ARMword instr) { } //chy 2005-08-01, borrow from wlm's 2005-07-26's change static void base_termios_exit (void) { //tcsetattr (STDIN_FILENO, TCSANOW, &(state->base_termios)); } //chy 2005-08-01 --------------------------------------------- extern void init_register_type(); static int init () { static int done; int ret; if (!done) { done = 1; /*some option should init before read config. e.g. uart option. */ initialize_all_devices (); initialize_all_arch (); /* initialize register type for gdb server */ init_register_type(); /* parse skyeye.conf to set skyeye_config */ skyeye_option_init (&skyeye_config); if((ret = skyeye_read_config()) < 0) return ret; arch_instance = (generic_arch_t *) malloc (sizeof (generic_arch_t)); if (!arch_instance) { printf ("malloc error!\n"); return -1; } arch_instance->init = skyeye_config.arch->init; arch_instance->reset = skyeye_config.arch->reset; arch_instance->step_once = skyeye_config.arch->step_once; arch_instance->set_pc = skyeye_config.arch->set_pc; arch_instance->get_pc = skyeye_config.arch->get_pc; arch_instance->ICE_write_byte = skyeye_config.arch->ICE_write_byte; arch_instance->ICE_read_byte = skyeye_config.arch->ICE_read_byte; arch_instance->init (); //chy:2003-08-19, after mach_init, because ARMul_Reset should after ARMul_SelectProcess arch_instance->reset (); } return 1; } #include "armemu.h" extern ARMul_State * state; void sim_resume (int step) { /*workaround here: we have different run mode on arm*/ if(!strcmp(skyeye_config.arch->arch_name, "arm")){ state->EndCondition = 0; stop_simulator = 0; if (step) { state->Reg[15] = ARMul_DoInstr (state); if (state->EndCondition == 0) { //chy 20050729 ???? printf ("error in sim_resume for state->EndCondition"); skyeye_exit (-1); } } else { state->NextInstr = RESUME; /* treat as PC change */ state->Reg[15] = ARMul_DoProg (state); } FLUSHPIPE; } /* other target simualtor step run*/ else { do { arch_instance->step_once (); }while(!step); } } //teawater add for load elf 2005.07.31------------------------------------------ static inline void tea_write (uint32_t addr, uint8_t * buffer, int size) { int i,fault; for (i = 0; i < size; i++) { fault=arch_instance->ICE_write_byte (addr + i, buffer[i]); if(fault) {printf("SKYEYE: tea_write error!!!\n");skyeye_exit(-1);} } } #ifdef NO_BFD #include static inline void tea_set(uint32_t addr, uint8_t value, int size) { int i,fault; for (i = 0; i < size; i++) { fault=arch_instance->ICE_write_byte (addr + i, value); if(fault) {printf("SKYEYE: tea_set error!!!\n");skyeye_exit(-1);} } } /* These function convert little-endian ELF datatypes into host endianess values. */ #ifdef HOST_IS_BIG_ENDIAN uint16_t e2h16(uint16_t x) { return ((x & 0xff) << 8) | (x >> 8); } uint32_t e2h32(uint32_t x) { return ((x & 0xff) << 24) | (((x >> 8) & 0xff) << 16) | (((x >> 16) & 0xff) << 8) | (((x >> 24) & 0xff)); } #else uint16_t e2h16(uint16_t x) { return x; } uint32_t e2h32(uint32_t x) { return x; } #endif //#ifdef HOST_IS_BIG_ENDIAN static int elf32_checkFile(struct Elf32_Header *file) { if (file->e_ident[EI_MAG0] != ELFMAG0 || file->e_ident[EI_MAG1] != ELFMAG1 || file->e_ident[EI_MAG2] != ELFMAG2 || file->e_ident[EI_MAG3] != ELFMAG3) return -1; /* not an elf file */ if (file->e_ident[EI_CLASS] != ELFCLASS32) return -2; /* not 32-bit file */ if (e2h16(file->e_machine) != EM_ARM) return -3; return 0; /* elf file looks OK */ } static int tea_load_exec(const char *file) { int ret = -1; int i; int tmp_fd; int r; struct Elf32_Header *elfFile; struct stat stat; struct Elf32_Phdr *segments; tmp_fd = open(file, O_RDONLY); if (tmp_fd == -1) { fprintf (stderr, "open %s error: %s\n", file, strerror(errno)); goto out; } fstat(tmp_fd, &stat); /* malloc */ elfFile = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, tmp_fd, 0); if (elfFile == NULL) { fprintf (stderr, "mmap error: %s\n", strerror(errno)); goto out; } r = elf32_checkFile(elfFile); if (r != 0) { fprintf (stderr, "elf_checkFile failed: %d\n", r); goto out; } segments = (struct Elf32_Phdr*) (uintptr_t) (((uintptr_t) elfFile) + e2h32(elfFile->e_phoff)); for(i=0; i < e2h16(elfFile->e_phnum); i++) { /* Load that section */ uint32_t dest; char *src; size_t filesz = e2h32(segments[i].p_filesz); size_t memsz = e2h32(segments[i].p_memsz); dest = e2h32(segments[i].p_paddr); src = ((char*) elfFile) + e2h32(segments[i].p_offset); tea_write(dest, src, filesz); dest += filesz; tea_set(dest, 0, memsz - filesz); } if (skyeye_config.start_address == 0) { skyeye_config.start_address = e2h32(elfFile->e_entry); } ret = 0; out: if (tmp_fd != -1) close(tmp_fd); if (elfFile) munmap(elfFile, stat.st_size); return(ret); } #else //#ifdef NO_BFD //teawater add for load elf 2005.07.31------------------------------------------ #include static int tea_load_exec (const char *file) { int ret = -1; bfd *tmp_bfd = NULL; asection *s; char *tmp_str = NULL; //open tmp_bfd = bfd_openr (file, NULL); if (tmp_bfd == NULL) { fprintf (stderr, "open %s error: %s\n", file, bfd_errmsg (bfd_get_error ())); goto out; } if (!bfd_check_format (tmp_bfd, bfd_object)) { /*FIXME:In freebsd, if bfd_errno is bfd_error_file_ambiguously_recognized, * though bfd can't recognize this format, we should try to load file.*/ if (bfd_get_error () != bfd_error_file_ambiguously_recognized) { fprintf (stderr, "check format of %s error: %s\n", file, bfd_errmsg (bfd_get_error ())); goto out; } } printf ("exec file \"%s\"'s format is %s.\n", file, tmp_bfd->xvec->name); //load for (s = tmp_bfd->sections; s; s = s->next) { if (bfd_get_section_flags (tmp_bfd, s) & (SEC_LOAD)) { if (bfd_section_lma (tmp_bfd, s) != bfd_section_vma (tmp_bfd, s)) { printf ("load section %s: lma = 0x%08x (vma = 0x%08x) size = 0x%08x.\n", bfd_section_name (tmp_bfd, s), (unsigned int) bfd_section_lma (tmp_bfd, s), (unsigned int) bfd_section_vma (tmp_bfd, s), (unsigned int) bfd_section_size (tmp_bfd, s)); } else { printf ("load section %s: addr = 0x%08x size = 0x%08x.\n", bfd_section_name (tmp_bfd, s), (unsigned int) bfd_section_lma (tmp_bfd, s), (unsigned int) bfd_section_size (tmp_bfd, s)); } if (bfd_section_size (tmp_bfd, s) > 0) { tmp_str = (char *) malloc (bfd_section_size (tmp_bfd, s)); if (!tmp_str) { fprintf (stderr, "alloc memory to load session %s error.\n", bfd_section_name (tmp_bfd, s)); goto out; } if (!bfd_get_section_contents (tmp_bfd, s, tmp_str, 0, bfd_section_size (tmp_bfd, s))) { fprintf (stderr, "get session %s content error: %s\n", bfd_section_name (tmp_bfd, s), bfd_errmsg (bfd_get_error ())); goto out; } tea_write (bfd_section_vma (tmp_bfd, s), tmp_str, bfd_section_size (tmp_bfd, s)); free (tmp_str); tmp_str = NULL; } } else { printf ("not load section %s: addr = 0x%08x size = 0x%08x .\n", bfd_section_name (tmp_bfd, s), (unsigned int) bfd_section_vma (tmp_bfd, s), (unsigned int) bfd_section_size (tmp_bfd, s)); } } //set strat address if (skyeye_config.start_address == 0) { skyeye_config.start_address = bfd_get_start_address (tmp_bfd); printf ("start addr is set to 0x%08x by exec file.\n", (unsigned int) skyeye_config.start_address); } ret = 0; out: if (tmp_str) free (tmp_str); if (tmp_bfd) bfd_close (tmp_bfd); return (ret); } #endif //#ifdef NO_BFD //AJ2D-------------------------------------------------------------------------- void usage () { #ifdef __MINGW32__ #define fprintf(a, b) skyeye_win32_std_write(1, b, strlen(b)) char c; AllocConsole(); do{ Sleep(100); }while(GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE); #endif fprintf (stderr, "------------------------- SkyEye -V1.2 ---------------------------\n"); fprintf (stderr, "Usage: SkyEye [options] -e program [program args]\n"); fprintf (stderr, "Default mode is STANDALONE mode\n"); fprintf (stderr, "------------------------------------------------------------------\n"); fprintf (stderr, "Options:\n"); //teawater add for load elf 2005.07.31------------------------------------------ fprintf (stderr, "-e exec-file the (ELF executable format)kernel file name.\n"); //AJ2D-------------------------------------------------------------------------- fprintf (stderr, "-d in GDB Server mode (can be connected by GDB).\n"); fprintf (stderr, "-c config-file the skyeye configure file name.\n"); fprintf (stderr, "-h The SkyEye command options, and ARCHs and CPUs simulated\n"); fprintf (stderr, "------------------------------------------------------------------\n"); #ifdef __MINGW32__ fprintf(stderr, "\nPress any key to quit..."); #undef fprintf ReadConsole(GetStdHandle(STD_INPUT_HANDLE), &c, 1, NULL, NULL); #endif } extern cpu_config_t bfin_cpu[]; extern machine_config_t arm_machines[]; void display_all_support(){ int i; fprintf (stderr, "----------- Architectures and CPUs simulated by SkyEye-------------\n"); fprintf (stderr, "-------- ARM architectures ---------\n"); for(i = 0; arm_machines[i].machine_name!=NULL ; i++) fprintf(stderr, "%s \n",arm_machines[i].machine_name); fprintf (stderr, "-------- BlackFin architectures ----\n"); for(i = 0; bfin_cpu[i].cpu_name!=NULL ; i++) fprintf(stderr, "%s \n",bfin_cpu[i].cpu_name); } //chy 2006-04-11 terminal old value #ifndef __MINGW32__ struct termios skyeye_termios_old; #else DWORD skyeye_console_mode_old; #endif void skyeye_exit(int ret) { /* Restore the original terminal settings */ #ifndef __MINGW32__ tcsetattr (0, TCSANOW, &skyeye_termios_old); #else SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), skyeye_console_mode_old); #endif exit( ret); } #ifdef __MINGW32__ static BOOL init_win32_socket() { WSADATA wsdData; if(WSAStartup(0x202, &wsdData) != 0 || LOBYTE(wsdData.wVersion) != 2 || HIBYTE(wsdData.wVersion) != 2) return FALSE; return TRUE; } static void cancel_win32_socket() { WSACleanup(); } #endif void sigint_handler (int signum) { longjmp (ctrl_c_cleanup, 1); } int main (int argc, char **argv) { int c; int index; int ret; //teawater add for load elf 2005.07.31------------------------------------------ char *exec_file = NULL; /* Set the terminal for non-blocking per-character (not per-line) input, no echo */ #ifndef __MINGW32__ struct termios old, tmp; opterr = 0; tcgetattr (0, &old); skyeye_termios_old = old; tmp = old; tmp.c_lflag &= ~ICANON; tmp.c_lflag |= ISIG; tmp.c_lflag &= ~ECHO; tmp.c_cc[VMIN] = 0; tmp.c_cc[VTIME] = 0; tcsetattr (0, TCSANOW, &tmp); #else if(GetStdHandle(STD_INPUT_HANDLE) == NULL || GetStdHandle(STD_INPUT_HANDLE) == INVALID_HANDLE_VALUE) AllocConsole(); GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &skyeye_console_mode_old); SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), skyeye_console_mode_old & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)); init_win32_socket(); atexit(cancel_win32_socket); #endif if (setjmp (ctrl_c_cleanup) != 0) { goto exit_skyeye; } signal (SIGINT, sigint_handler); while ((c = getopt (argc, argv, "e:dc:h")) != -1) //AJ2D-------------------------------------------------------------------------- switch (c) { //teawater add for load elf 2005.07.31------------------------------------------ case 'e': exec_file = optarg; break; //AJ2D-------------------------------------------------------------------------- case 'd': debugmode = 1; break; case 'h': usage (); display_all_support(); goto exit_skyeye; case 'c': skyeye_config_filename = optarg; break; case '?': if (isprint (optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt); else fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); ret=1; goto exit_skyeye; /* case 'v': display_all_support(); goto exit_skyeye; */ default: fprintf(stderr, "Default option .....\n"); ret=1; goto exit_skyeye; } //usage (); if(debugmode) printf ("debugmode= %d, filename = %s, server TCP port is 12345\n", debugmode, skyeye_config_filename); if(exec_file == NULL){ printf ("SKYEYE: If you have ELF kernel file, please use -e option to indicate your ELF format kernel filename \n"); printf ("SKYEYE: If you only have kernel binary image, you should put the filename of kernel binary image in skyeye.conf file\n"); } if (skyeye_config_filename == NULL) skyeye_config_filename = DEFAULT_CONFIG_FILE; for (index = optind; index < argc; index++) printf ("Non-option argument %s\n", argv[index]); //teawater add DBCT_TEST_SPEED 2005.10.04--------------------------------------- #ifdef DBCT_TEST_SPEED { if (!dbct_test_speed_state) { //init timer struct itimerval value; struct sigaction act; dbct_test_speed_state = state; state->instr_count = 0; act.sa_handler = dbct_test_speed_sig; act.sa_flags = SA_RESTART; //cygwin don't support ITIMER_VIRTUAL or ITIMER_PROF #ifndef __CYGWIN__ if (sigaction(SIGVTALRM, &act, NULL) == -1) { #else if (sigaction(SIGALRM, &act, NULL) == -1) { #endif //__CYGWIN__ fprintf(stderr, "init timer error.\n"); goto exit_skyeye; } if (skyeye_config.dbct_test_speed_sec) { value.it_value.tv_sec = skyeye_config.dbct_test_speed_sec; } else { value.it_value.tv_sec = DBCT_TEST_SPEED_SEC; } printf("dbct_test_speed_sec = %ld\n", value.it_value.tv_sec); value.it_value.tv_usec = 0; value.it_interval.tv_sec = 0; value.it_interval.tv_usec = 0; #ifndef __CYGWIN__ if (setitimer(ITIMER_VIRTUAL, &value, NULL) == -1) { #else if (setitimer(ITIMER_REAL, &value, NULL) == -1) { #endif //__CYGWIN__ fprintf(stderr, "init timer error.\n"); goto exit_skyeye; } } } #endif //DBCT_TEST_SPEED //AJ2D-------------------------------------------------------------------------- /*do some initialization*/ if((ret = init ()) < 0) goto exit_skyeye; //teawater add for load elf 2005.07.31------------------------------------------ if (exec_file) { if (tea_load_exec (exec_file)) { fprintf (stderr, "load \"%s\" error\n", exec_file); goto exit_skyeye; } } //AJ2D-------------------------------------------------------------------------- if (skyeye_config.start_address != 0) arch_instance->set_pc (skyeye_config.start_address); fflush(stdout); if (debugmode == 0) sim_resume (0); else sim_debug (); exit_skyeye: /* Restore the original terminal settings */ #ifndef __MINGW32__ tcsetattr (0, TCSANOW, &old); #else SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), skyeye_console_mode_old); #endif return ret; } #ifdef __MINGW32__ int _stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { return main(__argc, __argv); } #endif // __MINGW32__