Compare commits

..

12 Commits

Author SHA1 Message Date
bellard
1eb87257da update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@97 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 01:12:28 +00:00
bellard
32ce63371a path patch
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@96 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:16:16 +00:00
bellard
ec86b0fb3a stat patches - path patches - added exit_group() syscall
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@95 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:15:04 +00:00
bellard
1d346ae63a added prefix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@94 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:14:24 +00:00
bellard
74cd30b811 RH9 fix - path patch
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@93 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:13:41 +00:00
bellard
7fb9a24e39 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@92 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:13:04 +00:00
bellard
afeb6ee377 suppressed undefined shldw shrdw
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@91 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-11 00:12:54 +00:00
bellard
f29042b531 TIOCGPTN and TIOCSPTLCK ioctls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@90 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:12:45 +00:00
bellard
09bfb054fb first self virtualizable version
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@89 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:03:40 +00:00
bellard
2677e107e6 warning fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@88 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:03:27 +00:00
bellard
66cd58461d update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@87 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:02:58 +00:00
bellard
bb0ebb1f2d ISO C fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@86 c046a42c-6fe2-441c-8c8c-71466251a162
2003-04-10 00:02:33 +00:00
24 changed files with 681 additions and 177 deletions

View File

@@ -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:
- ppc64 support + personality() patch (Rusty Russell)

View File

@@ -45,7 +45,7 @@ LDFLAGS+=-p
main.o: CFLAGS+=-p
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)
OBJS+= libqemu.a
@@ -105,18 +105,19 @@ qemu-doc.html: qemu-doc.texi
FILES= \
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
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\
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-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/test-i386.c tests/test-i386-shift.h tests/test-i386.h\
tests/test-i386-muldiv.h tests/test-i386-code16.S\
tests/hello.c tests/hello tests/sha1.c \
tests/testsig.c tests/testclone.c tests/testthread.c \
tests/runcom.c tests/pi_10.com \
tests/test_path.c \
qemu-doc.texi qemu-doc.html
FILE=qemu-$(VERSION)
@@ -132,10 +133,10 @@ tar:
BINPATH=/usr/local/qemu-i386
tarbin:
tar zcvf /tmp/qemu-i386-glibc21.tar.gz \
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin
tar zcvf /tmp/qemu-i386-wine.tar.gz \
$(BINPATH)/X11R6 $(BINPATH)/wine
tar zcvf /tmp/qemu-$(VERSION)-i386-glibc21.tar.gz \
$(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin $(BINPATH)/usr
tar zcvf /tmp/qemu-$(VERSION)-i386-wine.tar.gz \
$(BINPATH)/wine
ifneq ($(wildcard .depend),)
include .depend

4
README
View File

@@ -6,7 +6,7 @@ INSTALLATION
Type
./configure
./configure --interp-prefix=/usr/local/qemu-i386
make
to build qemu and libqemu.a.
@@ -23,7 +23,7 @@ libraries installed on your PC. For example:
./qemu -L / /bin/ls
* 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:
unset LD_LIBRARY_PATH

3
TODO
View File

@@ -7,5 +7,6 @@
issues, fix 16 bit uid issues)
- finish signal handing (fp87 state, more siginfo conversions)
- 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)

View File

@@ -1 +1 @@
0.1.5
0.1.6

9
configure vendored
View File

