Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
1eb87257da | ||
|
32ce63371a | ||
|
ec86b0fb3a | ||
|
1d346ae63a | ||
|
74cd30b811 | ||
|
7fb9a24e39 | ||
|
afeb6ee377 | ||
|
f29042b531 | ||
|
09bfb054fb | ||
|
2677e107e6 | ||
|
66cd58461d | ||
|
bb0ebb1f2d |
@@ -1,3 +1,12 @@
|
|||||||
|
version 0.1.6:
|
||||||
|
|
||||||
|
- automatic library search system. QEMU can now work with unpatched
|
||||||
|
ELF dynamic loader and libc (Rusty Russell).
|
||||||
|
- ISO C warning fixes (Alistair Strachan)
|
||||||
|
- first self-virtualizable version (works only as long as the
|
||||||
|
translation cache is not flushed)
|
||||||
|
- RH9 fixes
|
||||||
|
|
||||||
version 0.1.5:
|
version 0.1.5:
|
||||||
|
|
||||||
- ppc64 support + personality() patch (Rusty Russell)
|
- ppc64 support + personality() patch (Rusty Russell)
|
||||||
|
15
Makefile
15
Makefile
@@ -45,7 +45,7 @@ LDFLAGS+=-p
|
|||||||
main.o: CFLAGS+=-p
|
main.o: CFLAGS+=-p
|
||||||
endif
|
endif
|
||||||
|
|
||||||
OBJS= elfload.o main.o syscall.o signal.o
|
OBJS= elfload.o main.o syscall.o signal.o path.o
|
||||||
SRCS:= $(OBJS:.o=.c)
|
SRCS:= $(OBJS:.o=.c)
|
||||||
OBJS+= libqemu.a
|
OBJS+= libqemu.a
|
||||||
|
|
||||||
@@ -105,18 +105,19 @@ qemu-doc.html: qemu-doc.texi
|
|||||||
FILES= \
|
FILES= \
|
||||||
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
|
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
|
||||||
dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\
|
dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\
|
||||||
Makefile elf.h linux_bin.h segment.h thunk.c\
|
Makefile elf.h thunk.c\
|
||||||
elfload.c main.c signal.c thunk.h\
|
elfload.c main.c signal.c thunk.h\
|
||||||
cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\
|
cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\
|
||||||
dis-asm.h gen-i386.h syscall.c\
|
dis-asm.h gen-i386.h syscall.c\
|
||||||
dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\
|
dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\
|
||||||
ppc.ld s390.ld exec-i386.h exec-i386.c configure \
|
ppc.ld s390.ld exec-i386.h exec-i386.c path.c configure \
|
||||||
tests/Makefile\
|
tests/Makefile\
|
||||||
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\
|
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\
|
||||||
tests/test-i386-muldiv.h tests/test-i386-code16.S\
|
tests/test-i386-muldiv.h tests/test-i386-code16.S\
|
||||||
tests/hello.c tests/hello tests/sha1.c \
|
tests/hello.c tests/hello tests/sha1.c \
|
||||||
tests/testsig.c tests/testclone.c tests/testthread.c \
|
tests/testsig.c tests/testclone.c tests/testthread.c \
|
||||||
tests/runcom.c tests/pi_10.com \
|
tests/runcom.c tests/pi_10.com \
|
||||||
|
tests/test_path.c \
|
||||||
qemu-doc.texi qemu-doc.html
|
qemu-doc.texi qemu-doc.html
|
||||||
|
|
||||||
FILE=qemu-$(VERSION)
|
FILE=qemu-$(VERSION)
|
||||||
@@ -132,10 +133,10 @@ tar:
|
|||||||
BINPATH=/usr/local/qemu-i386
|
BINPATH=/usr/local/qemu-i386
|
||||||
|
|
||||||
tarbin:
|
tarbin:
|
||||||
tar zcvf /tmp/qemu-i386-glibc21.tar.gz \
|
tar zcvf /tmp/qemu-$(VERSION)-i386-glibc21.tar.gz \
|
||||||
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin
|
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin $(BINPATH)/usr
|
||||||
tar zcvf /tmp/qemu-i386-wine.tar.gz \
|
tar zcvf /tmp/qemu-$(VERSION)-i386-wine.tar.gz \
|
||||||
$(BINPATH)/X11R6 $(BINPATH)/wine
|
$(BINPATH)/wine
|
||||||
|
|
||||||
ifneq ($(wildcard .depend),)
|
ifneq ($(wildcard .depend),)
|
||||||
include .depend
|
include .depend
|
||||||
|
4
README
4
README
@@ -6,7 +6,7 @@ INSTALLATION
|
|||||||
|
|
||||||
Type
|
Type
|
||||||
|
|
||||||
./configure
|
./configure --interp-prefix=/usr/local/qemu-i386
|
||||||
make
|
make
|
||||||
|
|
||||||
to build qemu and libqemu.a.
|
to build qemu and libqemu.a.
|
||||||
@@ -23,7 +23,7 @@ libraries installed on your PC. For example:
|
|||||||
./qemu -L / /bin/ls
|
./qemu -L / /bin/ls
|
||||||
|
|
||||||
* On non x86 CPUs, you need first to download at least an x86 glibc
|
* On non x86 CPUs, you need first to download at least an x86 glibc
|
||||||
(qemu-i386-glibc21.tar.gz on the qemu web page). Ensure that
|
(qemu-XXX-i386-glibc21.tar.gz on the qemu web page). Ensure that
|
||||||
LD_LIBRARY_PATH is not set:
|
LD_LIBRARY_PATH is not set:
|
||||||
|
|
||||||
unset LD_LIBRARY_PATH
|
unset LD_LIBRARY_PATH
|
||||||
|
3
TODO
3
TODO
@@ -7,5 +7,6 @@
|
|||||||
issues, fix 16 bit uid issues)
|
issues, fix 16 bit uid issues)
|
||||||
- finish signal handing (fp87 state, more siginfo conversions)
|
- finish signal handing (fp87 state, more siginfo conversions)
|
||||||
- verify thread support (clone() and various locks)
|
- verify thread support (clone() and various locks)
|
||||||
- make it self runnable (use same trick as ld.so : include its own relocator and libc)
|
- make it self runnable (handle self modifying code, relocate stack
|
||||||
|
and dyn loader)
|
||||||
- fix FPU exceptions (in particular: gen_op_fpush not before mem load)
|
- fix FPU exceptions (in particular: gen_op_fpush not before mem load)
|
||||||
|
9
configure
vendored
9
configure
vendored
@@ -19,6 +19,7 @@ TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h"
|
|||||||
|
|
||||||
# default parameters
|
# default parameters
|
||||||
prefix="/usr/local"
|
prefix="/usr/local"
|
||||||
|
interp_prefix="/usr/gnemul/qemu-i386"
|
||||||
cross_prefix=""
|
cross_prefix=""
|
||||||
cc="gcc"
|
cc="gcc"
|
||||||
host_cc="gcc"
|
host_cc="gcc"
|
||||||
@@ -89,6 +90,8 @@ for opt do
|
|||||||
case "$opt" in
|
case "$opt" in
|
||||||
--prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
|
--prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
|
||||||
;;
|
;;
|
||||||
|
--interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2`
|
||||||
|
;;
|
||||||
--source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
|
--source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
|
||||||
;;
|
;;
|
||||||
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
|
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
|
||||||
@@ -172,7 +175,7 @@ EOF
|
|||||||
echo "Standard options:"
|
echo "Standard options:"
|
||||||
echo " --help print this message"
|
echo " --help print this message"
|
||||||
echo " --prefix=PREFIX install in PREFIX [$prefix]"
|
echo " --prefix=PREFIX install in PREFIX [$prefix]"
|
||||||
echo " for audio/video/image support"
|
echo " --interp-prefix=PREFIX where to find shared libraries, etc. [$interp_prefix]"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Advanced options (experts only):"
|
echo "Advanced options (experts only):"
|
||||||
echo " --source-path=PATH path of source code [$source_path]"
|
echo " --source-path=PATH path of source code [$source_path]"
|
||||||
@@ -198,7 +201,7 @@ echo "# Automatically generated by configure - do not modify" > config.mak
|
|||||||
echo "/* Automatically generated by configure - do not modify */" > $TMPH
|
echo "/* Automatically generated by configure - do not modify */" > $TMPH
|
||||||
|
|
||||||
echo "prefix=$prefix" >> config.mak
|
echo "prefix=$prefix" >> config.mak
|
||||||
echo "#define CONFIG_QEMU_PREFIX \"$prefix\"" >> $TMPH
|
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $TMPH
|
||||||
echo "MAKE=$make" >> config.mak
|
echo "MAKE=$make" >> config.mak
|
||||||
echo "CC=$cc" >> config.mak
|
echo "CC=$cc" >> config.mak
|
||||||
echo "GCC_MAJOR=$gcc_major" >> config.mak
|
echo "GCC_MAJOR=$gcc_major" >> config.mak
|
||||||
@@ -268,4 +271,4 @@ else
|
|||||||
echo "config.h is unchanged"
|
echo "config.h is unchanged"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -f $TMPH
|
rm -f $TMPO $TMPC $TMPE $TMPS $TMPH
|
||||||
|
@@ -33,12 +33,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|||||||
* the Intel manual for details.
|
* the Intel manual for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
#include "dis-asm.h"
|
#include "dis-asm.h"
|
||||||
|
|
||||||
#define MAXLEN 20
|
#define MAXLEN 20
|
||||||
|
|
||||||
#include <setjmp.h>
|
|
||||||
|
|
||||||
static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
|
static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
|
||||||
|
|
||||||
struct dis_private
|
struct dis_private
|
||||||
|
@@ -49,9 +49,77 @@ typedef struct user_i387_struct elf_fpregset_t;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "linux_bin.h"
|
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include "segment.h"
|
|
||||||
|
/*
|
||||||
|
* MAX_ARG_PAGES defines the number of pages allocated for arguments
|
||||||
|
* and envelope for the new program. 32 should suffice, this gives
|
||||||
|
* a maximum env+arg of 128kB w/4KB pages!
|
||||||
|
*/
|
||||||
|
#define MAX_ARG_PAGES 32
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This structure is used to hold the arguments that are
|
||||||
|
* used when loading binaries.
|
||||||
|
*/
|
||||||
|
struct linux_binprm {
|
||||||
|
char buf[128];
|
||||||
|
unsigned long page[MAX_ARG_PAGES];
|
||||||
|
unsigned long p;
|
||||||
|
int sh_bang;
|
||||||
|
int fd;
|
||||||
|
int e_uid, e_gid;
|
||||||
|
int argc, envc;
|
||||||
|
char * filename; /* Name of binary */
|
||||||
|
unsigned long loader, exec;
|
||||||
|
int dont_iput; /* binfmt handler has put inode */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct exec
|
||||||
|
{
|
||||||
|
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
|
||||||
|
unsigned int a_text; /* length of text, in bytes */
|
||||||
|
unsigned int a_data; /* length of data, in bytes */
|
||||||
|
unsigned int a_bss; /* length of uninitialized data area, in bytes */
|
||||||
|
unsigned int a_syms; /* length of symbol table data in file, in bytes */
|
||||||
|
unsigned int a_entry; /* start address */
|
||||||
|
unsigned int a_trsize; /* length of relocation info for text, in bytes */
|
||||||
|
unsigned int a_drsize; /* length of relocation info for data, in bytes */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define N_MAGIC(exec) ((exec).a_info & 0xffff)
|
||||||
|
#define OMAGIC 0407
|
||||||
|
#define NMAGIC 0410
|
||||||
|
#define ZMAGIC 0413
|
||||||
|
#define QMAGIC 0314
|
||||||
|
|
||||||
|
#define X86_STACK_TOP 0x7d000000
|
||||||
|
|
||||||
|
/* max code+data+bss space allocated to elf interpreter */
|
||||||
|
#define INTERP_MAP_SIZE (32 * 1024 * 1024)
|
||||||
|
|
||||||
|
/* max code+data+bss+brk space allocated to ET_DYN executables */
|
||||||
|
#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
|
||||||
|
|
||||||
|
/* from personality.h */
|
||||||
|
|
||||||
|
/* Flags for bug emulation. These occupy the top three bytes. */
|
||||||
|
#define STICKY_TIMEOUTS 0x4000000
|
||||||
|
#define WHOLE_SECONDS 0x2000000
|
||||||
|
|
||||||
|
/* Personality types. These go in the low byte. Avoid using the top bit,
|
||||||
|
* it will conflict with error returns.
|
||||||
|
*/
|
||||||
|
#define PER_MASK (0x00ff)
|
||||||
|
#define PER_LINUX (0x0000)
|
||||||
|
#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS)
|
||||||
|
#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS)
|
||||||
|
#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
|
||||||
|
#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS)
|
||||||
|
#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS)
|
||||||
|
#define PER_BSD (0x0006)
|
||||||
|
#define PER_XENIX (0x0007 | STICKY_TIMEOUTS)
|
||||||
|
|
||||||
/* Necessary parameters */
|
/* Necessary parameters */
|
||||||
#define ALPHA_PAGE_SIZE 4096
|
#define ALPHA_PAGE_SIZE 4096
|
||||||
@@ -78,8 +146,18 @@ typedef struct user_i387_struct elf_fpregset_t;
|
|||||||
|
|
||||||
#define DLINFO_ITEMS 12
|
#define DLINFO_ITEMS 12
|
||||||
|
|
||||||
/* Where we find X86 libraries... */
|
#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x))
|
||||||
|
#define get_user(ptr) (typeof(*ptr))(*(ptr))
|
||||||
|
|
||||||
|
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
|
||||||
|
{
|
||||||
|
memcpy(to, from, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
|
||||||
|
{
|
||||||
|
memcpy(to, from, n);
|
||||||
|
}
|
||||||
|
|
||||||
//extern void * mmap4k();
|
//extern void * mmap4k();
|
||||||
#define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f)
|
#define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f)
|
||||||
@@ -282,42 +360,34 @@ static int prepare_binprm(struct linux_binprm *bprm)
|
|||||||
unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
||||||
struct image_info * info)
|
struct image_info * info)
|
||||||
{
|
{
|
||||||
unsigned long stack_base;
|
unsigned long stack_base, size, error;
|
||||||
int i;
|
int i;
|
||||||
extern unsigned long stktop;
|
|
||||||
|
|
||||||
stack_base = X86_STACK_TOP - MAX_ARG_PAGES*X86_PAGE_SIZE;
|
|
||||||
|
|
||||||
p += stack_base;
|
|
||||||
if (bprm->loader) {
|
|
||||||
bprm->loader += stack_base;
|
|
||||||
}
|
|
||||||
bprm->exec += stack_base;
|
|
||||||
|
|
||||||
/* Create enough stack to hold everything. If we don't use
|
/* Create enough stack to hold everything. If we don't use
|
||||||
* it for args, we'll use it for something else...
|
* it for args, we'll use it for something else...
|
||||||
*/
|
*/
|
||||||
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
size = x86_stack_size;
|
||||||
we allocate a bigger stack. Need a better solution, for example
|
if (size < MAX_ARG_PAGES*X86_PAGE_SIZE)
|
||||||
by remapping the process stack directly at the right place */
|
size = MAX_ARG_PAGES*X86_PAGE_SIZE;
|
||||||
if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) {
|
error = (unsigned long)mmap4k(NULL,
|
||||||
if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE,
|
size + X86_PAGE_SIZE,
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE,
|
||||||
MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
|
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||||
perror("stk mmap");
|
-1, 0);
|
||||||
exit(-1);
|
if (error == -1) {
|
||||||
}
|
perror("stk mmap");
|
||||||
}
|
exit(-1);
|
||||||
else {
|
|
||||||
if((long)mmap4k((void *)stack_base, (MAX_ARG_PAGES+1)*X86_PAGE_SIZE,
|
|
||||||
PROT_READ | PROT_WRITE,
|
|
||||||
MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
|
|
||||||
perror("stk mmap");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
/* we reserve one extra page at the top of the stack as guard */
|
||||||
|
mprotect((void *)(error + size), X86_PAGE_SIZE, PROT_NONE);
|
||||||
|
|
||||||
stktop = stack_base;
|
stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE;
|
||||||
|
p += stack_base;
|
||||||
|
|
||||||
|
if (bprm->loader) {
|
||||||
|
bprm->loader += stack_base;
|
||||||
|
}
|
||||||
|
bprm->exec += stack_base;
|
||||||
|
|
||||||
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
|
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
|
||||||
if (bprm->page[i]) {
|
if (bprm->page[i]) {
|
||||||
@@ -369,10 +439,11 @@ static void padzero(unsigned long elf_bss)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
||||||
struct elfhdr * exec,
|
struct elfhdr * exec,
|
||||||
unsigned long load_addr,
|
unsigned long load_addr,
|
||||||
unsigned long interp_load_addr, int ibcs,
|
unsigned long load_bias,
|
||||||
struct image_info *info)
|
unsigned long interp_load_addr, int ibcs,
|
||||||
|
struct image_info *info)
|
||||||
{
|
{
|
||||||
target_ulong *argv, *envp, *dlinfo;
|
target_ulong *argv, *envp, *dlinfo;
|
||||||
target_ulong *sp;
|
target_ulong *sp;
|
||||||
@@ -397,17 +468,17 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
|
|||||||
put_user (tswapl(val), dlinfo++)
|
put_user (tswapl(val), dlinfo++)
|
||||||
|
|
||||||
if (exec) { /* Put this here for an ELF program interpreter */
|
if (exec) { /* Put this here for an ELF program interpreter */
|
||||||
NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff));
|
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
|
||||||
NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr)));
|
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
|
||||||
NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum));
|
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
|
||||||
NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE));
|
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(ALPHA_PAGE_SIZE));
|
||||||
NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr));
|
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
|
||||||
NEW_AUX_ENT (AT_FLAGS, (unsigned int)0);
|
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
|
||||||
NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry);
|
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
|
||||||
NEW_AUX_ENT (AT_UID, (unsigned int) getuid());
|
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
|
||||||
NEW_AUX_ENT (AT_EUID, (unsigned int) geteuid());
|
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
|
||||||
NEW_AUX_ENT (AT_GID, (unsigned int) getgid());
|
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
|
||||||
NEW_AUX_ENT (AT_EGID, (unsigned int) getegid());
|
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
|
||||||
}
|
}
|
||||||
NEW_AUX_ENT (AT_NULL, 0);
|
NEW_AUX_ENT (AT_NULL, 0);
|
||||||
#undef NEW_AUX_ENT
|
#undef NEW_AUX_ENT
|
||||||
@@ -436,7 +507,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
|||||||
{
|
{
|
||||||
struct elf_phdr *elf_phdata = NULL;
|
struct elf_phdr *elf_phdata = NULL;
|
||||||
struct elf_phdr *eppnt;
|
struct elf_phdr *eppnt;
|
||||||
unsigned long load_addr;
|
unsigned long load_addr = 0;
|
||||||
int load_addr_set = 0;
|
int load_addr_set = 0;
|
||||||
int retval;
|
int retval;
|
||||||
unsigned long last_bss, elf_bss;
|
unsigned long last_bss, elf_bss;
|
||||||
@@ -447,17 +518,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
|||||||
last_bss = 0;
|
last_bss = 0;
|
||||||
error = 0;
|
error = 0;
|
||||||
|
|
||||||
/* We put this here so that mmap will search for the *first*
|
|
||||||
* available memory...
|
|
||||||
*/
|
|
||||||
load_addr = INTERP_LOADADDR;
|
|
||||||
|
|
||||||
#ifdef BSWAP_NEEDED
|
#ifdef BSWAP_NEEDED
|
||||||
bswap_ehdr(interp_elf_ex);
|
bswap_ehdr(interp_elf_ex);
|
||||||
#endif
|
#endif
|
||||||
/* First of all, some simple consistency checks */
|
/* First of all, some simple consistency checks */
|
||||||
if ((interp_elf_ex->e_type != ET_EXEC &&
|
if ((interp_elf_ex->e_type != ET_EXEC &&
|
||||||
interp_elf_ex->e_type != ET_DYN) ||
|
interp_elf_ex->e_type != ET_DYN) ||
|
||||||
!elf_check_arch(interp_elf_ex->e_machine)) {
|
!elf_check_arch(interp_elf_ex->e_machine)) {
|
||||||
return ~0UL;
|
return ~0UL;
|
||||||
}
|
}
|
||||||
@@ -478,11 +544,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
|||||||
* If the size of this structure has changed, then punt, since
|
* If the size of this structure has changed, then punt, since
|
||||||
* we will be doing the wrong thing.
|
* we will be doing the wrong thing.
|
||||||
*/
|
*/
|
||||||
if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
|
if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
|
||||||
{
|
|
||||||
free(elf_phdata);
|
free(elf_phdata);
|
||||||
return ~0UL;
|
return ~0UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
|
retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
|
||||||
if(retval >= 0) {
|
if(retval >= 0) {
|
||||||
@@ -502,6 +567,21 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
|
|||||||
bswap_phdr(eppnt);
|
bswap_phdr(eppnt);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (interp_elf_ex->e_type == ET_DYN) {
|
||||||
|
/* in order to avoid harcoding the interpreter load
|
||||||
|
address in qemu, we allocate a big enough memory zone */
|
||||||
|
error = (unsigned long)mmap4k(NULL, INTERP_MAP_SIZE,
|
||||||
|
PROT_NONE, MAP_PRIVATE | MAP_ANON,
|
||||||
|
-1, 0);
|
||||||
|
if (error == -1) {
|
||||||
|
perror("mmap");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
load_addr = error;
|
||||||
|
load_addr_set = 1;
|
||||||
|
}
|
||||||
|
|
||||||
eppnt = elf_phdata;
|
eppnt = elf_phdata;
|
||||||
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
|
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
|
||||||
if (eppnt->p_type == PT_LOAD) {
|
if (eppnt->p_type == PT_LOAD) {
|
||||||
@@ -585,7 +665,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
|||||||
struct elfhdr interp_elf_ex;
|
struct elfhdr interp_elf_ex;
|
||||||
struct exec interp_ex;
|
struct exec interp_ex;
|
||||||
int interpreter_fd = -1; /* avoid warning */
|
int interpreter_fd = -1; /* avoid warning */
|
||||||
unsigned long load_addr;
|
unsigned long load_addr, load_bias;
|
||||||
int load_addr_set = 0;
|
int load_addr_set = 0;
|
||||||
unsigned int interpreter_type = INTERPRETER_NONE;
|
unsigned int interpreter_type = INTERPRETER_NONE;
|
||||||
unsigned char ibcs2_interpreter;
|
unsigned char ibcs2_interpreter;
|
||||||
@@ -605,6 +685,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
|||||||
ibcs2_interpreter = 0;
|
ibcs2_interpreter = 0;
|
||||||
status = 0;
|
status = 0;
|
||||||
load_addr = 0;
|
load_addr = 0;
|
||||||
|
load_bias = 0;
|
||||||
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
|
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
|
||||||
#ifdef BSWAP_NEEDED
|
#ifdef BSWAP_NEEDED
|
||||||
bswap_ehdr(&elf_ex);
|
bswap_ehdr(&elf_ex);
|
||||||
@@ -674,8 +755,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
|||||||
* is an a.out format binary
|
* is an a.out format binary
|
||||||
*/
|
*/
|
||||||
|
|
||||||
elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+
|
elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
|
||||||
strlen(bprm->interp_prefix));
|
|
||||||
|
|
||||||
if (elf_interpreter == NULL) {
|
if (elf_interpreter == NULL) {
|
||||||
free (elf_phdata);
|
free (elf_phdata);
|
||||||
@@ -683,12 +763,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(elf_interpreter, bprm->interp_prefix);
|
|
||||||
retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
|
retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
|
||||||
if(retval >= 0) {
|
if(retval >= 0) {
|
||||||
retval = read(bprm->fd,
|
retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
|
||||||
elf_interpreter+strlen(bprm->interp_prefix),
|
|
||||||
elf_ppnt->p_filesz);
|
|
||||||
}
|
}
|
||||||
if(retval < 0) {
|
if(retval < 0) {
|
||||||
perror("load_elf_binary2");
|
perror("load_elf_binary2");
|
||||||
@@ -710,7 +787,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
|||||||
printf("Using ELF interpreter %s\n", elf_interpreter);
|
printf("Using ELF interpreter %s\n", elf_interpreter);
|
||||||
#endif
|
#endif
|
||||||
if (retval >= 0) {
|
if (retval >= 0) {
|
||||||
retval = open(elf_interpreter, O_RDONLY);
|
retval = open(path(elf_interpreter), O_RDONLY);
|
||||||
if(retval >= 0) {
|
if(retval >= 0) {
|
||||||
interpreter_fd = retval;
|
interpreter_fd = retval;
|
||||||
}
|
}
|
||||||
@@ -810,56 +887,86 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
|||||||
* address.
|
* address.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
|
for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
|
||||||
if (elf_ppnt->p_type == PT_LOAD) {
|
int elf_prot = 0;
|
||||||
int elf_prot = 0;
|
int elf_flags = 0;
|
||||||
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
|
unsigned long error;
|
||||||
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
|
|
||||||
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
|
|
||||||
|
|
||||||
mapped_addr = mmap4k(X86_ELF_PAGESTART(elf_ppnt->p_vaddr),
|
if (elf_ppnt->p_type != PT_LOAD)
|
||||||
(elf_ppnt->p_filesz +
|
continue;
|
||||||
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
|
|
||||||
elf_prot,
|
|
||||||
(MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
|
|
||||||
bprm->fd,
|
|
||||||
(elf_ppnt->p_offset -
|
|
||||||
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
|
|
||||||
|
|
||||||
if((unsigned long)mapped_addr == 0xffffffffffffffff) {
|
|
||||||
perror("mmap");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
|
||||||
|
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
|
||||||
|
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
|
||||||
|
elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
|
||||||
|
if (elf_ex.e_type == ET_EXEC || load_addr_set) {
|
||||||
|
elf_flags |= MAP_FIXED;
|
||||||
|
} else if (elf_ex.e_type == ET_DYN) {
|
||||||
|
/* Try and get dynamic programs out of the way of the default mmap
|
||||||
|
base, as well as whatever program they might try to exec. This
|
||||||
|
is because the brk will follow the loader, and is not movable. */
|
||||||
|
/* NOTE: for qemu, we do a big mmap to get enough space
|
||||||
|
without harcoding any address */
|
||||||
|
error = (unsigned long)mmap4k(NULL, ET_DYN_MAP_SIZE,
|
||||||
|
PROT_NONE, MAP_PRIVATE | MAP_ANON,
|
||||||
|
-1, 0);
|
||||||
|
if (error == -1) {
|
||||||
|
perror("mmap");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
load_bias = X86_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = (unsigned long)mmap4k(
|
||||||
|
X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
|
||||||
|
(elf_ppnt->p_filesz +
|
||||||
|
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
|
||||||
|
elf_prot,
|
||||||
|
(MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
|
||||||
|
bprm->fd,
|
||||||
|
(elf_ppnt->p_offset -
|
||||||
|
X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
|
||||||
|
if (error == -1) {
|
||||||
|
perror("mmap");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef LOW_ELF_STACK
|
#ifdef LOW_ELF_STACK
|
||||||
if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
|
if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
|
||||||
elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr);
|
elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!load_addr_set) {
|
if (!load_addr_set) {
|
||||||
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
|
load_addr_set = 1;
|
||||||
load_addr_set = 1;
|
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
|
||||||
}
|
if (elf_ex.e_type == ET_DYN) {
|
||||||
k = elf_ppnt->p_vaddr;
|
load_bias += error -
|
||||||
if (k < start_code) start_code = k;
|
X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
|
||||||
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
|
load_addr += load_bias;
|
||||||
if (k > elf_bss) elf_bss = k;
|
}
|
||||||
#if 1
|
}
|
||||||
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
|
k = elf_ppnt->p_vaddr;
|
||||||
#else
|
if (k < start_code)
|
||||||
if ( !(elf_ppnt->p_flags & PF_W) && end_code < k)
|
start_code = k;
|
||||||
#endif
|
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
|
||||||
end_code = k;
|
if (k > elf_bss)
|
||||||
if (end_data < k) end_data = k;
|
elf_bss = k;
|
||||||
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
|
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
|
||||||
if (k > elf_brk) elf_brk = k;
|
end_code = k;
|
||||||
}
|
if (end_data < k)
|
||||||
|
end_data = k;
|
||||||
|
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
|
||||||
|
if (k > elf_brk) elf_brk = k;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elf_entry += load_bias;
|
||||||
|
elf_bss += load_bias;
|
||||||
|
elf_brk += load_bias;
|
||||||
|
start_code += load_bias;
|
||||||
|
end_code += load_bias;
|
||||||
|
// start_data += load_bias;
|
||||||
|
end_data += load_bias;
|
||||||
|
|
||||||
if (elf_interpreter) {
|
if (elf_interpreter) {
|
||||||
if (interpreter_type & 1) {
|
if (interpreter_type & 1) {
|
||||||
elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
|
elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
|
||||||
@@ -893,7 +1000,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
|||||||
bprm->argc,
|
bprm->argc,
|
||||||
bprm->envc,
|
bprm->envc,
|
||||||
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
|
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
|
||||||
load_addr,
|
load_addr, load_bias,
|
||||||
interp_load_addr,
|
interp_load_addr,
|
||||||
(interpreter_type == INTERPRETER_AOUT ? 0 : 1),
|
(interpreter_type == INTERPRETER_AOUT ? 0 : 1),
|
||||||
info);
|
info);
|
||||||
@@ -948,8 +1055,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int elf_exec(const char *interp_prefix,
|
int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||||
const char * filename, char ** argv, char ** envp,
|
|
||||||
struct target_pt_regs * regs, struct image_info *infop)
|
struct target_pt_regs * regs, struct image_info *infop)
|
||||||
{
|
{
|
||||||
struct linux_binprm bprm;
|
struct linux_binprm bprm;
|
||||||
@@ -968,7 +1074,6 @@ int elf_exec(const char *interp_prefix,
|
|||||||
else {
|
else {
|
||||||
bprm.fd = retval;
|
bprm.fd = retval;
|
||||||
}
|
}
|
||||||
bprm.interp_prefix = (char *)interp_prefix;
|
|
||||||
bprm.filename = (char *)filename;
|
bprm.filename = (char *)filename;
|
||||||
bprm.sh_bang = 0;
|
bprm.sh_bang = 0;
|
||||||
bprm.loader = 0;
|
bprm.loader = 0;
|
||||||
|
@@ -37,6 +37,8 @@
|
|||||||
IOCTL(TIOCNOTTY, 0, TYPE_NULL)
|
IOCTL(TIOCNOTTY, 0, TYPE_NULL)
|
||||||
IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
|
IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
|
||||||
IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
|
IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
|
||||||
|
IOCTL(TIOCGPTN, IOC_R, MK_PTR(TYPE_INT))
|
||||||
|
IOCTL(TIOCSPTLCK, IOC_W, MK_PTR(TYPE_INT))
|
||||||
IOCTL(FIOCLEX, 0, TYPE_NULL)
|
IOCTL(FIOCLEX, 0, TYPE_NULL)
|
||||||
IOCTL(FIONCLEX, 0, TYPE_NULL)
|
IOCTL(FIONCLEX, 0, TYPE_NULL)
|
||||||
IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
|
IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
|
||||||
|
@@ -23,9 +23,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
|
|
||||||
#include <sys/personality.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "qemu.h"
|
#include "qemu.h"
|
||||||
|
|
||||||
@@ -35,19 +32,28 @@
|
|||||||
|
|
||||||
FILE *logfile = NULL;
|
FILE *logfile = NULL;
|
||||||
int loglevel;
|
int loglevel;
|
||||||
const char *interp_prefix = CONFIG_QEMU_PREFIX "/qemu-i386";
|
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
/* Force usage of an ELF interpreter even if it is an ELF shared
|
/* Force usage of an ELF interpreter even if it is an ELF shared
|
||||||
object ! */
|
object ! */
|
||||||
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
|
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
|
||||||
|
|
||||||
|
/* for recent libc, we add these dummies symbol which are not declared
|
||||||
|
when generating a linked object (bug in ld ?) */
|
||||||
|
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
|
||||||
|
long __init_array_start[0];
|
||||||
|
long __init_array_end[0];
|
||||||
|
long __fini_array_start[0];
|
||||||
|
long __fini_array_end[0];
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
||||||
we allocate a bigger stack. Need a better solution, for example
|
we allocate a bigger stack. Need a better solution, for example
|
||||||
by remapping the process stack directly at the right place */
|
by remapping the process stack directly at the right place */
|
||||||
unsigned long x86_stack_size = 512 * 1024;
|
unsigned long x86_stack_size = 512 * 1024;
|
||||||
unsigned long stktop;
|
|
||||||
|
|
||||||
void gemu_log(const char *fmt, ...)
|
void gemu_log(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
@@ -359,7 +365,7 @@ void usage(void)
|
|||||||
DEBUG_LOGFILE,
|
DEBUG_LOGFILE,
|
||||||
interp_prefix,
|
interp_prefix,
|
||||||
x86_stack_size);
|
x86_stack_size);
|
||||||
exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: currently only used for async signals (see signal.c) */
|
/* XXX: currently only used for async signals (see signal.c) */
|
||||||
@@ -380,12 +386,6 @@ int main(int argc, char **argv)
|
|||||||
if (argc <= 1)
|
if (argc <= 1)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
/* Set personality to X86_LINUX. May fail on unpatched kernels:
|
|
||||||
if so, they need to have munged paths themselves (eg. chroot,
|
|
||||||
hacked ld.so, whatever). */
|
|
||||||
if (personality(0x11) >= 0)
|
|
||||||
interp_prefix = "";
|
|
||||||
|
|
||||||
loglevel = 0;
|
loglevel = 0;
|
||||||
optind = 1;
|
optind = 1;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
@@ -424,7 +424,7 @@ int main(int argc, char **argv)
|
|||||||
logfile = fopen(DEBUG_LOGFILE, "w");
|
logfile = fopen(DEBUG_LOGFILE, "w");
|
||||||
if (!logfile) {
|
if (!logfile) {
|
||||||
perror(DEBUG_LOGFILE);
|
perror(DEBUG_LOGFILE);
|
||||||
exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
setvbuf(logfile, NULL, _IOLBF, 0);
|
setvbuf(logfile, NULL, _IOLBF, 0);
|
||||||
}
|
}
|
||||||
@@ -435,9 +435,12 @@ int main(int argc, char **argv)
|
|||||||
/* Zero out image_info */
|
/* Zero out image_info */
|
||||||
memset(info, 0, sizeof(struct image_info));
|
memset(info, 0, sizeof(struct image_info));
|
||||||
|
|
||||||
if(elf_exec(interp_prefix, filename, argv+optind, environ, regs, info) != 0) {
|
/* Scan interp_prefix dir for replacement files. */
|
||||||
|
init_paths(interp_prefix);
|
||||||
|
|
||||||
|
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||||
printf("Error loading %s\n", filename);
|
printf("Error loading %s\n", filename);
|
||||||
exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loglevel) {
|
if (loglevel) {
|
||||||
|
142
linux-user/path.c
Normal file
142
linux-user/path.c
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/* Code to mangle pathnames into those matching a given prefix.
|
||||||
|
eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so");
|
||||||
|
|
||||||
|
The assumption is that this area does not change.
|
||||||
|
*/
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "qemu.h"
|
||||||
|
|
||||||
|
struct pathelem
|
||||||
|
{
|
||||||
|
/* Name of this, eg. lib */
|
||||||
|
char *name;
|
||||||
|
/* Full path name, eg. /usr/gnemul/x86-linux/lib. */
|
||||||
|
char *pathname;
|
||||||
|
struct pathelem *parent;
|
||||||
|
/* Children */
|
||||||
|
unsigned int num_entries;
|
||||||
|
struct pathelem *entries[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pathelem *base;
|
||||||
|
|
||||||
|
/* First N chars of S1 match S2, and S2 is N chars long. */
|
||||||
|
static int strneq(const char *s1, unsigned int n, const char *s2)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
if (s1[i] != s2[i])
|
||||||
|
return 0;
|
||||||
|
return s2[i] == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pathelem *add_entry(struct pathelem *root, const char *name);
|
||||||
|
|
||||||
|
static struct pathelem *new_entry(const char *root,
|
||||||
|
struct pathelem *parent,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct pathelem *new = malloc(sizeof(*new));
|
||||||
|
new->name = strdup(name);
|
||||||
|
asprintf(&new->pathname, "%s/%s", root, name);
|
||||||
|
new->num_entries = 0;
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define streq(a,b) (strcmp((a), (b)) == 0)
|
||||||
|
|
||||||
|
static struct pathelem *add_dir_maybe(struct pathelem *path)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
|
||||||
|
if ((dir = opendir(path->pathname)) != NULL) {
|
||||||
|
struct dirent *dirent;
|
||||||
|
|
||||||
|
while ((dirent = readdir(dir)) != NULL) {
|
||||||
|
if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
|
||||||
|
path = add_entry(path, dirent->d_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pathelem *add_entry(struct pathelem *root, const char *name)
|
||||||
|
{
|
||||||
|
root->num_entries++;
|
||||||
|
|
||||||
|
root = realloc(root, sizeof(*root)
|
||||||
|
+ sizeof(root->entries[0])*root->num_entries);
|
||||||
|
|
||||||
|
root->entries[root->num_entries-1] = new_entry(root->pathname, root, name);
|
||||||
|
root->entries[root->num_entries-1]
|
||||||
|
= add_dir_maybe(root->entries[root->num_entries-1]);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This needs to be done after tree is stabalized (ie. no more reallocs!). */
|
||||||
|
static void set_parents(struct pathelem *child, struct pathelem *parent)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
child->parent = parent;
|
||||||
|
for (i = 0; i < child->num_entries; i++)
|
||||||
|
set_parents(child->entries[i], child);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_paths(const char *prefix)
|
||||||
|
{
|
||||||
|
if (prefix[0] != '/' ||
|
||||||
|
prefix[0] == '\0' ||
|
||||||
|
!strcmp(prefix, "/"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
base = new_entry("", NULL, prefix+1);
|
||||||
|
base = add_dir_maybe(base);
|
||||||
|
set_parents(base, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
|
||||||
|
static const char *
|
||||||
|
follow_path(const struct pathelem *cursor, const char *name)
|
||||||
|
{
|
||||||
|
unsigned int i, namelen;
|
||||||
|
|
||||||
|
name += strspn(name, "/");
|
||||||
|
namelen = strcspn(name, "/");
|
||||||
|
|
||||||
|
if (namelen == 0)
|
||||||
|
return cursor->pathname;
|
||||||
|
|
||||||
|
if (strneq(name, namelen, ".."))
|
||||||
|
return follow_path(cursor->parent, name + namelen);
|
||||||
|
|
||||||
|
if (strneq(name, namelen, "."))
|
||||||
|
return follow_path(cursor, name + namelen);
|
||||||
|
|
||||||
|
for (i = 0; i < cursor->num_entries; i++)
|
||||||
|
if (strneq(name, namelen, cursor->entries[i]->name))
|
||||||
|
return follow_path(cursor->entries[i], name + namelen);
|
||||||
|
|
||||||
|
/* Not found */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look for path in emulation dir, otherwise return name. */
|
||||||
|
const char *path(const char *name)
|
||||||
|
{
|
||||||
|
/* Only do absolute paths: quick and dirty, but should mostly be OK.
|
||||||
|
Could do relative by tracking cwd. */
|
||||||
|
if (!base || name[0] != '/')
|
||||||
|
return name;
|
||||||
|
|
||||||
|
return follow_path(base, name) ?: name;
|
||||||
|
}
|
@@ -60,8 +60,7 @@ typedef struct TaskState {
|
|||||||
|
|
||||||
extern TaskState *first_task_state;
|
extern TaskState *first_task_state;
|
||||||
|
|
||||||
int elf_exec(const char *interp_prefix,
|
int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||||
const char * filename, char ** argv, char ** envp,
|
|
||||||
struct target_pt_regs * regs, struct image_info *infop);
|
struct target_pt_regs * regs, struct image_info *infop);
|
||||||
|
|
||||||
void target_set_brk(char *new_brk);
|
void target_set_brk(char *new_brk);
|
||||||
@@ -75,5 +74,6 @@ void process_pending_signals(void *cpu_env);
|
|||||||
void signal_init(void);
|
void signal_init(void);
|
||||||
int queue_signal(int sig, target_siginfo_t *info);
|
int queue_signal(int sig, target_siginfo_t *info);
|
||||||
void save_v86_state(CPUX86State *env);
|
void save_v86_state(CPUX86State *env);
|
||||||
|
void init_paths(const char *prefix);
|
||||||
|
const char *path(const char *pathname);
|
||||||
#endif
|
#endif
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/ucontext.h>
|
#include <sys/ucontext.h>
|
||||||
|
@@ -105,6 +105,9 @@ _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
|
|||||||
_syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf)
|
_syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf)
|
||||||
_syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf)
|
_syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf)
|
||||||
_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
|
_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
|
||||||
|
#ifdef __NR_exit_group
|
||||||
|
_syscall1(int,exit_group,int,error_code)
|
||||||
|
#endif
|
||||||
|
|
||||||
extern int personality(int);
|
extern int personality(int);
|
||||||
extern int flock(int, int);
|
extern int flock(int, int);
|
||||||
@@ -1212,7 +1215,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
ret = get_errno(write(arg1, (void *)arg2, arg3));
|
ret = get_errno(write(arg1, (void *)arg2, arg3));
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_open:
|
case TARGET_NR_open:
|
||||||
ret = get_errno(open((const char *)arg1, arg2, arg3));
|
ret = get_errno(open(path((const char *)arg1), arg2, arg3));
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_close:
|
case TARGET_NR_close:
|
||||||
ret = get_errno(close(arg1));
|
ret = get_errno(close(arg1));
|
||||||
@@ -1700,7 +1703,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
case TARGET_NR_oldlstat:
|
case TARGET_NR_oldlstat:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
case TARGET_NR_readlink:
|
case TARGET_NR_readlink:
|
||||||
ret = get_errno(readlink((const char *)arg1, (char *)arg2, arg3));
|
ret = get_errno(readlink(path((const char *)arg1), (char *)arg2, arg3));
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_uselib:
|
case TARGET_NR_uselib:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
@@ -1779,7 +1782,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
case TARGET_NR_statfs:
|
case TARGET_NR_statfs:
|
||||||
stfs = (void *)arg2;
|
stfs = (void *)arg2;
|
||||||
ret = get_errno(sys_statfs((const char *)arg1, stfs));
|
ret = get_errno(sys_statfs(path((const char *)arg1), stfs));
|
||||||
convert_statfs:
|
convert_statfs:
|
||||||
if (!is_error(ret)) {
|
if (!is_error(ret)) {
|
||||||
tswap32s(&stfs->f_type);
|
tswap32s(&stfs->f_type);
|
||||||
@@ -1844,10 +1847,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TARGET_NR_stat:
|
case TARGET_NR_stat:
|
||||||
ret = get_errno(stat((const char *)arg1, &st));
|
ret = get_errno(stat(path((const char *)arg1), &st));
|
||||||
goto do_stat;
|
goto do_stat;
|
||||||
case TARGET_NR_lstat:
|
case TARGET_NR_lstat:
|
||||||
ret = get_errno(lstat((const char *)arg1, &st));
|
ret = get_errno(lstat(path((const char *)arg1), &st));
|
||||||
goto do_stat;
|
goto do_stat;
|
||||||
case TARGET_NR_fstat:
|
case TARGET_NR_fstat:
|
||||||
{
|
{
|
||||||
@@ -1857,7 +1860,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
struct target_stat *target_st = (void *)arg2;
|
struct target_stat *target_st = (void *)arg2;
|
||||||
target_st->st_dev = tswap16(st.st_dev);
|
target_st->st_dev = tswap16(st.st_dev);
|
||||||
target_st->st_ino = tswapl(st.st_ino);
|
target_st->st_ino = tswapl(st.st_ino);
|
||||||
target_st->st_mode = tswap32(st.st_mode);
|
target_st->st_mode = tswap16(st.st_mode);
|
||||||
target_st->st_nlink = tswap16(st.st_nlink);
|
target_st->st_nlink = tswap16(st.st_nlink);
|
||||||
target_st->st_uid = tswap16(st.st_uid);
|
target_st->st_uid = tswap16(st.st_uid);
|
||||||
target_st->st_gid = tswap16(st.st_gid);
|
target_st->st_gid = tswap16(st.st_gid);
|
||||||
@@ -1930,6 +1933,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
case TARGET_NR_clone:
|
case TARGET_NR_clone:
|
||||||
ret = get_errno(do_fork(cpu_env, arg1, arg2));
|
ret = get_errno(do_fork(cpu_env, arg1, arg2));
|
||||||
break;
|
break;
|
||||||
|
#ifdef __NR_exit_group
|
||||||
|
/* new thread calls */
|
||||||
|
case TARGET_NR_exit_group:
|
||||||
|
ret = get_errno(exit_group(arg1));
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case TARGET_NR_setdomainname:
|
case TARGET_NR_setdomainname:
|
||||||
ret = get_errno(setdomainname((const char *)arg1, arg2));
|
ret = get_errno(setdomainname((const char *)arg1, arg2));
|
||||||
break;
|
break;
|
||||||
@@ -2235,10 +2244,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
case TARGET_NR_ftruncate64:
|
case TARGET_NR_ftruncate64:
|
||||||
goto unimplemented;
|
goto unimplemented;
|
||||||
case TARGET_NR_stat64:
|
case TARGET_NR_stat64:
|
||||||
ret = get_errno(stat((const char *)arg1, &st));
|
ret = get_errno(stat(path((const char *)arg1), &st));
|
||||||
goto do_stat64;
|
goto do_stat64;
|
||||||
case TARGET_NR_lstat64:
|
case TARGET_NR_lstat64:
|
||||||
ret = get_errno(lstat((const char *)arg1, &st));
|
ret = get_errno(lstat(path((const char *)arg1), &st));
|
||||||
goto do_stat64;
|
goto do_stat64;
|
||||||
case TARGET_NR_fstat64:
|
case TARGET_NR_fstat64:
|
||||||
{
|
{
|
||||||
@@ -2246,15 +2255,19 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|||||||
do_stat64:
|
do_stat64:
|
||||||
if (!is_error(ret)) {
|
if (!is_error(ret)) {
|
||||||
struct target_stat64 *target_st = (void *)arg2;
|
struct target_stat64 *target_st = (void *)arg2;
|
||||||
|
memset(target_st, 0, sizeof(struct target_stat64));
|
||||||
target_st->st_dev = tswap16(st.st_dev);
|
target_st->st_dev = tswap16(st.st_dev);
|
||||||
target_st->st_ino = tswapl(st.st_ino);
|
target_st->st_ino = tswapl(st.st_ino);
|
||||||
|
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
|
||||||
|
target_st->__st_ino = tswapl(st.st_ino);
|
||||||
|
#endif
|
||||||
target_st->st_mode = tswap32(st.st_mode);
|
target_st->st_mode = tswap32(st.st_mode);
|
||||||
target_st->st_nlink = tswap16(st.st_nlink);
|
target_st->st_nlink = tswap32(st.st_nlink);
|
||||||
target_st->st_uid = tswap16(st.st_uid);
|
target_st->st_uid = tswapl(st.st_uid);
|
||||||
target_st->st_gid = tswap16(st.st_gid);
|
target_st->st_gid = tswapl(st.st_gid);
|
||||||
target_st->st_rdev = tswap16(st.st_rdev);
|
target_st->st_rdev = tswap16(st.st_rdev);
|
||||||
/* XXX: better use of kernel struct */
|
/* XXX: better use of kernel struct */
|
||||||
target_st->st_size = tswapl(st.st_size);
|
target_st->st_size = tswap64(st.st_size);
|
||||||
target_st->st_blksize = tswapl(st.st_blksize);
|
target_st->st_blksize = tswapl(st.st_blksize);
|
||||||
target_st->st_blocks = tswapl(st.st_blocks);
|
target_st->st_blocks = tswapl(st.st_blocks);
|
||||||
target_st->target_st_atime = tswapl(st.st_atime);
|
target_st->target_st_atime = tswapl(st.st_atime);
|
||||||
|
@@ -36,6 +36,8 @@ User space LDT and GDT are emulated. VM86 mode is also supported
|
|||||||
|
|
||||||
@item Accurate signal handling by remapping host signals to virtual x86 signals.
|
@item Accurate signal handling by remapping host signals to virtual x86 signals.
|
||||||
|
|
||||||
|
@item QEMU can emulate itself on x86 (experimental).
|
||||||
|
|
||||||
@item The virtual x86 CPU is a library (@code{libqemu}) which can be used
|
@item The virtual x86 CPU is a library (@code{libqemu}) which can be used
|
||||||
in other projects.
|
in other projects.
|
||||||
|
|
||||||
@@ -50,9 +52,7 @@ Current QEMU Limitations:
|
|||||||
|
|
||||||
@item Not all x86 exceptions are precise (yet). [Very few programs need that].
|
@item Not all x86 exceptions are precise (yet). [Very few programs need that].
|
||||||
|
|
||||||
@item Not self virtualizable (yet). [You cannot launch qemu with qemu on the same CPU].
|
@item No support for self-modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !].
|
||||||
|
|
||||||
@item No support for self modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !].
|
|
||||||
|
|
||||||
@item No SSE/MMX support (yet).
|
@item No SSE/MMX support (yet).
|
||||||
|
|
||||||
@@ -88,9 +88,14 @@ qemu -L / /bin/ls
|
|||||||
@code{-L /} tells that the x86 dynamic linker must be searched with a
|
@code{-L /} tells that the x86 dynamic linker must be searched with a
|
||||||
@file{/} prefix.
|
@file{/} prefix.
|
||||||
|
|
||||||
|
@item Since QEMU is also a linux process, you can launch qemu with qemu:
|
||||||
|
|
||||||
|
@example
|
||||||
|
qemu -L / qemu -L / /bin/ls
|
||||||
|
@end example
|
||||||
|
|
||||||
@item On non x86 CPUs, you need first to download at least an x86 glibc
|
@item On non x86 CPUs, you need first to download at least an x86 glibc
|
||||||
(@file{qemu-i386-glibc21.tar.gz} on the QEMU web page). Ensure that
|
(@file{qemu-XXX-i386-glibc21.tar.gz} on the QEMU web page). Ensure that
|
||||||
@code{LD_LIBRARY_PATH} is not set:
|
@code{LD_LIBRARY_PATH} is not set:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
@@ -107,6 +112,11 @@ QEMU is automatically launched by the Linux kernel when you try to
|
|||||||
launch x86 executables. It requires the @code{binfmt_misc} module in the
|
launch x86 executables. It requires the @code{binfmt_misc} module in the
|
||||||
Linux kernel.
|
Linux kernel.
|
||||||
|
|
||||||
|
@item The x86 version of QEMU is also included. You can try weird things such as:
|
||||||
|
@example
|
||||||
|
qemu /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
|
||||||
|
@end example
|
||||||
|
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@section Wine launch (Currently only tested when emulating x86 on x86)
|
@section Wine launch (Currently only tested when emulating x86 on x86)
|
||||||
@@ -122,7 +132,7 @@ qemu /usr/local/qemu-i386/bin/ls-i386
|
|||||||
@end example
|
@end example
|
||||||
|
|
||||||
@item Download the binary x86 Wine install
|
@item Download the binary x86 Wine install
|
||||||
(@file{qemu-i386-wine.tar.gz} on the QEMU web page).
|
(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page).
|
||||||
|
|
||||||
@item Configure Wine on your account. Look at the provided script
|
@item Configure Wine on your account. Look at the provided script
|
||||||
@file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous
|
@file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous
|
||||||
@@ -302,6 +312,21 @@ thread.
|
|||||||
The virtual x86 CPU atomic operations are emulated with a global lock so
|
The virtual x86 CPU atomic operations are emulated with a global lock so
|
||||||
that their semantic is preserved.
|
that their semantic is preserved.
|
||||||
|
|
||||||
|
@section Self-virtualization
|
||||||
|
|
||||||
|
QEMU was conceived so that ultimately it can emulate itself. Althought
|
||||||
|
it is not very useful, it is an important test to show the power of the
|
||||||
|
emulator.
|
||||||
|
|
||||||
|
Achieving self-virtualization is not easy because there may be address
|
||||||
|
space conflicts. QEMU solves this problem by being an ELF shared object
|
||||||
|
as the ld-linux.so ELF interpreter. That way, it can be relocated at
|
||||||
|
load time.
|
||||||
|
|
||||||
|
Since self-modifying code is not supported yet, QEMU cannot self
|
||||||
|
virtualize itself in case of translation cache flush. This limitation
|
||||||
|
will be suppressed soon.
|
||||||
|
|
||||||
@section Bibliography
|
@section Bibliography
|
||||||
|
|
||||||
@table @asis
|
@table @asis
|
||||||
|
@@ -302,7 +302,7 @@ struct target_stat64 {
|
|||||||
unsigned short st_dev;
|
unsigned short st_dev;
|
||||||
unsigned char __pad0[10];
|
unsigned char __pad0[10];
|
||||||
|
|
||||||
#define STAT64_HAS_BROKEN_ST_INO 1
|
#define TARGET_STAT64_HAS_BROKEN_ST_INO 1
|
||||||
target_ulong __st_ino;
|
target_ulong __st_ino;
|
||||||
|
|
||||||
unsigned int st_mode;
|
unsigned int st_mode;
|
||||||
@@ -572,8 +572,8 @@ struct target_pt_regs {
|
|||||||
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
|
||||||
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
|
||||||
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
|
||||||
#define TARGET_TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
|
||||||
#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
|
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
|
||||||
|
|
||||||
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
||||||
#define TARGET_FIOCLEX 0x5451
|
#define TARGET_FIOCLEX 0x5451
|
||||||
|
28
tests/.cvsignore
Normal file
28
tests/.cvsignore
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
gmon.out
|
||||||
|
testsig
|
||||||
|
hello
|
||||||
|
sha1.test.c
|
||||||
|
sha1.c
|
||||||
|
op.c
|
||||||
|
test-i386
|
||||||
|
sha1
|
||||||
|
testclone
|
||||||
|
interp.h
|
||||||
|
interploop.c
|
||||||
|
.gdb_history
|
||||||
|
cachegrind.out
|
||||||
|
interp.c
|
||||||
|
interp
|
||||||
|
testthread
|
||||||
|
test-i386.s
|
||||||
|
test-i386.ref
|
||||||
|
sha1-i386
|
||||||
|
runcom
|
||||||
|
debug.com
|
||||||
|
test-i386.out
|
||||||
|
speed.txt
|
||||||
|
test-i386.ref.P3
|
||||||
|
pi_10.com
|
||||||
|
test-i386.ref.P4
|
||||||
|
ldso.c
|
||||||
|
test_path
|
@@ -6,7 +6,7 @@ LDFLAGS=
|
|||||||
ifeq ($(ARCH),i386)
|
ifeq ($(ARCH),i386)
|
||||||
TESTS=testclone testsig testthread sha1-i386 test-i386 runcom
|
TESTS=testclone testsig testthread sha1-i386 test-i386 runcom
|
||||||
endif
|
endif
|
||||||
TESTS+=sha1
|
TESTS+=sha1 test_path
|
||||||
|
|
||||||
QEMU=../qemu
|
QEMU=../qemu
|
||||||
|
|
||||||
@@ -25,6 +25,10 @@ testsig: testsig.c
|
|||||||
testthread: testthread.c
|
testthread: testthread.c
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
|
||||||
|
|
||||||
|
test_path: test_path.c
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
|
||||||
|
./$@ || { rm $@; exit 1; }
|
||||||
|
|
||||||
# i386 emulation test (test various opcodes) */
|
# i386 emulation test (test various opcodes) */
|
||||||
test-i386: test-i386.c test-i386-code16.S \
|
test-i386: test-i386.c test-i386-code16.S \
|
||||||
test-i386.h test-i386-shift.h test-i386-muldiv.h
|
test-i386.h test-i386-shift.h test-i386-muldiv.h
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -14,6 +15,12 @@
|
|||||||
|
|
||||||
//#define SIGTEST
|
//#define SIGTEST
|
||||||
|
|
||||||
|
#undef __syscall_return
|
||||||
|
#define __syscall_return(type, res) \
|
||||||
|
do { \
|
||||||
|
return (type) (res); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)
|
_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)
|
||||||
|
|
||||||
#define COM_BASE_ADDR 0x10100
|
#define COM_BASE_ADDR 0x10100
|
||||||
|
@@ -108,7 +108,12 @@ void exec_opb(int s0, int s1, int iflags)
|
|||||||
void exec_op(int s2, int s0, int s1)
|
void exec_op(int s2, int s0, int s1)
|
||||||
{
|
{
|
||||||
exec_opl(s2, s0, s1, 0);
|
exec_opl(s2, s0, s1, 0);
|
||||||
|
#ifdef OP_SHIFTD
|
||||||
|
if (s1 <= 15)
|
||||||
|
exec_opw(s2, s0, s1, 0);
|
||||||
|
#else
|
||||||
exec_opw(s2, s0, s1, 0);
|
exec_opw(s2, s0, s1, 0);
|
||||||
|
#endif
|
||||||
#ifndef OP_NOBYTE
|
#ifndef OP_NOBYTE
|
||||||
exec_opb(s0, s1, 0);
|
exec_opb(s0, s1, 0);
|
||||||
#endif
|
#endif
|
||||||
|
152
tests/test_path.c
Normal file
152
tests/test_path.c
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/* Test path override code */
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include "../path.c"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
/* Any log message kills the test. */
|
||||||
|
void gemu_log(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
fprintf(stderr, "FATAL: ");
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NO_CHANGE(_path) \
|
||||||
|
do { \
|
||||||
|
if (strcmp(path(_path), _path) != 0) return __LINE__; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define CHANGE_TO(_path, _newpath) \
|
||||||
|
do { \
|
||||||
|
if (strcmp(path(_path), _newpath) != 0) return __LINE__; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
static void cleanup(void)
|
||||||
|
{
|
||||||
|
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||||
|
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE2");
|
||||||
|
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE3");
|
||||||
|
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE4");
|
||||||
|
unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE5");
|
||||||
|
rmdir("/tmp/qemu-test_path/DIR1/DIR2");
|
||||||
|
rmdir("/tmp/qemu-test_path/DIR1/DIR3");
|
||||||
|
rmdir("/tmp/qemu-test_path/DIR1");
|
||||||
|
rmdir("/tmp/qemu-test_path");
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int do_test(void)
|
||||||
|
{
|
||||||
|
if (mkdir("/tmp/qemu-test_path", 0700) != 0)
|
||||||
|
return __LINE__;
|
||||||
|
|
||||||
|
if (mkdir("/tmp/qemu-test_path/DIR1", 0700) != 0)
|
||||||
|
return __LINE__;
|
||||||
|
|
||||||
|
if (mkdir("/tmp/qemu-test_path/DIR1/DIR2", 0700) != 0)
|
||||||
|
return __LINE__;
|
||||||
|
|
||||||
|
if (mkdir("/tmp/qemu-test_path/DIR1/DIR3", 0700) != 0)
|
||||||
|
return __LINE__;
|
||||||
|
|
||||||
|
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE", 0600)) != 0)
|
||||||
|
return __LINE__;
|
||||||
|
|
||||||
|
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE2", 0600)) != 0)
|
||||||
|
return __LINE__;
|
||||||
|
|
||||||
|
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE3", 0600)) != 0)
|
||||||
|
return __LINE__;
|
||||||
|
|
||||||
|
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE4", 0600)) != 0)
|
||||||
|
return __LINE__;
|
||||||
|
|
||||||
|
if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE5", 0600)) != 0)
|
||||||
|
return __LINE__;
|
||||||
|
|
||||||
|
init_paths("/tmp/qemu-test_path");
|
||||||
|
|
||||||
|
NO_CHANGE("/tmp");
|
||||||
|
NO_CHANGE("/tmp/");
|
||||||
|
NO_CHANGE("/tmp/qemu-test_path");
|
||||||
|
NO_CHANGE("/tmp/qemu-test_path/");
|
||||||
|
NO_CHANGE("/tmp/qemu-test_path/D");
|
||||||
|
NO_CHANGE("/tmp/qemu-test_path/DI");
|
||||||
|
NO_CHANGE("/tmp/qemu-test_path/DIR");
|
||||||
|
NO_CHANGE("/tmp/qemu-test_path/DIR1");
|
||||||
|
NO_CHANGE("/tmp/qemu-test_path/DIR1/");
|
||||||
|
|
||||||
|
NO_CHANGE("/D");
|
||||||
|
NO_CHANGE("/DI");
|
||||||
|
NO_CHANGE("/DIR");
|
||||||
|
NO_CHANGE("/DIR2");
|
||||||
|
NO_CHANGE("/DIR1.");
|
||||||
|
|
||||||
|
CHANGE_TO("/DIR1", "/tmp/qemu-test_path/DIR1");
|
||||||
|
CHANGE_TO("/DIR1/", "/tmp/qemu-test_path/DIR1");
|
||||||
|
|
||||||
|
NO_CHANGE("/DIR1/D");
|
||||||
|
NO_CHANGE("/DIR1/DI");
|
||||||
|
NO_CHANGE("/DIR1/DIR");
|
||||||
|
NO_CHANGE("/DIR1/DIR1");
|
||||||
|
|
||||||
|
CHANGE_TO("/DIR1/DIR2", "/tmp/qemu-test_path/DIR1/DIR2");
|
||||||
|
CHANGE_TO("/DIR1/DIR2/", "/tmp/qemu-test_path/DIR1/DIR2");
|
||||||
|
|
||||||
|
CHANGE_TO("/DIR1/DIR3", "/tmp/qemu-test_path/DIR1/DIR3");
|
||||||
|
CHANGE_TO("/DIR1/DIR3/", "/tmp/qemu-test_path/DIR1/DIR3");
|
||||||
|
|
||||||
|
NO_CHANGE("/DIR1/DIR2/F");
|
||||||
|
NO_CHANGE("/DIR1/DIR2/FI");
|
||||||
|
NO_CHANGE("/DIR1/DIR2/FIL");
|
||||||
|
NO_CHANGE("/DIR1/DIR2/FIL.");
|
||||||
|
|
||||||
|
CHANGE_TO("/DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||||
|
CHANGE_TO("/DIR1/DIR2/FILE2", "/tmp/qemu-test_path/DIR1/DIR2/FILE2");
|
||||||
|
CHANGE_TO("/DIR1/DIR2/FILE3", "/tmp/qemu-test_path/DIR1/DIR2/FILE3");
|
||||||
|
CHANGE_TO("/DIR1/DIR2/FILE4", "/tmp/qemu-test_path/DIR1/DIR2/FILE4");
|
||||||
|
CHANGE_TO("/DIR1/DIR2/FILE5", "/tmp/qemu-test_path/DIR1/DIR2/FILE5");
|
||||||
|
|
||||||
|
NO_CHANGE("/DIR1/DIR2/FILE6");
|
||||||
|
NO_CHANGE("/DIR1/DIR2/FILE/X");
|
||||||
|
|
||||||
|
CHANGE_TO("/DIR1/../DIR1", "/tmp/qemu-test_path/DIR1");
|
||||||
|
CHANGE_TO("/DIR1/../DIR1/", "/tmp/qemu-test_path/DIR1");
|
||||||
|
CHANGE_TO("/../DIR1", "/tmp/qemu-test_path/DIR1");
|
||||||
|
CHANGE_TO("/../DIR1/", "/tmp/qemu-test_path/DIR1");
|
||||||
|
CHANGE_TO("/DIR1/DIR2/../DIR2", "/tmp/qemu-test_path/DIR1/DIR2");
|
||||||
|
CHANGE_TO("/DIR1/DIR2/../DIR2/../../DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||||
|
CHANGE_TO("/DIR1/DIR2/../DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||||
|
|
||||||
|
NO_CHANGE("/DIR1/DIR2/../DIR1");
|
||||||
|
NO_CHANGE("/DIR1/DIR2/../FILE");
|
||||||
|
|
||||||
|
CHANGE_TO("/./DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||||
|
CHANGE_TO("/././DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||||
|
CHANGE_TO("/DIR1/./DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||||
|
CHANGE_TO("/DIR1/././DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||||
|
CHANGE_TO("/DIR1/DIR2/./FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||||
|
CHANGE_TO("/DIR1/DIR2/././FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||||
|
CHANGE_TO("/./DIR1/./DIR2/./FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = do_test();
|
||||||
|
cleanup();
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "test_path: failed on line %i\n", ret);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@@ -1,5 +1,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
18
thunk.h
18
thunk.h
@@ -94,17 +94,17 @@ static inline uint64_t bswap64(uint64_t x)
|
|||||||
return bswap_64(x);
|
return bswap_64(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inline bswap16s(uint16_t *s)
|
static inline void bswap16s(uint16_t *s)
|
||||||
{
|
{
|
||||||
*s = bswap16(*s);
|
*s = bswap16(*s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inline bswap32s(uint32_t *s)
|
static inline void bswap32s(uint32_t *s)
|
||||||
{
|
{
|
||||||
*s = bswap32(*s);
|
*s = bswap32(*s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inline bswap64s(uint64_t *s)
|
static inline void bswap64s(uint64_t *s)
|
||||||
{
|
{
|
||||||
*s = bswap64(*s);
|
*s = bswap64(*s);
|
||||||
}
|
}
|
||||||
@@ -126,17 +126,17 @@ static inline uint64_t tswap64(uint64_t s)
|
|||||||
return bswap64(s);
|
return bswap64(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inline tswap16s(uint16_t *s)
|
static inline void tswap16s(uint16_t *s)
|
||||||
{
|
{
|
||||||
*s = bswap16(*s);
|
*s = bswap16(*s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inline tswap32s(uint32_t *s)
|
static inline void tswap32s(uint32_t *s)
|
||||||
{
|
{
|
||||||
*s = bswap32(*s);
|
*s = bswap32(*s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inline tswap64s(uint64_t *s)
|
static inline void tswap64s(uint64_t *s)
|
||||||
{
|
{
|
||||||
*s = bswap64(*s);
|
*s = bswap64(*s);
|
||||||
}
|
}
|
||||||
@@ -158,15 +158,15 @@ static inline uint64_t tswap64(uint64_t s)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inline tswap16s(uint16_t *s)
|
static inline void tswap16s(uint16_t *s)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inline tswap32s(uint32_t *s)
|
static inline void tswap32s(uint32_t *s)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inline tswap64s(uint64_t *s)
|
static inline void tswap64s(uint64_t *s)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user