@@ -19,6 +19,7 @@ TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h"
# default parameters
prefix="/usr/local"
interp_prefix="/usr/gnemul/qemu-i386"
cross_prefix=""
cc="gcc"
host_cc="gcc"
@@ -89,6 +90,8 @@ for opt do
case "$opt" in
--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`
;;
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
@@ -172,7 +175,7 @@ EOF
echo "Standard options:"
echo " --help print this message"
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 "Advanced options (experts only):"
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 "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 "CC=$cc" >> config.mak
echo "GCC_MAJOR=$gcc_major" >> config.mak
@@ -268,4 +271,4 @@ else
echo "config.h is unchanged"
fi
rm -f $TMPH
rm -f $TMPO $TMPC $TMPE $TMPS $TMPH

View File

@@ -33,12 +33,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
* the Intel manual for details.
*/
#include <stdlib.h>
#include <setjmp.h>
#include "dis-asm.h"
#define MAXLEN 20
#include <setjmp.h>
static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
struct dis_private

View File

@@ -49,9 +49,77 @@ typedef struct user_i387_struct elf_fpregset_t;
#endif
#include "linux_bin.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 */
#define ALPHA_PAGE_SIZE 4096
@@ -78,8 +146,18 @@ typedef struct user_i387_struct elf_fpregset_t;
#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();
#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,
struct image_info * info)
{
unsigned long stack_base;
unsigned long stack_base, size, error;
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
* it for args, we'll use it for something else...
*/
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
by remapping the process stack directly at the right place */
if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) {
if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
perror("stk mmap");
exit(-1);
}
size = x86_stack_size;
if (size < MAX_ARG_PAGES*X86_PAGE_SIZE)
size = MAX_ARG_PAGES*X86_PAGE_SIZE;
error = (unsigned long)mmap4k(NULL,
size + X86_PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
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);
stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE;
p += stack_base;
if (bprm->loader) {
bprm->loader += stack_base;
}
stktop = stack_base;
bprm->exec += stack_base;
for (i = 0 ; i < MAX_ARG_PAGES ; 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,
struct elfhdr * exec,
unsigned long load_addr,
unsigned long interp_load_addr, int ibcs,
struct image_info *info)
struct elfhdr * exec,
unsigned long load_addr,
unsigned long load_bias,
unsigned long interp_load_addr, int ibcs,
struct image_info *info)
{
target_ulong *argv, *envp, *dlinfo;
target_ulong *sp;
@@ -397,17 +468,17 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
put_user (tswapl(val), dlinfo++)
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_PHENT, (unsigned int)(sizeof (struct elf_phdr)));
NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum));
NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE));
NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr));
NEW_AUX_ENT (AT_FLAGS, (unsigned int)0);
NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry);
NEW_AUX_ENT (AT_UID, (unsigned int) getuid());
NEW_AUX_ENT (AT_EUID, (unsigned int) geteuid());
NEW_AUX_ENT (AT_GID, (unsigned int) getgid());
NEW_AUX_ENT (AT_EGID, (unsigned int) getegid());
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(ALPHA_PAGE_SIZE));
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
}
NEW_AUX_ENT (AT_NULL, 0);
#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 *eppnt;
unsigned long load_addr;
unsigned long load_addr = 0;
int load_addr_set = 0;
int retval;
unsigned long last_bss, elf_bss;
@@ -447,17 +518,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
last_bss = 0;
error = 0;
/* We put this here so that mmap will search for the *first*
* available memory...
*/
load_addr = INTERP_LOADADDR;
#ifdef BSWAP_NEEDED
bswap_ehdr(interp_elf_ex);
#endif
/* First of all, some simple consistency checks */
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)) {
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
* 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);
return ~0UL;
}
}
retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
if(retval >= 0) {
@@ -502,6 +567,21 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
bswap_phdr(eppnt);
}
#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;
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
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 exec interp_ex;
int interpreter_fd = -1; /* avoid warning */
unsigned long load_addr;
unsigned long load_addr, load_bias;
int load_addr_set = 0;
unsigned int interpreter_type = INTERPRETER_NONE;
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;
status = 0;
load_addr = 0;
load_bias = 0;
elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
#ifdef BSWAP_NEEDED
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
*/
elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+
strlen(bprm->interp_prefix));
elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
if (elf_interpreter == NULL) {
free (elf_phdata);
@@ -683,12 +763,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
return -ENOMEM;
}
strcpy(elf_interpreter, bprm->interp_prefix);
retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
if(retval >= 0) {
retval = read(bprm->fd,
elf_interpreter+strlen(bprm->interp_prefix),
elf_ppnt->p_filesz);
retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
}
if(retval < 0) {
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);
#endif
if (retval >= 0) {
retval = open(elf_interpreter, O_RDONLY);
retval = open(path(elf_interpreter), O_RDONLY);
if(retval >= 0) {
interpreter_fd = retval;
}
@@ -810,56 +887,86 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
* address.
*/
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;
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;
mapped_addr = mmap4k(X86_ELF_PAGESTART(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((unsigned long)mapped_addr == 0xffffffffffffffff) {
perror("mmap");
exit(-1);
}
int elf_prot = 0;
int elf_flags = 0;
unsigned long error;
if (elf_ppnt->p_type != PT_LOAD)
continue;
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
if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr);
if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr);
#endif
if (!load_addr_set) {
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
load_addr_set = 1;
}
k = elf_ppnt->p_vaddr;
if (k < start_code) start_code = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
if (k > elf_bss) elf_bss = k;
#if 1
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
#else
if ( !(elf_ppnt->p_flags & PF_W) && end_code < k)
#endif
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;
}
if (!load_addr_set) {
load_addr_set = 1;
load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
if (elf_ex.e_type == ET_DYN) {
load_bias += error -
X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
load_addr += load_bias;
}
}
k = elf_ppnt->p_vaddr;
if (k < start_code)
start_code = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
if (k > elf_bss)
elf_bss = k;
if ((elf_ppnt->p_flags & PF_X) && end_code < 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 (interpreter_type & 1) {
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->envc,
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
load_addr,
load_addr, load_bias,
interp_load_addr,
(interpreter_type == INTERPRETER_AOUT ? 0 : 1),
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,
const char * filename, char ** argv, char ** envp,
int elf_exec(const char * filename, char ** argv, char ** envp,
struct target_pt_regs * regs, struct image_info *infop)
{
struct linux_binprm bprm;
@@ -968,7 +1074,6 @@ int elf_exec(const char *interp_prefix,
else {
bprm.fd = retval;
}
bprm.interp_prefix = (char *)interp_prefix;
bprm.filename = (char *)filename;
bprm.sh_bang = 0;
bprm.loader = 0;

View File

@@ -37,6 +37,8 @@
IOCTL(TIOCNOTTY, 0, TYPE_NULL)
IOCTL(TIOCGETD, IOC_R, 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(FIONCLEX, 0, TYPE_NULL)
IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))

View File

@@ -23,9 +23,6 @@
#include <string.h>
#include <errno.h>
#include <unistd.h>
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
#include <sys/personality.h>
#endif
#include "qemu.h"
@@ -35,19 +32,28 @@
FILE *logfile = NULL;
int loglevel;
const char *interp_prefix = CONFIG_QEMU_PREFIX "/qemu-i386";
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
#ifdef __i386__
/* Force usage of an ELF interpreter even if it is an ELF shared
object ! */
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
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
by remapping the process stack directly at the right place */
unsigned long x86_stack_size = 512 * 1024;
unsigned long stktop;
void gemu_log(const char *fmt, ...)
{
@@ -359,7 +365,7 @@ void usage(void)
DEBUG_LOGFILE,
interp_prefix,
x86_stack_size);
exit(1);
_exit(1);
}
/* XXX: currently only used for async signals (see signal.c) */
@@ -380,12 +386,6 @@ int main(int argc, char **argv)
if (argc <= 1)
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;
optind = 1;
for(;;) {
@@ -424,7 +424,7 @@ int main(int argc, char **argv)
logfile = fopen(DEBUG_LOGFILE, "w");
if (!logfile) {
perror(DEBUG_LOGFILE);
exit(1);
_exit(1);
}
setvbuf(logfile, NULL, _IOLBF, 0);
}
@@ -435,9 +435,12 @@ int main(int argc, char **argv)
/* Zero out 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);
exit(1);
_exit(1);
}
if (loglevel) {

142
linux-user/path.c Normal file
View 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;
}

View File

@@ -60,8 +60,7 @@ typedef struct TaskState {
extern TaskState *first_task_state;
int elf_exec(const char *interp_prefix,
const char * filename, char ** argv, char ** envp,
int elf_exec(const char * filename, char ** argv, char ** envp,
struct target_pt_regs * regs, struct image_info *infop);
void target_set_brk(char *new_brk);
@@ -75,5 +74,6 @@ void process_pending_signals(void *cpu_env);
void signal_init(void);
int queue_signal(int sig, target_siginfo_t *info);
void save_v86_state(CPUX86State *env);
void init_paths(const char *prefix);
const char *path(const char *pathname);
#endif

View File

@@ -21,6 +21,7 @@
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/ucontext.h>

View File

@@ -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_fstatfs,int,fd,struct kernel_statfs *,buf)
_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 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));
break;
case TARGET_NR_open:
ret = get_errno(open((const char *)arg1, arg2, arg3));
ret = get_errno(open(path((const char *)arg1), arg2, arg3));
break;
case TARGET_NR_close:
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:
goto unimplemented;
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;
case TARGET_NR_uselib:
goto unimplemented;
@@ -1779,7 +1782,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
goto unimplemented;
case TARGET_NR_statfs:
stfs = (void *)arg2;
ret = get_errno(sys_statfs((const char *)arg1, stfs));
ret = get_errno(sys_statfs(path((const char *)arg1), stfs));
convert_statfs:
if (!is_error(ret)) {
tswap32s(&stfs->f_type);
@@ -1844,10 +1847,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
break;
case TARGET_NR_stat:
ret = get_errno(stat((const char *)arg1, &st));
ret = get_errno(stat(path((const char *)arg1), &st));
goto do_stat;
case TARGET_NR_lstat:
ret = get_errno(lstat((const char *)arg1, &st));
ret = get_errno(lstat(path((const char *)arg1), &st));
goto do_stat;
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;
target_st->st_dev = tswap16(st.st_dev);
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_uid = tswap16(st.st_uid);
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:
ret = get_errno(do_fork(cpu_env, arg1, arg2));
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:
ret = get_errno(setdomainname((const char *)arg1, arg2));
break;
@@ -2235,10 +2244,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_ftruncate64:
goto unimplemented;
case TARGET_NR_stat64:
ret = get_errno(stat((const char *)arg1, &st));
ret = get_errno(stat(path((const char *)arg1), &st));
goto do_stat64;
case TARGET_NR_lstat64:
ret = get_errno(lstat((const char *)arg1, &st));
ret = get_errno(lstat(path((const char *)arg1), &st));
goto do_stat64;
case TARGET_NR_fstat64:
{
@@ -2246,15 +2255,19 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
do_stat64:
if (!is_error(ret)) {
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_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_nlink = tswap16(st.st_nlink);
target_st->st_uid = tswap16(st.st_uid);
target_st->st_gid = tswap16(st.st_gid);
target_st->st_nlink = tswap32(st.st_nlink);
target_st->st_uid = tswapl(st.st_uid);
target_st->st_gid = tswapl(st.st_gid);
target_st->st_rdev = tswap16(st.st_rdev);
/* 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_blocks = tswapl(st.st_blocks);
target_st->target_st_atime = tswapl(st.st_atime);

View File

@@ -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 QEMU can emulate itself on x86 (experimental).
@item The virtual x86 CPU is a library (@code{libqemu}) which can be used
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 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).
@@ -88,9 +88,14 @@ qemu -L / /bin/ls
@code{-L /} tells that the x86 dynamic linker must be searched with a
@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
(@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:
@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
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
@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
@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
@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
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
@table @asis

View File

@@ -302,7 +302,7 @@ struct target_stat64 {
unsigned short st_dev;
unsigned char __pad0[10];
#define STAT64_HAS_BROKEN_ST_INO 1
#define TARGET_STAT64_HAS_BROKEN_ST_INO 1
target_ulong __st_ino;
unsigned int st_mode;
@@ -572,8 +572,8 @@ struct target_pt_regs {
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
#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_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
#define TARGET_FIOCLEX 0x5451

28
tests/.cvsignore Normal file
View 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

View File

@@ -6,7 +6,7 @@ LDFLAGS=
ifeq ($(ARCH),i386)
TESTS=testclone testsig testthread sha1-i386 test-i386 runcom
endif
TESTS+=sha1
TESTS+=sha1 test_path
QEMU=../qemu
@@ -25,6 +25,10 @@ testsig: testsig.c
testthread: testthread.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
test_path: test_path.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
./$@ || { rm $@; exit 1; }
# i386 emulation test (test various opcodes) */
test-i386: test-i386.c test-i386-code16.S \
test-i386.h test-i386-shift.h test-i386-muldiv.h

View File

@@ -3,6 +3,7 @@
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
@@ -14,6 +15,12 @@
//#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)
#define COM_BASE_ADDR 0x10100

View File

@@ -108,7 +108,12 @@ void exec_opb(int s0, int s1, int iflags)
void exec_op(int s2, int s0, int s1)
{
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);
#endif
#ifndef OP_NOBYTE
exec_opb(s0, s1, 0);
#endif

152
tests/test_path.c Normal file
View 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;
}

View File

@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <inttypes.h>

View File

@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <inttypes.h>

18
thunk.h
View File

@@ -94,17 +94,17 @@ static inline uint64_t bswap64(uint64_t x)
return bswap_64(x);
}
static void inline bswap16s(uint16_t *s)
static inline void bswap16s(uint16_t *s)
{
*s = bswap16(*s);
}
static void inline bswap32s(uint32_t *s)
static inline void bswap32s(uint32_t *s)
{
*s = bswap32(*s);
}
static void inline bswap64s(uint64_t *s)
static inline void bswap64s(uint64_t *s)
{
*s = bswap64(*s);
}
@@ -126,17 +126,17 @@ static inline uint64_t tswap64(uint64_t s)
return bswap64(s);
}
static void inline tswap16s(uint16_t *s)
static inline void tswap16s(uint16_t *s)
{
*s = bswap16(*s);
}
static void inline tswap32s(uint32_t *s)
static inline void tswap32s(uint32_t *s)
{
*s = bswap32(*s);
}
static void inline tswap64s(uint64_t *s)
static inline void tswap64s(uint64_t *s)
{
*s = bswap64(*s);
}
@@ -158,15 +158,15 @@ static inline uint64_t tswap64(uint64_t 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)
{
}