forked from Minki/linux
uml: throw out CONFIG_MODE_TT
This patchset throws out tt mode, which has been non-functional for a while. This is done in phases, interspersed with code cleanups on the affected files. The removal is done as follows: remove all code, config options, and files which depend on CONFIG_MODE_TT get rid of the CHOOSE_MODE macro, which decided whether to call tt-mode or skas-mode code, and replace invocations with their skas portions replace all now-trivial procedures with their skas equivalents There are now a bunch of now-redundant pieces of data structures, including mode-specific pieces of the thread structure, pt_regs, and mm_context. These are all replaced with their skas-specific contents. As part of the ongoing style compliance project, I made a style pass over all files that were changed. There are three such patches, one for each phase, covering the files affected by that phase but no later ones. I noticed that we weren't freeing the LDT state associated with a process when it exited, so that's fixed in one of the later patches. The last patch is a tidying patch which I've had for a while, but which caused inexplicable crashes under tt mode. Since that is no longer a problem, this can now go in. This patch: Start getting rid of tt mode support. This patch throws out CONFIG_MODE_TT and all config options, code, and files which depend on it. CONFIG_MODE_SKAS is gone and everything that depends on it is included unconditionally. The few changed lines are in re-written Kconfig help, lines which needed something skas-related removed from them, and a few more which weren't strictly deletions. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
a1ff5878d2
commit
42fda66387
@ -62,55 +62,16 @@ config IRQ_RELEASE_METHOD
|
|||||||
|
|
||||||
menu "UML-specific options"
|
menu "UML-specific options"
|
||||||
|
|
||||||
config MODE_TT
|
|
||||||
bool "Tracing thread support (DEPRECATED)"
|
|
||||||
default n
|
|
||||||
depends on BROKEN
|
|
||||||
help
|
|
||||||
This option controls whether tracing thread support is compiled
|
|
||||||
into UML. This option is largely obsolete, given that skas0 provides
|
|
||||||
skas security and performance without needing to patch the host.
|
|
||||||
It is safe to say 'N' here; saying 'Y' may cause additional problems
|
|
||||||
with the resulting binary even if you run UML in SKAS mode, and running
|
|
||||||
in TT mode is strongly *NOT RECOMMENDED*.
|
|
||||||
|
|
||||||
config STATIC_LINK
|
config STATIC_LINK
|
||||||
bool "Force a static link"
|
bool "Force a static link"
|
||||||
default n
|
default n
|
||||||
depends on !MODE_TT
|
|
||||||
help
|
help
|
||||||
If CONFIG_MODE_TT is disabled, then this option gives you the ability
|
This option gives you the ability to force a static link of UML.
|
||||||
to force a static link of UML. Normally, if only skas mode is built
|
Normally, UML is linked as a shared binary. This is inconvenient for
|
||||||
in to UML, it will be linked as a shared binary. This is inconvenient
|
use in a chroot jail. So, if you intend to run UML inside a chroot,
|
||||||
for use in a chroot jail. So, if you intend to run UML inside a
|
you probably want to say Y here.
|
||||||
chroot, and you disable CONFIG_MODE_TT, you probably want to say Y
|
|
||||||
here.
|
|
||||||
Additionally, this option enables using higher memory spaces (up to
|
Additionally, this option enables using higher memory spaces (up to
|
||||||
2.75G) for UML - disabling CONFIG_MODE_TT and enabling this option leads
|
2.75G) for UML.
|
||||||
to best results for this.
|
|
||||||
|
|
||||||
config KERNEL_HALF_GIGS
|
|
||||||
int "Kernel address space size (in .5G units)"
|
|
||||||
default "1"
|
|
||||||
depends on MODE_TT
|
|
||||||
help
|
|
||||||
This determines the amount of address space that UML will allocate for
|
|
||||||
its own, measured in half Gigabyte units. The default is 1.
|
|
||||||
Change this only if you need to boot UML with an unusually large amount
|
|
||||||
of physical memory.
|
|
||||||
|
|
||||||
config MODE_SKAS
|
|
||||||
bool "Separate Kernel Address Space support" if MODE_TT
|
|
||||||
default y
|
|
||||||
help
|
|
||||||
This option controls whether skas (separate kernel address space)
|
|
||||||
support is compiled in.
|
|
||||||
Unless you have specific needs to use TT mode (which applies almost only
|
|
||||||
to developers), you should say Y here.
|
|
||||||
SKAS mode will make use of the SKAS3 patch if it is applied on the host
|
|
||||||
(and your UML will run in SKAS3 mode), but if no SKAS patch is applied
|
|
||||||
on the host it will run in SKAS0 mode, which is anyway faster than TT
|
|
||||||
mode.
|
|
||||||
|
|
||||||
source "arch/um/Kconfig.arch"
|
source "arch/um/Kconfig.arch"
|
||||||
source "mm/Kconfig"
|
source "mm/Kconfig"
|
||||||
@ -118,7 +79,7 @@ source "mm/Kconfig"
|
|||||||
config LD_SCRIPT_STATIC
|
config LD_SCRIPT_STATIC
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
depends on MODE_TT || STATIC_LINK
|
depends on STATIC_LINK
|
||||||
|
|
||||||
config LD_SCRIPT_DYN
|
config LD_SCRIPT_DYN
|
||||||
bool
|
bool
|
||||||
@ -220,7 +181,7 @@ config SMP
|
|||||||
bool "Symmetric multi-processing support (EXPERIMENTAL)"
|
bool "Symmetric multi-processing support (EXPERIMENTAL)"
|
||||||
default n
|
default n
|
||||||
#SMP_BROKEN is for x86_64.
|
#SMP_BROKEN is for x86_64.
|
||||||
depends on MODE_TT && EXPERIMENTAL && (!SMP_BROKEN || (BROKEN && SMP_BROKEN))
|
depends on EXPERIMENTAL && (!SMP_BROKEN || (BROKEN && SMP_BROKEN))
|
||||||
help
|
help
|
||||||
This option enables UML SMP support.
|
This option enables UML SMP support.
|
||||||
It is NOT related to having a real SMP box. Not directly, at least.
|
It is NOT related to having a real SMP box. Not directly, at least.
|
||||||
@ -258,11 +219,6 @@ config NEST_LEVEL
|
|||||||
inside another UML, set CONFIG_NEST_LEVEL to one more than the host
|
inside another UML, set CONFIG_NEST_LEVEL to one more than the host
|
||||||
UML.
|
UML.
|
||||||
|
|
||||||
Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to
|
|
||||||
greater than one, then the guest UML should have its CONFIG_NEST_LEVEL
|
|
||||||
set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS.
|
|
||||||
Only change this if you are running nested UMLs.
|
|
||||||
|
|
||||||
config HIGHMEM
|
config HIGHMEM
|
||||||
bool "Highmem support (EXPERIMENTAL)"
|
bool "Highmem support (EXPERIMENTAL)"
|
||||||
depends on !64BIT && EXPERIMENTAL
|
depends on !64BIT && EXPERIMENTAL
|
||||||
@ -271,9 +227,9 @@ config HIGHMEM
|
|||||||
This was used to allow UML to run with big amounts of memory.
|
This was used to allow UML to run with big amounts of memory.
|
||||||
Currently it is unstable, so if unsure say N.
|
Currently it is unstable, so if unsure say N.
|
||||||
|
|
||||||
To use big amounts of memory, it is recommended to disable TT mode (i.e.
|
To use big amounts of memory, it is recommended enable static
|
||||||
CONFIG_MODE_TT) and enable static linking (i.e. CONFIG_STATIC_LINK) -
|
linking (i.e. CONFIG_STATIC_LINK) - this should allow the
|
||||||
this should allow the guest to use up to 2.75G of memory.
|
guest to use up to 2.75G of memory.
|
||||||
|
|
||||||
config KERNEL_STACK_ORDER
|
config KERNEL_STACK_ORDER
|
||||||
int "Kernel stack size order"
|
int "Kernel stack size order"
|
||||||
|
@ -65,8 +65,6 @@ config XTERM_CHAN
|
|||||||
This option enables support for attaching UML consoles and serial
|
This option enables support for attaching UML consoles and serial
|
||||||
lines to xterms. Each UML device so assigned will be brought up in
|
lines to xterms. Each UML device so assigned will be brought up in
|
||||||
its own xterm.
|
its own xterm.
|
||||||
If you disable this option, then CONFIG_PT_PROXY will be disabled as
|
|
||||||
well, since UML's gdb currently requires an xterm.
|
|
||||||
It is safe to say 'Y' here.
|
It is safe to say 'Y' here.
|
||||||
|
|
||||||
config NOCONFIG_CHAN
|
config NOCONFIG_CHAN
|
||||||
|
@ -2,28 +2,9 @@ menu "Kernel hacking"
|
|||||||
|
|
||||||
source "lib/Kconfig.debug"
|
source "lib/Kconfig.debug"
|
||||||
|
|
||||||
config CMDLINE_ON_HOST
|
|
||||||
bool "Show command line arguments on the host in TT mode"
|
|
||||||
depends on MODE_TT
|
|
||||||
default !DEBUG_INFO
|
|
||||||
help
|
|
||||||
This controls whether arguments in guest processes should be shown on
|
|
||||||
the host's ps output.
|
|
||||||
Enabling this option hinders debugging on some recent GDB versions
|
|
||||||
(because GDB gets "confused" when we do an execvp()). So probably you
|
|
||||||
should disable it.
|
|
||||||
|
|
||||||
config PT_PROXY
|
|
||||||
bool "Enable ptrace proxy"
|
|
||||||
depends on XTERM_CHAN && DEBUG_INFO && MODE_TT
|
|
||||||
help
|
|
||||||
This option enables a debugging interface which allows gdb to debug
|
|
||||||
the kernel without needing to actually attach to kernel threads.
|
|
||||||
If you want to do kernel debugging, say Y here; otherwise say N.
|
|
||||||
|
|
||||||
config GPROF
|
config GPROF
|
||||||
bool "Enable gprof support"
|
bool "Enable gprof support"
|
||||||
depends on DEBUG_INFO && MODE_SKAS && !MODE_TT
|
depends on DEBUG_INFO
|
||||||
help
|
help
|
||||||
This allows profiling of a User-Mode Linux kernel with the gprof
|
This allows profiling of a User-Mode Linux kernel with the gprof
|
||||||
utility.
|
utility.
|
||||||
@ -36,7 +17,7 @@ config GPROF
|
|||||||
|
|
||||||
config GCOV
|
config GCOV
|
||||||
bool "Enable gcov support"
|
bool "Enable gcov support"
|
||||||
depends on DEBUG_INFO && MODE_SKAS
|
depends on DEBUG_INFO
|
||||||
help
|
help
|
||||||
This option allows developers to retrieve coverage data from a UML
|
This option allows developers to retrieve coverage data from a UML
|
||||||
session.
|
session.
|
||||||
|
@ -31,18 +31,9 @@ SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header))
|
|||||||
ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \
|
ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \
|
||||||
$(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h
|
$(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h
|
||||||
|
|
||||||
um-modes-$(CONFIG_MODE_TT) += tt
|
MODE_INCLUDE += -I$(srctree)/$(ARCH_DIR)/include/skas
|
||||||
um-modes-$(CONFIG_MODE_SKAS) += skas
|
|
||||||
|
|
||||||
MODE_INCLUDE += $(foreach mode,$(um-modes-y),\
|
include $(srctree)/$(ARCH_DIR)/Makefile-skas
|
||||||
-I$(srctree)/$(ARCH_DIR)/include/$(mode))
|
|
||||||
|
|
||||||
MAKEFILES-INCL += $(foreach mode,$(um-modes-y),\
|
|
||||||
$(srctree)/$(ARCH_DIR)/Makefile-$(mode))
|
|
||||||
|
|
||||||
ifneq ($(MAKEFILES-INCL),)
|
|
||||||
include $(MAKEFILES-INCL)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ARCH_INCLUDE := -I$(ARCH_DIR)/include
|
ARCH_INCLUDE := -I$(ARCH_DIR)/include
|
||||||
ifneq ($(KBUILD_SRC),)
|
ifneq ($(KBUILD_SRC),)
|
||||||
@ -89,9 +80,8 @@ CFLAGS += $(call cc-option,-fno-unit-at-a-time,)
|
|||||||
# included; the values here are meaningless
|
# included; the values here are meaningless
|
||||||
|
|
||||||
CONFIG_NEST_LEVEL ?= 0
|
CONFIG_NEST_LEVEL ?= 0
|
||||||
CONFIG_KERNEL_HALF_GIGS ?= 0
|
|
||||||
|
|
||||||
SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
|
SIZE = ($(CONFIG_NEST_LEVEL) * 0x20000000)
|
||||||
|
|
||||||
PHONY += linux
|
PHONY += linux
|
||||||
|
|
||||||
@ -124,7 +114,6 @@ CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,)
|
|||||||
$(call cc-option, -fno-stack-protector,) \
|
$(call cc-option, -fno-stack-protector,) \
|
||||||
$(call cc-option, -fno-stack-protector-all,)
|
$(call cc-option, -fno-stack-protector-all,)
|
||||||
|
|
||||||
CPP_MODE-$(CONFIG_MODE_TT) := -DMODE_TT
|
|
||||||
CONFIG_KERNEL_STACK_ORDER ?= 2
|
CONFIG_KERNEL_STACK_ORDER ?= 2
|
||||||
STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] )
|
STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] )
|
||||||
|
|
||||||
@ -132,11 +121,8 @@ ifndef START
|
|||||||
START = $(shell echo $$[ $(TOP_ADDR) - $(SIZE) ] )
|
START = $(shell echo $$[ $(TOP_ADDR) - $(SIZE) ] )
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CPPFLAGS_vmlinux.lds = -U$(SUBARCH) \
|
CPPFLAGS_vmlinux.lds = -U$(SUBARCH) -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \
|
||||||
-DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \
|
-DELF_FORMAT="$(ELF_FORMAT)" -DKERNEL_STACK_SIZE=$(STACK_SIZE)
|
||||||
-DELF_FORMAT="$(ELF_FORMAT)" $(CPP_MODE-y) \
|
|
||||||
-DKERNEL_STACK_SIZE=$(STACK_SIZE) \
|
|
||||||
-DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap.o
|
|
||||||
|
|
||||||
#The wrappers will select whether using "malloc" or the kernel allocator.
|
#The wrappers will select whether using "malloc" or the kernel allocator.
|
||||||
LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
|
LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
|
||||||
|
@ -2,11 +2,7 @@ core-y += arch/um/sys-i386/ arch/x86/crypto/
|
|||||||
|
|
||||||
TOP_ADDR := $(CONFIG_TOP_ADDR)
|
TOP_ADDR := $(CONFIG_TOP_ADDR)
|
||||||
|
|
||||||
ifeq ($(CONFIG_MODE_SKAS),y)
|
START := 0x8048000
|
||||||
ifneq ($(CONFIG_MODE_TT),y)
|
|
||||||
START := 0x8048000
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
LDFLAGS += -m elf_i386
|
LDFLAGS += -m elf_i386
|
||||||
ELF_ARCH := $(SUBARCH)
|
ELF_ARCH := $(SUBARCH)
|
||||||
|
@ -12,9 +12,7 @@ CONFIG_IRQ_RELEASE_METHOD=y
|
|||||||
#
|
#
|
||||||
# UML-specific options
|
# UML-specific options
|
||||||
#
|
#
|
||||||
# CONFIG_MODE_TT is not set
|
|
||||||
# CONFIG_STATIC_LINK is not set
|
# CONFIG_STATIC_LINK is not set
|
||||||
CONFIG_MODE_SKAS=y
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Host processor type and features
|
# Host processor type and features
|
||||||
|
@ -735,8 +735,6 @@ void mconsole_sysrq(struct mc_request *req)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
|
|
||||||
static void stack_proc(void *arg)
|
static void stack_proc(void *arg)
|
||||||
{
|
{
|
||||||
struct task_struct *from = current, *to = arg;
|
struct task_struct *from = current, *to = arg;
|
||||||
@ -750,7 +748,7 @@ static void stack_proc(void *arg)
|
|||||||
* Dumps a stacks registers to the linux console.
|
* Dumps a stacks registers to the linux console.
|
||||||
* Usage stack <pid>.
|
* Usage stack <pid>.
|
||||||
*/
|
*/
|
||||||
static void do_stack_trace(struct mc_request *req)
|
void mconsole_stack(struct mc_request *req)
|
||||||
{
|
{
|
||||||
char *ptr = req->request.data;
|
char *ptr = req->request.data;
|
||||||
int pid_requested= -1;
|
int pid_requested= -1;
|
||||||
@ -781,17 +779,6 @@ static void do_stack_trace(struct mc_request *req)
|
|||||||
}
|
}
|
||||||
with_console(req, stack_proc, to);
|
with_console(req, stack_proc, to);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_MODE_SKAS */
|
|
||||||
|
|
||||||
void mconsole_stack(struct mc_request *req)
|
|
||||||
{
|
|
||||||
/* This command doesn't work in TT mode, so let's check and then
|
|
||||||
* get out of here
|
|
||||||
*/
|
|
||||||
CHOOSE_MODE(mconsole_reply(req, "Sorry, this doesn't work in TT mode",
|
|
||||||
1, 0),
|
|
||||||
do_stack_trace(req));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Changed by mconsole_setup, which is __setup, and called before SMP is
|
/* Changed by mconsole_setup, which is __setup, and called before SMP is
|
||||||
* active.
|
* active.
|
||||||
|
@ -28,7 +28,6 @@ extern unsigned long _unprotected_end;
|
|||||||
extern unsigned long brk_start;
|
extern unsigned long brk_start;
|
||||||
|
|
||||||
extern int linux_main(int argc, char **argv);
|
extern int linux_main(int argc, char **argv);
|
||||||
extern void set_cmdline(char *cmd);
|
|
||||||
|
|
||||||
extern void (*sig_info[])(int, union uml_pt_regs *);
|
extern void (*sig_info[])(int, union uml_pt_regs *);
|
||||||
|
|
||||||
|
@ -8,26 +8,8 @@
|
|||||||
|
|
||||||
#include "uml-config.h"
|
#include "uml-config.h"
|
||||||
|
|
||||||
#if defined(UML_CONFIG_MODE_TT) && defined(UML_CONFIG_MODE_SKAS)
|
|
||||||
#define CHOOSE_MODE(tt, skas) (mode_tt ? (tt) : (skas))
|
|
||||||
|
|
||||||
extern int mode_tt;
|
|
||||||
static inline void *__choose_mode(void *tt, void *skas) {
|
|
||||||
return mode_tt ? tt : skas;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define __CHOOSE_MODE(tt, skas) (*( (typeof(tt) *) __choose_mode(&(tt), &(skas))))
|
|
||||||
|
|
||||||
#elif defined(UML_CONFIG_MODE_SKAS)
|
|
||||||
#define CHOOSE_MODE(tt, skas) (skas)
|
#define CHOOSE_MODE(tt, skas) (skas)
|
||||||
|
|
||||||
#elif defined(UML_CONFIG_MODE_TT)
|
|
||||||
#define CHOOSE_MODE(tt, skas) (tt)
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error CONFIG_MODE_SKAS and CONFIG_MODE_TT are both disabled
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CHOOSE_MODE_PROC(tt, skas, args...) \
|
#define CHOOSE_MODE_PROC(tt, skas, args...) \
|
||||||
CHOOSE_MODE(tt(args), skas(args))
|
CHOOSE_MODE(tt(args), skas(args))
|
||||||
|
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
/* for use by sys-$SUBARCH/kernel-offsets.c */
|
/* for use by sys-$SUBARCH/kernel-offsets.c */
|
||||||
|
|
||||||
DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE);
|
DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE);
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
OFFSET(HOST_TASK_REGS, task_struct, thread.regs);
|
OFFSET(HOST_TASK_REGS, task_struct, thread.regs);
|
||||||
OFFSET(HOST_TASK_PID, task_struct, pid);
|
OFFSET(HOST_TASK_PID, task_struct, pid);
|
||||||
|
@ -30,8 +30,4 @@ extern void deactivate_fd(int fd, int irqnum);
|
|||||||
extern int deactivate_all_fds(void);
|
extern int deactivate_all_fds(void);
|
||||||
extern int activate_ipi(int fd, int pid);
|
extern int activate_ipi(int fd, int pid);
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
extern void forward_interrupts(int pid);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,9 +34,6 @@ extern int nsyscalls;
|
|||||||
UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
|
UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
|
||||||
|
|
||||||
extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
|
extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
extern unsigned long stack_sp(unsigned long page);
|
|
||||||
#endif
|
|
||||||
extern int kernel_thread_proc(void *data);
|
extern int kernel_thread_proc(void *data);
|
||||||
extern void syscall_segv(int sig);
|
extern void syscall_segv(int sig);
|
||||||
extern int current_pid(void);
|
extern int current_pid(void);
|
||||||
@ -82,9 +79,6 @@ extern void check_stack_overflow(void *ptr);
|
|||||||
extern void relay_signal(int sig, union uml_pt_regs *regs);
|
extern void relay_signal(int sig, union uml_pt_regs *regs);
|
||||||
extern int user_context(unsigned long sp);
|
extern int user_context(unsigned long sp);
|
||||||
extern void timer_irq(union uml_pt_regs *regs);
|
extern void timer_irq(union uml_pt_regs *regs);
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
extern void unprotect_stack(unsigned long stack);
|
|
||||||
#endif
|
|
||||||
extern void do_uml_exitcalls(void);
|
extern void do_uml_exitcalls(void);
|
||||||
extern int attach_debugger(int idle_pid, int pid, int stop);
|
extern int attach_debugger(int idle_pid, int pid, int stop);
|
||||||
extern int config_gdb(char *str);
|
extern int config_gdb(char *str);
|
||||||
|
@ -6,25 +6,6 @@
|
|||||||
#ifndef __MODE_H__
|
#ifndef __MODE_H__
|
||||||
#define __MODE_H__
|
#define __MODE_H__
|
||||||
|
|
||||||
#include "uml-config.h"
|
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
#include "mode-tt.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
#include "mode-skas.h"
|
#include "mode-skas.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
||||||
|
@ -6,12 +6,6 @@
|
|||||||
#ifndef __MODE_KERN_H__
|
#ifndef __MODE_KERN_H__
|
||||||
#define __MODE_KERN_H__
|
#define __MODE_KERN_H__
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
#include "mode_kern_tt.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
#include "mode_kern_skas.h"
|
#include "mode_kern_skas.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -178,11 +178,7 @@ extern void check_host_supports_tls(int *supports_tls, int *tls_min);
|
|||||||
|
|
||||||
/* Make sure they are clear when running in TT mode. Required by
|
/* Make sure they are clear when running in TT mode. Required by
|
||||||
* SEGV_MAYBE_FIXABLE */
|
* SEGV_MAYBE_FIXABLE */
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
#define clear_can_do_skas() do { ptrace_faultinfo = proc_mm = 0; } while (0)
|
#define clear_can_do_skas() do { ptrace_faultinfo = proc_mm = 0; } while (0)
|
||||||
#else
|
|
||||||
#define clear_can_do_skas() do {} while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* mem.c */
|
/* mem.c */
|
||||||
extern int create_mem_file(unsigned long long len);
|
extern int create_mem_file(unsigned long long len);
|
||||||
@ -193,18 +189,11 @@ extern int os_process_parent(int pid);
|
|||||||
extern void os_stop_process(int pid);
|
extern void os_stop_process(int pid);
|
||||||
extern void os_kill_process(int pid, int reap_child);
|
extern void os_kill_process(int pid, int reap_child);
|
||||||
extern void os_kill_ptraced_process(int pid, int reap_child);
|
extern void os_kill_ptraced_process(int pid, int reap_child);
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
extern void os_usr1_process(int pid);
|
|
||||||
#endif
|
|
||||||
extern long os_ptrace_ldt(long pid, long addr, long data);
|
extern long os_ptrace_ldt(long pid, long addr, long data);
|
||||||
|
|
||||||
extern int os_getpid(void);
|
extern int os_getpid(void);
|
||||||
extern int os_getpgrp(void);
|
extern int os_getpgrp(void);
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
|
|
||||||
extern void stop(void);
|
|
||||||
#endif
|
|
||||||
extern void init_new_thread_signals(void);
|
extern void init_new_thread_signals(void);
|
||||||
extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
|
extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
|
||||||
|
|
||||||
@ -217,18 +206,6 @@ extern int os_drop_memory(void *addr, int length);
|
|||||||
extern int can_drop_memory(void);
|
extern int can_drop_memory(void);
|
||||||
extern void os_flush_stdout(void);
|
extern void os_flush_stdout(void);
|
||||||
|
|
||||||
/* tt.c
|
|
||||||
* for tt mode only (will be deleted in future...)
|
|
||||||
*/
|
|
||||||
extern void forward_ipi(int fd, int pid);
|
|
||||||
extern void kill_child_dead(int pid);
|
|
||||||
extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
|
|
||||||
extern int protect_memory(unsigned long addr, unsigned long len,
|
|
||||||
int r, int w, int x, int must_succeed);
|
|
||||||
extern void forward_pending_sigio(int target);
|
|
||||||
extern int start_fork_tramp(void *arg, unsigned long temp_stack,
|
|
||||||
int clone_flags, int (*tramp)(void *));
|
|
||||||
|
|
||||||
/* uaccess.c */
|
/* uaccess.c */
|
||||||
extern unsigned long __do_user_copy(void *to, const void *from, int n,
|
extern unsigned long __do_user_copy(void *to, const void *from, int n,
|
||||||
void **fault_addr, void **fault_catcher,
|
void **fault_addr, void **fault_catcher,
|
||||||
@ -281,9 +258,6 @@ extern void os_dump_core(void);
|
|||||||
extern void switch_timers(int to_real);
|
extern void switch_timers(int to_real);
|
||||||
extern void idle_sleep(int secs);
|
extern void idle_sleep(int secs);
|
||||||
extern int set_interval(int is_virtual);
|
extern int set_interval(int is_virtual);
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
extern void enable_timer(void);
|
|
||||||
#endif
|
|
||||||
extern void disable_timer(void);
|
extern void disable_timer(void);
|
||||||
extern void uml_idle_timer(void);
|
extern void uml_idle_timer(void);
|
||||||
extern unsigned long long os_nsecs(void);
|
extern unsigned long long os_nsecs(void);
|
||||||
|
@ -14,12 +14,7 @@
|
|||||||
#define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long))
|
#define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long))
|
||||||
#define MAX_REG_OFFSET (UM_FRAME_SIZE)
|
#define MAX_REG_OFFSET (UM_FRAME_SIZE)
|
||||||
|
|
||||||
#ifdef UML_CONFIG_PT_PROXY
|
|
||||||
extern void update_debugregs(int seq);
|
|
||||||
#else
|
|
||||||
static inline void update_debugregs(int seq) {}
|
static inline void update_debugregs(int seq) {}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* syscall emulation path in ptrace */
|
/* syscall emulation path in ptrace */
|
||||||
|
|
||||||
@ -31,12 +26,6 @@ void set_using_sysemu(int value);
|
|||||||
int get_using_sysemu(void);
|
int get_using_sysemu(void);
|
||||||
extern int sysemu_supported;
|
extern int sysemu_supported;
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
#include "sysdep/sc.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
|
|
||||||
#include "skas_ptregs.h"
|
#include "skas_ptregs.h"
|
||||||
|
|
||||||
#define REGS_IP(r) ((r)[HOST_IP])
|
#define REGS_IP(r) ((r)[HOST_IP])
|
||||||
@ -60,20 +49,11 @@ extern int sysemu_supported;
|
|||||||
|
|
||||||
#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
|
#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
|
||||||
|
|
||||||
#endif
|
|
||||||
#ifndef PTRACE_SYSEMU_SINGLESTEP
|
#ifndef PTRACE_SYSEMU_SINGLESTEP
|
||||||
#define PTRACE_SYSEMU_SINGLESTEP 32
|
#define PTRACE_SYSEMU_SINGLESTEP 32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
union uml_pt_regs {
|
union uml_pt_regs {
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
struct tt_regs {
|
|
||||||
long syscall;
|
|
||||||
void *sc;
|
|
||||||
struct faultinfo faultinfo;
|
|
||||||
} tt;
|
|
||||||
#endif
|
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
struct skas_regs {
|
struct skas_regs {
|
||||||
unsigned long regs[MAX_REG_NR];
|
unsigned long regs[MAX_REG_NR];
|
||||||
unsigned long fp[HOST_FP_SIZE];
|
unsigned long fp[HOST_FP_SIZE];
|
||||||
@ -82,13 +62,10 @@ union uml_pt_regs {
|
|||||||
long syscall;
|
long syscall;
|
||||||
int is_user;
|
int is_user;
|
||||||
} skas;
|
} skas;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EMPTY_UML_PT_REGS { }
|
#define EMPTY_UML_PT_REGS { }
|
||||||
|
|
||||||
extern int mode_tt;
|
|
||||||
|
|
||||||
#define UPT_SC(r) ((r)->tt.sc)
|
#define UPT_SC(r) ((r)->tt.sc)
|
||||||
#define UPT_IP(r) \
|
#define UPT_IP(r) \
|
||||||
__CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
|
__CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
|
||||||
|
@ -30,11 +30,7 @@
|
|||||||
#define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14)
|
#define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14)
|
||||||
|
|
||||||
/* SKAS3 has no trap_no on i386, but get_skas_faultinfo() sets it to 0. */
|
/* SKAS3 has no trap_no on i386, but get_skas_faultinfo() sets it to 0. */
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
#define SEGV_MAYBE_FIXABLE(fi) ((fi)->trap_no == 0 && ptrace_faultinfo)
|
#define SEGV_MAYBE_FIXABLE(fi) ((fi)->trap_no == 0 && ptrace_faultinfo)
|
||||||
#else
|
|
||||||
#define SEGV_MAYBE_FIXABLE(fi) 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern unsigned long *sc_sigmask(void *sc_ptr);
|
extern unsigned long *sc_sigmask(void *sc_ptr);
|
||||||
extern int sc_get_fpregs(unsigned long buf, void *sc_ptr);
|
extern int sc_get_fpregs(unsigned long buf, void *sc_ptr);
|
||||||
|
@ -4,8 +4,5 @@
|
|||||||
#include <kern_constants.h>
|
#include <kern_constants.h>
|
||||||
|
|
||||||
#define TASK_DEBUGREGS(task) ((unsigned long *) &(((char *) (task))[HOST_TASK_DEBUGREGS]))
|
#define TASK_DEBUGREGS(task) ((unsigned long *) &(((char *) (task))[HOST_TASK_DEBUGREGS]))
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
#define TASK_EXTERN_PID(task) *((int *) &(((char *) (task))[HOST_TASK_EXTERN_PID]))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003 PathScale, Inc.
|
* Copyright 2003 PathScale, Inc.
|
||||||
|
* Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
|
||||||
*
|
*
|
||||||
* Licensed under the GPL
|
* Licensed under the GPL
|
||||||
*/
|
*/
|
||||||
@ -14,11 +15,6 @@
|
|||||||
#define MAX_REG_OFFSET (UM_FRAME_SIZE)
|
#define MAX_REG_OFFSET (UM_FRAME_SIZE)
|
||||||
#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long))
|
#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long))
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
#include "sysdep/sc.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
#include "skas_ptregs.h"
|
#include "skas_ptregs.h"
|
||||||
|
|
||||||
#define REGS_IP(r) ((r)[HOST_IP])
|
#define REGS_IP(r) ((r)[HOST_IP])
|
||||||
@ -88,21 +84,10 @@
|
|||||||
|
|
||||||
#define REGS_ERR(r) ((r)->fault_type)
|
#define REGS_ERR(r) ((r)->fault_type)
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "choose-mode.h"
|
#include "choose-mode.h"
|
||||||
|
|
||||||
/* XXX */
|
/* XXX */
|
||||||
union uml_pt_regs {
|
union uml_pt_regs {
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
struct tt_regs {
|
|
||||||
long syscall;
|
|
||||||
unsigned long orig_rax;
|
|
||||||
void *sc;
|
|
||||||
struct faultinfo faultinfo;
|
|
||||||
} tt;
|
|
||||||
#endif
|
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
struct skas_regs {
|
struct skas_regs {
|
||||||
unsigned long regs[MAX_REG_NR];
|
unsigned long regs[MAX_REG_NR];
|
||||||
unsigned long fp[HOST_FP_SIZE];
|
unsigned long fp[HOST_FP_SIZE];
|
||||||
@ -110,14 +95,10 @@ union uml_pt_regs {
|
|||||||
long syscall;
|
long syscall;
|
||||||
int is_user;
|
int is_user;
|
||||||
} skas;
|
} skas;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EMPTY_UML_PT_REGS { }
|
#define EMPTY_UML_PT_REGS { }
|
||||||
|
|
||||||
/* XXX */
|
|
||||||
extern int mode_tt;
|
|
||||||
|
|
||||||
#define UPT_RBX(r) __CHOOSE_MODE(SC_RBX(UPT_SC(r)), REGS_RBX((r)->skas.regs))
|
#define UPT_RBX(r) __CHOOSE_MODE(SC_RBX(UPT_SC(r)), REGS_RBX((r)->skas.regs))
|
||||||
#define UPT_RCX(r) __CHOOSE_MODE(SC_RCX(UPT_SC(r)), REGS_RCX((r)->skas.regs))
|
#define UPT_RCX(r) __CHOOSE_MODE(SC_RCX(UPT_SC(r)), REGS_RCX((r)->skas.regs))
|
||||||
#define UPT_RDX(r) __CHOOSE_MODE(SC_RDX(UPT_SC(r)), REGS_RDX((r)->skas.regs))
|
#define UPT_RDX(r) __CHOOSE_MODE(SC_RDX(UPT_SC(r)), REGS_RDX((r)->skas.regs))
|
||||||
|
@ -3,8 +3,4 @@
|
|||||||
|
|
||||||
#include <kern_constants.h>
|
#include <kern_constants.h>
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
#define TASK_EXTERN_PID(task) *((int *) &(((char *) (task))[HOST_TASK_EXTERN_PID]))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and
|
|
||||||
* Lars Brinkhoff.
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __UML_TT_DEBUG_H
|
|
||||||
#define __UML_TT_DEBUG_H
|
|
||||||
|
|
||||||
extern int debugger_proxy(int status, pid_t pid);
|
|
||||||
extern void child_proxy(pid_t pid, int status);
|
|
||||||
extern void init_proxy (pid_t pid, int waiting, int status);
|
|
||||||
extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
|
|
||||||
extern void fake_child_exit(void);
|
|
||||||
extern int gdb_config(char *str);
|
|
||||||
extern int gdb_remove(int unused);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,12 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __TT_MMU_H
|
|
||||||
#define __TT_MMU_H
|
|
||||||
|
|
||||||
struct mmu_context_tt {
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __MODE_TT_H__
|
|
||||||
#define __MODE_TT_H__
|
|
||||||
|
|
||||||
#include "sysdep/ptrace.h"
|
|
||||||
|
|
||||||
enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
|
|
||||||
|
|
||||||
extern int tracing_pid;
|
|
||||||
|
|
||||||
extern int tracer(int (*init_proc)(void *), void *sp);
|
|
||||||
extern void sig_handler_common_tt(int sig, void *sc);
|
|
||||||
extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
|
|
||||||
extern void reboot_tt(void);
|
|
||||||
extern void halt_tt(void);
|
|
||||||
extern int is_tracer_winch(int pid, int fd, void *data);
|
|
||||||
extern void kill_off_processes_tt(void);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __TT_MODE_KERN_H__
|
|
||||||
#define __TT_MODE_KERN_H__
|
|
||||||
|
|
||||||
#include "linux/sched.h"
|
|
||||||
#include "asm/page.h"
|
|
||||||
#include "asm/ptrace.h"
|
|
||||||
#include "asm/uaccess.h"
|
|
||||||
|
|
||||||
extern void switch_to_tt(void *prev, void *next);
|
|
||||||
extern void flush_thread_tt(void);
|
|
||||||
extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
|
|
||||||
unsigned long esp);
|
|
||||||
extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
|
|
||||||
unsigned long stack_top, struct task_struct *p,
|
|
||||||
struct pt_regs *regs);
|
|
||||||
extern void release_thread_tt(struct task_struct *task);
|
|
||||||
extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
|
|
||||||
extern void init_idle_tt(void);
|
|
||||||
extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end);
|
|
||||||
extern void flush_tlb_kernel_vm_tt(void);
|
|
||||||
extern void __flush_tlb_one_tt(unsigned long addr);
|
|
||||||
extern void flush_tlb_range_tt(struct vm_area_struct *vma,
|
|
||||||
unsigned long start, unsigned long end);
|
|
||||||
extern void flush_tlb_mm_tt(struct mm_struct *mm);
|
|
||||||
extern void force_flush_all_tt(void);
|
|
||||||
extern long execute_syscall_tt(void *r);
|
|
||||||
extern void before_mem_tt(unsigned long brk_start);
|
|
||||||
extern unsigned long set_task_sizes_tt(unsigned long *task_size_out);
|
|
||||||
extern int start_uml_tt(void);
|
|
||||||
extern int external_pid_tt(struct task_struct *task);
|
|
||||||
extern int thread_pid_tt(struct task_struct *task);
|
|
||||||
|
|
||||||
#define kmem_end_tt (host_task_size - ABOVE_KMEM)
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __TT_H__
|
|
||||||
#define __TT_H__
|
|
||||||
|
|
||||||
#include "sysdep/ptrace.h"
|
|
||||||
|
|
||||||
extern int gdb_pid;
|
|
||||||
extern int debug;
|
|
||||||
extern int debug_stop;
|
|
||||||
extern int debug_trace;
|
|
||||||
|
|
||||||
extern int honeypot;
|
|
||||||
|
|
||||||
extern int fork_tramp(void *sig_stack);
|
|
||||||
extern int do_proc_op(void *t, int proc_id);
|
|
||||||
extern int tracer(int (*init_proc)(void *), void *sp);
|
|
||||||
extern void attach_process(int pid);
|
|
||||||
extern void tracer_panic(char *format, ...)
|
|
||||||
__attribute__ ((format (printf, 1, 2)));
|
|
||||||
extern void set_init_pid(int pid);
|
|
||||||
extern int set_user_mode(void *task);
|
|
||||||
extern void set_tracing(void *t, int tracing);
|
|
||||||
extern int is_tracing(void *task);
|
|
||||||
extern void syscall_handler(int sig, union uml_pt_regs *regs);
|
|
||||||
extern void exit_kernel(int pid, void *task);
|
|
||||||
extern void do_syscall(void *task, int pid, int local_using_sysemu);
|
|
||||||
extern void do_sigtrap(void *task);
|
|
||||||
extern int is_valid_pid(int pid);
|
|
||||||
extern void remap_data(void *segment_start, void *segment_end, int w);
|
|
||||||
extern long execute_syscall_tt(void *r);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __TT_UACCESS_H
|
|
||||||
#define __TT_UACCESS_H
|
|
||||||
|
|
||||||
#include "linux/string.h"
|
|
||||||
#include "linux/sched.h"
|
|
||||||
#include "asm/processor.h"
|
|
||||||
#include "asm/errno.h"
|
|
||||||
#include "asm/current.h"
|
|
||||||
#include "asm/a.out.h"
|
|
||||||
#include "uml_uaccess.h"
|
|
||||||
|
|
||||||
#define ABOVE_KMEM (16 * 1024 * 1024)
|
|
||||||
|
|
||||||
extern unsigned long end_vm;
|
|
||||||
extern unsigned long uml_physmem;
|
|
||||||
|
|
||||||
#define is_stack(addr, size) \
|
|
||||||
(((unsigned long) (addr) < STACK_TOP) && \
|
|
||||||
((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
|
|
||||||
(((unsigned long) (addr) + (size)) <= STACK_TOP))
|
|
||||||
|
|
||||||
#define access_ok_tt(type, addr, size) \
|
|
||||||
(is_stack(addr, size))
|
|
||||||
|
|
||||||
extern int __do_copy_from_user(void *to, const void *from, int n,
|
|
||||||
void **fault_addr, void **fault_catcher);
|
|
||||||
extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
|
|
||||||
void **fault_addr, void **fault_catcher);
|
|
||||||
extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
|
|
||||||
void **fault_catcher);
|
|
||||||
extern int __do_strnlen_user(const char *str, unsigned long n,
|
|
||||||
void **fault_addr, void **fault_catcher);
|
|
||||||
|
|
||||||
extern int copy_from_user_tt(void *to, const void __user *from, int n);
|
|
||||||
extern int copy_to_user_tt(void __user *to, const void *from, int n);
|
|
||||||
extern int strncpy_from_user_tt(char *dst, const char __user *src, int count);
|
|
||||||
extern int __clear_user_tt(void __user *mem, int len);
|
|
||||||
extern int clear_user_tt(void __user *mem, int len);
|
|
||||||
extern int strnlen_user_tt(const void __user *str, int len);
|
|
||||||
|
|
||||||
#endif
|
|
@ -8,33 +8,10 @@
|
|||||||
|
|
||||||
#include "uml-config.h"
|
#include "uml-config.h"
|
||||||
#include "choose-mode.h"
|
#include "choose-mode.h"
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
#include "mmu-tt.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
#include "mmu-skas.h"
|
#include "mmu-skas.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef union mm_context {
|
typedef union mm_context {
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
struct mmu_context_tt tt;
|
|
||||||
#endif
|
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
struct mmu_context_skas skas;
|
struct mmu_context_skas skas;
|
||||||
#endif
|
|
||||||
} mm_context_t;
|
} mm_context_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
||||||
|
@ -7,15 +7,7 @@
|
|||||||
#define __ARCH_UM_UACCESS_H
|
#define __ARCH_UM_UACCESS_H
|
||||||
|
|
||||||
#include "choose-mode.h"
|
#include "choose-mode.h"
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
#include "uaccess-tt.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
#include "uaccess-skas.h"
|
#include "uaccess-skas.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "asm/fixmap.h"
|
#include "asm/fixmap.h"
|
||||||
|
|
||||||
#define __under_task_size(addr, size) \
|
#define __under_task_size(addr, size) \
|
||||||
|
@ -9,15 +9,12 @@ clean-files :=
|
|||||||
obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \
|
obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \
|
||||||
physmem.o process.o ptrace.o reboot.o sigio.o \
|
physmem.o process.o ptrace.o reboot.o sigio.o \
|
||||||
signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \
|
signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \
|
||||||
um_arch.o umid.o
|
um_arch.o umid.o skas/
|
||||||
|
|
||||||
obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
|
obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
|
||||||
obj-$(CONFIG_GPROF) += gprof_syms.o
|
obj-$(CONFIG_GPROF) += gprof_syms.o
|
||||||
obj-$(CONFIG_GCOV) += gmon_syms.o
|
obj-$(CONFIG_GCOV) += gmon_syms.o
|
||||||
|
|
||||||
obj-$(CONFIG_MODE_TT) += tt/
|
|
||||||
obj-$(CONFIG_MODE_SKAS) += skas/
|
|
||||||
|
|
||||||
USER_OBJS := config.o
|
USER_OBJS := config.o
|
||||||
|
|
||||||
include arch/um/scripts/Makefile.rules
|
include arch/um/scripts/Makefile.rules
|
||||||
|
@ -10,8 +10,6 @@ SECTIONS
|
|||||||
PROVIDE (__executable_start = START);
|
PROVIDE (__executable_start = START);
|
||||||
. = START + SIZEOF_HEADERS;
|
. = START + SIZEOF_HEADERS;
|
||||||
.interp : { *(.interp) }
|
.interp : { *(.interp) }
|
||||||
/* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start
|
|
||||||
* is remapped.*/
|
|
||||||
__binary_start = .;
|
__binary_start = .;
|
||||||
. = ALIGN(4096); /* Init code and data */
|
. = ALIGN(4096); /* Init code and data */
|
||||||
_text = .;
|
_text = .;
|
||||||
|
@ -57,7 +57,6 @@ static long execve1(char *file, char __user * __user *argv,
|
|||||||
SUBARCH_EXECVE1(¤t->thread.regs.regs);
|
SUBARCH_EXECVE1(¤t->thread.regs.regs);
|
||||||
#endif
|
#endif
|
||||||
task_unlock(current);
|
task_unlock(current);
|
||||||
set_cmdline(current_cmd());
|
|
||||||
}
|
}
|
||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
|
@ -46,10 +46,3 @@ union thread_union init_thread_union
|
|||||||
union thread_union cpu0_irqstack
|
union thread_union cpu0_irqstack
|
||||||
__attribute__((__section__(".data.init_irqstack"))) =
|
__attribute__((__section__(".data.init_irqstack"))) =
|
||||||
{ INIT_THREAD_INFO(init_task) };
|
{ INIT_THREAD_INFO(init_task) };
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
void unprotect_stack(unsigned long stack)
|
|
||||||
{
|
|
||||||
os_protect_memory((void *) stack, THREAD_SIZE, 1, 1, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
@ -339,30 +339,6 @@ int deactivate_all_fds(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
void forward_interrupts(int pid)
|
|
||||||
{
|
|
||||||
struct irq_fd *irq;
|
|
||||||
unsigned long flags;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&irq_lock, flags);
|
|
||||||
for (irq = active_fds; irq != NULL; irq = irq->next) {
|
|
||||||
err = os_set_owner(irq->fd, pid);
|
|
||||||
if (err < 0) {
|
|
||||||
/* XXX Just remove the irq rather than
|
|
||||||
* print out an infinite stream of these
|
|
||||||
*/
|
|
||||||
printk("Failed to forward %d to pid %d, err = %d\n",
|
|
||||||
irq->fd, pid, -err);
|
|
||||||
}
|
|
||||||
|
|
||||||
irq->pid = pid;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&irq_lock, flags);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* do_IRQ handles all normal device IRQ's (the special
|
* do_IRQ handles all normal device IRQ's (the special
|
||||||
* SMP cross-CPU interrupts have their own specific
|
* SMP cross-CPU interrupts have their own specific
|
||||||
|
@ -34,24 +34,14 @@ EXPORT_SYMBOL(get_kmem_end);
|
|||||||
EXPORT_SYMBOL(high_physmem);
|
EXPORT_SYMBOL(high_physmem);
|
||||||
EXPORT_SYMBOL(empty_zero_page);
|
EXPORT_SYMBOL(empty_zero_page);
|
||||||
EXPORT_SYMBOL(um_virt_to_phys);
|
EXPORT_SYMBOL(um_virt_to_phys);
|
||||||
EXPORT_SYMBOL(mode_tt);
|
|
||||||
EXPORT_SYMBOL(handle_page_fault);
|
EXPORT_SYMBOL(handle_page_fault);
|
||||||
EXPORT_SYMBOL(find_iomem);
|
EXPORT_SYMBOL(find_iomem);
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
EXPORT_SYMBOL(stop);
|
|
||||||
EXPORT_SYMBOL(strncpy_from_user_tt);
|
|
||||||
EXPORT_SYMBOL(copy_from_user_tt);
|
|
||||||
EXPORT_SYMBOL(copy_to_user_tt);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
EXPORT_SYMBOL(strnlen_user_skas);
|
EXPORT_SYMBOL(strnlen_user_skas);
|
||||||
EXPORT_SYMBOL(strncpy_from_user_skas);
|
EXPORT_SYMBOL(strncpy_from_user_skas);
|
||||||
EXPORT_SYMBOL(copy_to_user_skas);
|
EXPORT_SYMBOL(copy_to_user_skas);
|
||||||
EXPORT_SYMBOL(copy_from_user_skas);
|
EXPORT_SYMBOL(copy_from_user_skas);
|
||||||
EXPORT_SYMBOL(clear_user_skas);
|
EXPORT_SYMBOL(clear_user_skas);
|
||||||
#endif
|
|
||||||
EXPORT_SYMBOL(uml_strdup);
|
EXPORT_SYMBOL(uml_strdup);
|
||||||
|
|
||||||
EXPORT_SYMBOL(os_stat_fd);
|
EXPORT_SYMBOL(os_stat_fd);
|
||||||
|
@ -183,13 +183,6 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
|
|||||||
kmalloc_ok = save_kmalloc_ok;
|
kmalloc_ok = save_kmalloc_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
unsigned long stack_sp(unsigned long page)
|
|
||||||
{
|
|
||||||
return page + PAGE_SIZE - sizeof(void *);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void default_idle(void)
|
void default_idle(void)
|
||||||
{
|
{
|
||||||
CHOOSE_MODE(uml_idle_timer(), (void) 0);
|
CHOOSE_MODE(uml_idle_timer(), (void) 0);
|
||||||
|
@ -14,28 +14,9 @@
|
|||||||
|
|
||||||
void (*pm_power_off)(void);
|
void (*pm_power_off)(void);
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
static void kill_idlers(int me)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
struct task_struct *p;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < ARRAY_SIZE(idle_threads); i++){
|
|
||||||
p = idle_threads[i];
|
|
||||||
if((p != NULL) && (p->thread.mode.tt.extern_pid != me))
|
|
||||||
os_kill_process(p->thread.mode.tt.extern_pid, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void kill_off_processes(void)
|
static void kill_off_processes(void)
|
||||||
{
|
{
|
||||||
CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas());
|
CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas());
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
kill_idlers(os_getpid());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void uml_cleanup(void)
|
void uml_cleanup(void)
|
||||||
|
@ -95,7 +95,6 @@ static int idle_proc(void *cpup)
|
|||||||
static struct task_struct *idle_thread(int cpu)
|
static struct task_struct *idle_thread(int cpu)
|
||||||
{
|
{
|
||||||
struct task_struct *new_task;
|
struct task_struct *new_task;
|
||||||
unsigned char c;
|
|
||||||
|
|
||||||
current->thread.request.u.thread.proc = idle_proc;
|
current->thread.request.u.thread.proc = idle_proc;
|
||||||
current->thread.request.u.thread.arg = (void *) cpu;
|
current->thread.request.u.thread.arg = (void *) cpu;
|
||||||
@ -108,9 +107,7 @@ static struct task_struct *idle_thread(int cpu)
|
|||||||
{ .pid = new_task->thread.mode.tt.extern_pid,
|
{ .pid = new_task->thread.mode.tt.extern_pid,
|
||||||
.task = new_task } );
|
.task = new_task } );
|
||||||
idle_threads[cpu] = new_task;
|
idle_threads[cpu] = new_task;
|
||||||
CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c,
|
panic("skas mode doesn't support SMP");
|
||||||
sizeof(c)),
|
|
||||||
({ panic("skas mode doesn't support SMP"); }));
|
|
||||||
return new_task;
|
return new_task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,9 +29,7 @@
|
|||||||
#include "sysdep/sigcontext.h"
|
#include "sysdep/sigcontext.h"
|
||||||
#include "sysdep/ptrace.h"
|
#include "sysdep/ptrace.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
#include "skas.h"
|
#include "skas.h"
|
||||||
#endif
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
/* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */
|
/* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
|
|
||||||
# Licensed under the GPL
|
|
||||||
#
|
|
||||||
|
|
||||||
obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
|
|
||||||
syscall_kern.o syscall_user.o tlb.o tracer.o trap_user.o \
|
|
||||||
uaccess.o uaccess_user.o
|
|
||||||
|
|
||||||
obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
|
|
||||||
|
|
||||||
USER_OBJS := gdb.o tracer.o
|
|
||||||
|
|
||||||
include arch/um/scripts/Makefile.rules
|
|
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "linux/kernel.h"
|
|
||||||
#include "linux/mm.h"
|
|
||||||
#include "asm/signal.h"
|
|
||||||
#include "asm/ptrace.h"
|
|
||||||
#include "asm/uaccess.h"
|
|
||||||
#include "asm/pgalloc.h"
|
|
||||||
#include "asm/tlbflush.h"
|
|
||||||
#include "kern_util.h"
|
|
||||||
#include "irq_user.h"
|
|
||||||
#include "mem_user.h"
|
|
||||||
#include "os.h"
|
|
||||||
#include "tlb.h"
|
|
||||||
#include "mode.h"
|
|
||||||
|
|
||||||
static int exec_tramp(void *sig_stack)
|
|
||||||
{
|
|
||||||
init_new_thread_stack(sig_stack, NULL);
|
|
||||||
init_new_thread_signals();
|
|
||||||
os_stop_process(os_getpid());
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush_thread_tt(void)
|
|
||||||
{
|
|
||||||
unsigned long stack;
|
|
||||||
int new_pid;
|
|
||||||
|
|
||||||
stack = alloc_stack(0, 0);
|
|
||||||
if(stack == 0){
|
|
||||||
printk(KERN_ERR
|
|
||||||
"flush_thread : failed to allocate temporary stack\n");
|
|
||||||
do_exit(SIGKILL);
|
|
||||||
}
|
|
||||||
|
|
||||||
new_pid = start_fork_tramp(task_stack_page(current), stack, 0, exec_tramp);
|
|
||||||
if(new_pid < 0){
|
|
||||||
printk(KERN_ERR
|
|
||||||
"flush_thread : new thread failed, errno = %d\n",
|
|
||||||
-new_pid);
|
|
||||||
do_exit(SIGKILL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(current_thread->cpu == 0)
|
|
||||||
forward_interrupts(new_pid);
|
|
||||||
current->thread.request.op = OP_EXEC;
|
|
||||||
current->thread.request.u.exec.pid = new_pid;
|
|
||||||
unprotect_stack((unsigned long) current_thread);
|
|
||||||
os_usr1_process(os_getpid());
|
|
||||||
change_sig(SIGUSR1, 1);
|
|
||||||
|
|
||||||
change_sig(SIGUSR1, 0);
|
|
||||||
enable_timer();
|
|
||||||
free_page(stack);
|
|
||||||
protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
|
|
||||||
stack_protections((unsigned long) current_thread);
|
|
||||||
force_flush_all();
|
|
||||||
unblock_signals();
|
|
||||||
}
|
|
||||||
|
|
||||||
void start_thread_tt(struct pt_regs *regs, unsigned long eip,
|
|
||||||
unsigned long esp)
|
|
||||||
{
|
|
||||||
set_fs(USER_DS);
|
|
||||||
flush_tlb_mm(current->mm);
|
|
||||||
PT_REGS_IP(regs) = eip;
|
|
||||||
PT_REGS_SP(regs) = esp;
|
|
||||||
PT_FIX_EXEC_STACK(esp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sched.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include "kern_util.h"
|
|
||||||
#include "user.h"
|
|
||||||
#include "ptrace_user.h"
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
void do_exec(int old_pid, int new_pid)
|
|
||||||
{
|
|
||||||
unsigned long regs[FRAME_SIZE];
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
|
|
||||||
(ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
|
|
||||||
tracer_panic("do_exec failed to attach proc - errno = %d",
|
|
||||||
errno);
|
|
||||||
|
|
||||||
CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
|
|
||||||
if (err < 0)
|
|
||||||
tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
|
|
||||||
errno);
|
|
||||||
|
|
||||||
if(ptrace_getregs(old_pid, regs) < 0)
|
|
||||||
tracer_panic("do_exec failed to get registers - errno = %d",
|
|
||||||
errno);
|
|
||||||
|
|
||||||
os_kill_ptraced_process(old_pid, 0);
|
|
||||||
|
|
||||||
if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
|
|
||||||
tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno);
|
|
||||||
|
|
||||||
if(ptrace_setregs(new_pid, regs) < 0)
|
|
||||||
tracer_panic("do_exec failed to start new proc - errno = %d",
|
|
||||||
errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,280 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include "ptrace_user.h"
|
|
||||||
#include "uml-config.h"
|
|
||||||
#include "kern_constants.h"
|
|
||||||
#include "chan_user.h"
|
|
||||||
#include "init.h"
|
|
||||||
#include "user.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "kern_util.h"
|
|
||||||
#include "tt.h"
|
|
||||||
#include "sysdep/thread.h"
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
extern int debugger_pid;
|
|
||||||
extern int debugger_fd;
|
|
||||||
extern int debugger_parent;
|
|
||||||
|
|
||||||
int detach(int pid, int sig)
|
|
||||||
{
|
|
||||||
return(ptrace(PTRACE_DETACH, pid, 0, sig));
|
|
||||||
}
|
|
||||||
|
|
||||||
int attach(int pid)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = ptrace(PTRACE_ATTACH, pid, 0, 0);
|
|
||||||
if(err < 0) return(-errno);
|
|
||||||
else return(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cont(int pid)
|
|
||||||
{
|
|
||||||
return(ptrace(PTRACE_CONT, pid, 0, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef UML_CONFIG_PT_PROXY
|
|
||||||
|
|
||||||
int debugger_signal(int status, pid_t pid)
|
|
||||||
{
|
|
||||||
return(debugger_proxy(status, pid));
|
|
||||||
}
|
|
||||||
|
|
||||||
void child_signal(pid_t pid, int status)
|
|
||||||
{
|
|
||||||
child_proxy(pid, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gdb_announce(char *dev_name, int dev)
|
|
||||||
{
|
|
||||||
printf("gdb assigned device '%s'\n", dev_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct chan_opts opts = {
|
|
||||||
.announce = gdb_announce,
|
|
||||||
.xterm_title = "UML kernel debugger",
|
|
||||||
.raw = 0,
|
|
||||||
.tramp_stack = 0,
|
|
||||||
.in_kernel = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Accessed by the tracing thread, which automatically serializes access */
|
|
||||||
static void *xterm_data;
|
|
||||||
static int xterm_fd;
|
|
||||||
|
|
||||||
extern void *xterm_init(char *, int, struct chan_opts *);
|
|
||||||
extern int xterm_open(int, int, int, void *, char **);
|
|
||||||
extern void xterm_close(int, void *);
|
|
||||||
|
|
||||||
int open_gdb_chan(void)
|
|
||||||
{
|
|
||||||
char stack[UM_KERN_PAGE_SIZE], *dummy;
|
|
||||||
|
|
||||||
opts.tramp_stack = (unsigned long) stack;
|
|
||||||
xterm_data = xterm_init("", 0, &opts);
|
|
||||||
xterm_fd = xterm_open(1, 1, 1, xterm_data, &dummy);
|
|
||||||
return(xterm_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void exit_debugger_cb(void *unused)
|
|
||||||
{
|
|
||||||
if(debugger_pid != -1){
|
|
||||||
if(gdb_pid != -1){
|
|
||||||
fake_child_exit();
|
|
||||||
gdb_pid = -1;
|
|
||||||
}
|
|
||||||
else kill_child_dead(debugger_pid);
|
|
||||||
debugger_pid = -1;
|
|
||||||
if(debugger_parent != -1)
|
|
||||||
detach(debugger_parent, SIGINT);
|
|
||||||
}
|
|
||||||
if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void exit_debugger(void)
|
|
||||||
{
|
|
||||||
initial_thread_cb(exit_debugger_cb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
__uml_exitcall(exit_debugger);
|
|
||||||
|
|
||||||
struct gdb_data {
|
|
||||||
char *str;
|
|
||||||
int err;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern char *linux_prog;
|
|
||||||
|
|
||||||
static void config_gdb_cb(void *arg)
|
|
||||||
{
|
|
||||||
struct gdb_data *data = arg;
|
|
||||||
void *task;
|
|
||||||
int pid;
|
|
||||||
|
|
||||||
data->err = -1;
|
|
||||||
if(debugger_pid != -1) exit_debugger_cb(NULL);
|
|
||||||
if(!strncmp(data->str, "pid,", strlen("pid,"))){
|
|
||||||
data->str += strlen("pid,");
|
|
||||||
pid = strtoul(data->str, NULL, 0);
|
|
||||||
task = cpu_tasks[0].task;
|
|
||||||
debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0);
|
|
||||||
if(debugger_pid != -1){
|
|
||||||
data->err = 0;
|
|
||||||
gdb_pid = pid;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data->err = 0;
|
|
||||||
debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
|
|
||||||
init_proxy(debugger_pid, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int gdb_config(char *str, char **error_out)
|
|
||||||
{
|
|
||||||
struct gdb_data data;
|
|
||||||
|
|
||||||
if(*str++ != '=') return(-1);
|
|
||||||
data.str = str;
|
|
||||||
initial_thread_cb(config_gdb_cb, &data);
|
|
||||||
return(data.err);
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove_gdb_cb(void *unused)
|
|
||||||
{
|
|
||||||
exit_debugger_cb(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int gdb_remove(int unused, char **error_out)
|
|
||||||
{
|
|
||||||
initial_thread_cb(remove_gdb_cb, NULL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void signal_usr1(int sig)
|
|
||||||
{
|
|
||||||
if(debugger_pid != -1){
|
|
||||||
printf("The debugger is already running\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
|
|
||||||
init_proxy(debugger_pid, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_ptrace_proxy(int idle_pid, int startup, int stop)
|
|
||||||
{
|
|
||||||
int pid, status;
|
|
||||||
|
|
||||||
pid = start_debugger(linux_prog, startup, stop, &debugger_fd);
|
|
||||||
status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
|
|
||||||
if(pid < 0){
|
|
||||||
cont(idle_pid);
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
init_proxy(pid, 1, status);
|
|
||||||
return(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
int attach_debugger(int idle_pid, int pid, int stop)
|
|
||||||
{
|
|
||||||
int status = 0, err;
|
|
||||||
|
|
||||||
err = attach(pid);
|
|
||||||
if(err < 0){
|
|
||||||
printf("Failed to attach pid %d, errno = %d\n", pid, -err);
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
|
|
||||||
init_proxy(pid, 1, status);
|
|
||||||
return(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef notdef /* Put this back in when it does something useful */
|
|
||||||
static int __init uml_gdb_init_setup(char *line, int *add)
|
|
||||||
{
|
|
||||||
gdb_init = uml_strdup(line);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
__uml_setup("gdb=", uml_gdb_init_setup,
|
|
||||||
"gdb=<channel description>\n\n"
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int __init uml_gdb_pid_setup(char *line, int *add)
|
|
||||||
{
|
|
||||||
gdb_pid = strtoul(line, NULL, 0);
|
|
||||||
*add = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
__uml_setup("gdb-pid=", uml_gdb_pid_setup,
|
|
||||||
"gdb-pid=<pid>\n"
|
|
||||||
" gdb-pid is used to attach an external debugger to UML. This may be\n"
|
|
||||||
" an already-running gdb or a debugger-like process like strace.\n\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
int debugger_signal(int status, pid_t pid){ return(0); }
|
|
||||||
void child_signal(pid_t pid, int status){ }
|
|
||||||
int init_ptrace_proxy(int idle_pid, int startup, int stop)
|
|
||||||
{
|
|
||||||
printf("debug requested when CONFIG_PT_PROXY is off\n");
|
|
||||||
kill_child_dead(idle_pid);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void signal_usr1(int sig)
|
|
||||||
{
|
|
||||||
printf("debug requested when CONFIG_PT_PROXY is off\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int attach_debugger(int idle_pid, int pid, int stop)
|
|
||||||
{
|
|
||||||
printf("attach_debugger called when CONFIG_PT_PROXY "
|
|
||||||
"is off\n");
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int config_gdb(char *str)
|
|
||||||
{
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int remove_gdb(void)
|
|
||||||
{
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_parent_proxy(int pid)
|
|
||||||
{
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void debugger_parent_signal(int status, int pid)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "linux/init.h"
|
|
||||||
#include "mconsole_kern.h"
|
|
||||||
|
|
||||||
#ifdef CONFIG_MCONSOLE
|
|
||||||
|
|
||||||
extern int gdb_config(char *str, char **error_out);
|
|
||||||
extern int gdb_remove(int n, char **error_out);
|
|
||||||
|
|
||||||
static struct mc_device gdb_mc = {
|
|
||||||
.list = INIT_LIST_HEAD(gdb_mc.list),
|
|
||||||
.name = "gdb",
|
|
||||||
.config = gdb_config,
|
|
||||||
.remove = gdb_remove,
|
|
||||||
};
|
|
||||||
|
|
||||||
int gdb_mc_init(void)
|
|
||||||
{
|
|
||||||
mconsole_register_dev(&gdb_mc);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
__initcall(gdb_mc_init);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __MODE_TT_H__
|
|
||||||
#define __MODE_TT_H__
|
|
||||||
|
|
||||||
#include "sysdep/ptrace.h"
|
|
||||||
|
|
||||||
enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
|
|
||||||
|
|
||||||
extern int tracing_pid;
|
|
||||||
|
|
||||||
extern int tracer(int (*init_proc)(void *), void *sp);
|
|
||||||
extern void sig_handler_common_tt(int sig, void *sc);
|
|
||||||
extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
|
|
||||||
extern void reboot_tt(void);
|
|
||||||
extern void halt_tt(void);
|
|
||||||
extern int is_tracer_winch(int pid, int fd, void *data);
|
|
||||||
extern void kill_off_processes_tt(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "linux/module.h"
|
|
||||||
#include "asm/uaccess.h"
|
|
||||||
#include "mode.h"
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(__do_copy_from_user);
|
|
||||||
EXPORT_SYMBOL(__do_copy_to_user);
|
|
||||||
EXPORT_SYMBOL(__do_strncpy_from_user);
|
|
||||||
EXPORT_SYMBOL(__do_strnlen_user);
|
|
||||||
EXPORT_SYMBOL(__do_clear_user);
|
|
||||||
EXPORT_SYMBOL(clear_user_tt);
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(tracing_pid);
|
|
||||||
EXPORT_SYMBOL(honeypot);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "linux/stddef.h"
|
|
||||||
#include "linux/mm.h"
|
|
||||||
#include "asm/uaccess.h"
|
|
||||||
#include "mem_user.h"
|
|
||||||
#include "kern_util.h"
|
|
||||||
#include "kern.h"
|
|
||||||
#include "tt.h"
|
|
||||||
|
|
||||||
void before_mem_tt(unsigned long brk_start)
|
|
||||||
{
|
|
||||||
if(debug)
|
|
||||||
remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1);
|
|
||||||
remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1);
|
|
||||||
remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
|
|
||||||
#define START (CONFIG_TOP_ADDR - SIZE)
|
|
||||||
|
|
||||||
unsigned long set_task_sizes_tt(unsigned long *task_size_out)
|
|
||||||
{
|
|
||||||
unsigned long host_task_size;
|
|
||||||
|
|
||||||
/* Round up to the nearest 4M */
|
|
||||||
host_task_size = ROUND_4M((unsigned long) &host_task_size);
|
|
||||||
*task_size_out = START;
|
|
||||||
|
|
||||||
return host_task_size;
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include "tt.h"
|
|
||||||
#include "mem_user.h"
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
void remap_data(void *segment_start, void *segment_end, int w)
|
|
||||||
{
|
|
||||||
void *addr;
|
|
||||||
unsigned long size;
|
|
||||||
int data, prot;
|
|
||||||
|
|
||||||
if(w) prot = PROT_WRITE;
|
|
||||||
else prot = 0;
|
|
||||||
prot |= PROT_READ | PROT_EXEC;
|
|
||||||
size = (unsigned long) segment_end -
|
|
||||||
(unsigned long) segment_start;
|
|
||||||
data = create_mem_file(size);
|
|
||||||
addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0);
|
|
||||||
if(addr == MAP_FAILED){
|
|
||||||
perror("mapping new data segment");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
memcpy(addr, segment_start, size);
|
|
||||||
if(switcheroo(data, prot, addr, segment_start, size) < 0){
|
|
||||||
printf("switcheroo failed\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,461 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "linux/sched.h"
|
|
||||||
#include "linux/signal.h"
|
|
||||||
#include "linux/kernel.h"
|
|
||||||
#include "linux/interrupt.h"
|
|
||||||
#include "linux/ptrace.h"
|
|
||||||
#include "asm/system.h"
|
|
||||||
#include "asm/pgalloc.h"
|
|
||||||
#include "asm/ptrace.h"
|
|
||||||
#include "asm/tlbflush.h"
|
|
||||||
#include "irq_user.h"
|
|
||||||
#include "kern_util.h"
|
|
||||||
#include "os.h"
|
|
||||||
#include "kern.h"
|
|
||||||
#include "sigcontext.h"
|
|
||||||
#include "mem_user.h"
|
|
||||||
#include "tlb.h"
|
|
||||||
#include "mode.h"
|
|
||||||
#include "mode_kern.h"
|
|
||||||
#include "init.h"
|
|
||||||
#include "tt.h"
|
|
||||||
|
|
||||||
void switch_to_tt(void *prev, void *next)
|
|
||||||
{
|
|
||||||
struct task_struct *from, *to, *prev_sched;
|
|
||||||
unsigned long flags;
|
|
||||||
int err, vtalrm, alrm, prof, cpu;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
from = prev;
|
|
||||||
to = next;
|
|
||||||
|
|
||||||
cpu = task_thread_info(from)->cpu;
|
|
||||||
if(cpu == 0)
|
|
||||||
forward_interrupts(to->thread.mode.tt.extern_pid);
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid);
|
|
||||||
#endif
|
|
||||||
local_irq_save(flags);
|
|
||||||
|
|
||||||
vtalrm = change_sig(SIGVTALRM, 0);
|
|
||||||
alrm = change_sig(SIGALRM, 0);
|
|
||||||
prof = change_sig(SIGPROF, 0);
|
|
||||||
|
|
||||||
forward_pending_sigio(to->thread.mode.tt.extern_pid);
|
|
||||||
|
|
||||||
c = 0;
|
|
||||||
|
|
||||||
/* Notice that here we "up" the semaphore on which "to" is waiting, and
|
|
||||||
* below (the read) we wait on this semaphore (which is implemented by
|
|
||||||
* switch_pipe) and go sleeping. Thus, after that, we have resumed in
|
|
||||||
* "to", and can't use any more the value of "from" (which is outdated),
|
|
||||||
* nor the value in "to" (since it was the task which stole us the CPU,
|
|
||||||
* which we don't care about). */
|
|
||||||
|
|
||||||
err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
|
|
||||||
if(err != sizeof(c))
|
|
||||||
panic("write of switch_pipe failed, err = %d", -err);
|
|
||||||
|
|
||||||
if(from->thread.mode.tt.switch_pipe[0] == -1)
|
|
||||||
os_kill_process(os_getpid(), 0);
|
|
||||||
|
|
||||||
err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c,
|
|
||||||
sizeof(c));
|
|
||||||
if(err != sizeof(c))
|
|
||||||
panic("read of switch_pipe failed, errno = %d", -err);
|
|
||||||
|
|
||||||
/* If the process that we have just scheduled away from has exited,
|
|
||||||
* then it needs to be killed here. The reason is that, even though
|
|
||||||
* it will kill itself when it next runs, that may be too late. Its
|
|
||||||
* stack will be freed, possibly before then, and if that happens,
|
|
||||||
* we have a use-after-free situation. So, it gets killed here
|
|
||||||
* in case it has not already killed itself.
|
|
||||||
*/
|
|
||||||
prev_sched = current->thread.prev_sched;
|
|
||||||
if(prev_sched->thread.mode.tt.switch_pipe[0] == -1)
|
|
||||||
os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1);
|
|
||||||
|
|
||||||
change_sig(SIGVTALRM, vtalrm);
|
|
||||||
change_sig(SIGALRM, alrm);
|
|
||||||
change_sig(SIGPROF, prof);
|
|
||||||
|
|
||||||
arch_switch_to_tt(prev_sched, current);
|
|
||||||
|
|
||||||
flush_tlb_all();
|
|
||||||
local_irq_restore(flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
void release_thread_tt(struct task_struct *task)
|
|
||||||
{
|
|
||||||
int pid = task->thread.mode.tt.extern_pid;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We first have to kill the other process, before
|
|
||||||
* closing its switch_pipe. Else it might wake up
|
|
||||||
* and receive "EOF" before we could kill it.
|
|
||||||
*/
|
|
||||||
if(os_getpid() != pid)
|
|
||||||
os_kill_process(pid, 0);
|
|
||||||
|
|
||||||
os_close_file(task->thread.mode.tt.switch_pipe[0]);
|
|
||||||
os_close_file(task->thread.mode.tt.switch_pipe[1]);
|
|
||||||
/* use switch_pipe as flag: thread is released */
|
|
||||||
task->thread.mode.tt.switch_pipe[0] = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void suspend_new_thread(int fd)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
os_stop_process(os_getpid());
|
|
||||||
err = os_read_file(fd, &c, sizeof(c));
|
|
||||||
if(err != sizeof(c))
|
|
||||||
panic("read failed in suspend_new_thread, err = %d", -err);
|
|
||||||
}
|
|
||||||
|
|
||||||
void schedule_tail(struct task_struct *prev);
|
|
||||||
|
|
||||||
static void new_thread_handler(int sig)
|
|
||||||
{
|
|
||||||
unsigned long disable;
|
|
||||||
int (*fn)(void *);
|
|
||||||
void *arg;
|
|
||||||
|
|
||||||
fn = current->thread.request.u.thread.proc;
|
|
||||||
arg = current->thread.request.u.thread.arg;
|
|
||||||
|
|
||||||
UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1);
|
|
||||||
disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) |
|
|
||||||
(1 << (SIGIO - 1)) | (1 << (SIGPROF - 1));
|
|
||||||
SC_SIGMASK(UPT_SC(¤t->thread.regs.regs)) &= ~disable;
|
|
||||||
|
|
||||||
suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
|
|
||||||
|
|
||||||
force_flush_all();
|
|
||||||
if(current->thread.prev_sched != NULL)
|
|
||||||
schedule_tail(current->thread.prev_sched);
|
|
||||||
current->thread.prev_sched = NULL;
|
|
||||||
|
|
||||||
init_new_thread_signals();
|
|
||||||
enable_timer();
|
|
||||||
free_page(current->thread.temp_stack);
|
|
||||||
set_cmdline("(kernel thread)");
|
|
||||||
|
|
||||||
change_sig(SIGUSR1, 1);
|
|
||||||
change_sig(SIGPROF, 1);
|
|
||||||
local_irq_enable();
|
|
||||||
if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf))
|
|
||||||
do_exit(0);
|
|
||||||
|
|
||||||
/* XXX No set_user_mode here because a newly execed process will
|
|
||||||
* immediately segfault on its non-existent IP, coming straight back
|
|
||||||
* to the signal handler, which will call set_user_mode on its way
|
|
||||||
* out. This should probably change since it's confusing.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
static int new_thread_proc(void *stack)
|
|
||||||
{
|
|
||||||
/* local_irq_disable is needed to block out signals until this thread is
|
|
||||||
* properly scheduled. Otherwise, the tracing thread will get mighty
|
|
||||||
* upset about any signals that arrive before that.
|
|
||||||
* This has the complication that it sets the saved signal mask in
|
|
||||||
* the sigcontext to block signals. This gets restored when this
|
|
||||||
* thread (or a descendant, since they get a copy of this sigcontext)
|
|
||||||
* returns to userspace.
|
|
||||||
* So, this is compensated for elsewhere.
|
|
||||||
* XXX There is still a small window until local_irq_disable() actually
|
|
||||||
* finishes where signals are possible - shouldn't be a problem in
|
|
||||||
* practice since SIGIO hasn't been forwarded here yet, and the
|
|
||||||
* local_irq_disable should finish before a SIGVTALRM has time to be
|
|
||||||
* delivered.
|
|
||||||
*/
|
|
||||||
|
|
||||||
local_irq_disable();
|
|
||||||
init_new_thread_stack(stack, new_thread_handler);
|
|
||||||
os_usr1_process(os_getpid());
|
|
||||||
change_sig(SIGUSR1, 1);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Signal masking - signals are blocked at the start of fork_tramp. They
|
|
||||||
* are re-enabled when finish_fork_handler is entered by fork_tramp hitting
|
|
||||||
* itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off,
|
|
||||||
* so it is blocked before it's called. They are re-enabled on sigreturn
|
|
||||||
* despite the fact that they were blocked when the SIGUSR1 was issued because
|
|
||||||
* copy_thread copies the parent's sigcontext, including the signal mask
|
|
||||||
* onto the signal frame.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void finish_fork_handler(int sig)
|
|
||||||
{
|
|
||||||
UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1);
|
|
||||||
suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
|
|
||||||
|
|
||||||
force_flush_all();
|
|
||||||
if(current->thread.prev_sched != NULL)
|
|
||||||
schedule_tail(current->thread.prev_sched);
|
|
||||||
current->thread.prev_sched = NULL;
|
|
||||||
|
|
||||||
enable_timer();
|
|
||||||
change_sig(SIGVTALRM, 1);
|
|
||||||
local_irq_enable();
|
|
||||||
if(current->mm != current->parent->mm)
|
|
||||||
protect_memory(uml_reserved, high_physmem - uml_reserved, 1,
|
|
||||||
1, 0, 1);
|
|
||||||
stack_protections((unsigned long) current_thread);
|
|
||||||
|
|
||||||
free_page(current->thread.temp_stack);
|
|
||||||
local_irq_disable();
|
|
||||||
change_sig(SIGUSR1, 0);
|
|
||||||
set_user_mode(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fork_tramp(void *stack)
|
|
||||||
{
|
|
||||||
local_irq_disable();
|
|
||||||
arch_init_thread();
|
|
||||||
init_new_thread_stack(stack, finish_fork_handler);
|
|
||||||
|
|
||||||
os_usr1_process(os_getpid());
|
|
||||||
change_sig(SIGUSR1, 1);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
|
|
||||||
unsigned long stack_top, struct task_struct * p,
|
|
||||||
struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
int (*tramp)(void *);
|
|
||||||
int new_pid, err;
|
|
||||||
unsigned long stack;
|
|
||||||
|
|
||||||
if(current->thread.forking)
|
|
||||||
tramp = fork_tramp;
|
|
||||||
else {
|
|
||||||
tramp = new_thread_proc;
|
|
||||||
p->thread.request.u.thread = current->thread.request.u.thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
|
|
||||||
if(err < 0){
|
|
||||||
printk("copy_thread : pipe failed, err = %d\n", -err);
|
|
||||||
return(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
stack = alloc_stack(0, 0);
|
|
||||||
if(stack == 0){
|
|
||||||
printk(KERN_ERR "copy_thread : failed to allocate "
|
|
||||||
"temporary stack\n");
|
|
||||||
return(-ENOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
clone_flags &= CLONE_VM;
|
|
||||||
p->thread.temp_stack = stack;
|
|
||||||
new_pid = start_fork_tramp(task_stack_page(p), stack, clone_flags, tramp);
|
|
||||||
if(new_pid < 0){
|
|
||||||
printk(KERN_ERR "copy_thread : clone failed - errno = %d\n",
|
|
||||||
-new_pid);
|
|
||||||
return(new_pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(current->thread.forking){
|
|
||||||
sc_to_sc(UPT_SC(&p->thread.regs.regs), UPT_SC(®s->regs));
|
|
||||||
SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0);
|
|
||||||
if(sp != 0)
|
|
||||||
SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
|
|
||||||
}
|
|
||||||
p->thread.mode.tt.extern_pid = new_pid;
|
|
||||||
|
|
||||||
current->thread.request.op = OP_FORK;
|
|
||||||
current->thread.request.u.fork.pid = new_pid;
|
|
||||||
os_usr1_process(os_getpid());
|
|
||||||
|
|
||||||
/* Enable the signal and then disable it to ensure that it is handled
|
|
||||||
* here, and nowhere else.
|
|
||||||
*/
|
|
||||||
change_sig(SIGUSR1, 1);
|
|
||||||
|
|
||||||
change_sig(SIGUSR1, 0);
|
|
||||||
err = 0;
|
|
||||||
return(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reboot_tt(void)
|
|
||||||
{
|
|
||||||
current->thread.request.op = OP_REBOOT;
|
|
||||||
os_usr1_process(os_getpid());
|
|
||||||
change_sig(SIGUSR1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void halt_tt(void)
|
|
||||||
{
|
|
||||||
current->thread.request.op = OP_HALT;
|
|
||||||
os_usr1_process(os_getpid());
|
|
||||||
change_sig(SIGUSR1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void kill_off_processes_tt(void)
|
|
||||||
{
|
|
||||||
struct task_struct *p;
|
|
||||||
int me;
|
|
||||||
|
|
||||||
me = os_getpid();
|
|
||||||
for_each_process(p){
|
|
||||||
if(p->thread.mode.tt.extern_pid != me)
|
|
||||||
os_kill_process(p->thread.mode.tt.extern_pid, 0);
|
|
||||||
}
|
|
||||||
if(init_task.thread.mode.tt.extern_pid != me)
|
|
||||||
os_kill_process(init_task.thread.mode.tt.extern_pid, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initial_thread_cb_tt(void (*proc)(void *), void *arg)
|
|
||||||
{
|
|
||||||
if(os_getpid() == tracing_pid){
|
|
||||||
(*proc)(arg);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
current->thread.request.op = OP_CB;
|
|
||||||
current->thread.request.u.cb.proc = proc;
|
|
||||||
current->thread.request.u.cb.arg = arg;
|
|
||||||
os_usr1_process(os_getpid());
|
|
||||||
change_sig(SIGUSR1, 1);
|
|
||||||
|
|
||||||
change_sig(SIGUSR1, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int do_proc_op(void *t, int proc_id)
|
|
||||||
{
|
|
||||||
struct task_struct *task;
|
|
||||||
struct thread_struct *thread;
|
|
||||||
int op, pid;
|
|
||||||
|
|
||||||
task = t;
|
|
||||||
thread = &task->thread;
|
|
||||||
op = thread->request.op;
|
|
||||||
switch(op){
|
|
||||||
case OP_NONE:
|
|
||||||
case OP_TRACE_ON:
|
|
||||||
break;
|
|
||||||
case OP_EXEC:
|
|
||||||
pid = thread->request.u.exec.pid;
|
|
||||||
do_exec(thread->mode.tt.extern_pid, pid);
|
|
||||||
thread->mode.tt.extern_pid = pid;
|
|
||||||
cpu_tasks[task_thread_info(task)->cpu].pid = pid;
|
|
||||||
break;
|
|
||||||
case OP_FORK:
|
|
||||||
attach_process(thread->request.u.fork.pid);
|
|
||||||
break;
|
|
||||||
case OP_CB:
|
|
||||||
(*thread->request.u.cb.proc)(thread->request.u.cb.arg);
|
|
||||||
break;
|
|
||||||
case OP_REBOOT:
|
|
||||||
case OP_HALT:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
tracer_panic("Bad op in do_proc_op");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
thread->request.op = OP_NONE;
|
|
||||||
return(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_idle_tt(void)
|
|
||||||
{
|
|
||||||
default_idle();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void start_kernel(void);
|
|
||||||
|
|
||||||
static int start_kernel_proc(void *unused)
|
|
||||||
{
|
|
||||||
int pid;
|
|
||||||
|
|
||||||
block_signals();
|
|
||||||
pid = os_getpid();
|
|
||||||
|
|
||||||
cpu_tasks[0].pid = pid;
|
|
||||||
cpu_tasks[0].task = current;
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
cpu_online_map = cpumask_of_cpu(0);
|
|
||||||
#endif
|
|
||||||
if(debug) os_stop_process(pid);
|
|
||||||
start_kernel();
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_tracing(void *task, int tracing)
|
|
||||||
{
|
|
||||||
((struct task_struct *) task)->thread.mode.tt.tracing = tracing;
|
|
||||||
}
|
|
||||||
|
|
||||||
int is_tracing(void *t)
|
|
||||||
{
|
|
||||||
return (((struct task_struct *) t)->thread.mode.tt.tracing);
|
|
||||||
}
|
|
||||||
|
|
||||||
int set_user_mode(void *t)
|
|
||||||
{
|
|
||||||
struct task_struct *task;
|
|
||||||
|
|
||||||
task = t ? t : current;
|
|
||||||
if(task->thread.mode.tt.tracing)
|
|
||||||
return(1);
|
|
||||||
task->thread.request.op = OP_TRACE_ON;
|
|
||||||
os_usr1_process(os_getpid());
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_init_pid(int pid)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
init_task.thread.mode.tt.extern_pid = pid;
|
|
||||||
err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1);
|
|
||||||
if(err)
|
|
||||||
panic("Can't create switch pipe for init_task, errno = %d",
|
|
||||||
-err);
|
|
||||||
}
|
|
||||||
|
|
||||||
int start_uml_tt(void)
|
|
||||||
{
|
|
||||||
void *sp;
|
|
||||||
int pages;
|
|
||||||
|
|
||||||
pages = (1 << CONFIG_KERNEL_STACK_ORDER);
|
|
||||||
sp = task_stack_page(&init_task) +
|
|
||||||
pages * PAGE_SIZE - sizeof(unsigned long);
|
|
||||||
return(tracer(start_kernel_proc, sp));
|
|
||||||
}
|
|
||||||
|
|
||||||
int external_pid_tt(struct task_struct *task)
|
|
||||||
{
|
|
||||||
return(task->thread.mode.tt.extern_pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
int thread_pid_tt(struct task_struct *task)
|
|
||||||
{
|
|
||||||
return(task->thread.mode.tt.extern_pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
int is_valid_pid(int pid)
|
|
||||||
{
|
|
||||||
struct task_struct *task;
|
|
||||||
|
|
||||||
read_lock(&tasklist_lock);
|
|
||||||
for_each_process(task){
|
|
||||||
if(task->thread.mode.tt.extern_pid == pid){
|
|
||||||
read_unlock(&tasklist_lock);
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
read_unlock(&tasklist_lock);
|
|
||||||
return(0);
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
# Licensed under the GPL
|
|
||||||
#
|
|
||||||
|
|
||||||
obj-y = proxy.o ptrace.o sysdep.o wait.o
|
|
||||||
|
|
||||||
USER_OBJS := $(obj-y)
|
|
||||||
|
|
||||||
include arch/um/scripts/Makefile.rules
|
|
@ -1,377 +0,0 @@
|
|||||||
/**********************************************************************
|
|
||||||
proxy.c
|
|
||||||
|
|
||||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
|
||||||
terms and conditions.
|
|
||||||
|
|
||||||
Jeff Dike (jdike@karaya.com) : Modified for integration into uml
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
/* XXX This file shouldn't refer to CONFIG_* */
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <asm/unistd.h>
|
|
||||||
#include "ptrace_user.h"
|
|
||||||
|
|
||||||
#include "ptproxy.h"
|
|
||||||
#include "sysdep.h"
|
|
||||||
#include "wait.h"
|
|
||||||
|
|
||||||
#include "user.h"
|
|
||||||
#include "os.h"
|
|
||||||
#include "tempfile.h"
|
|
||||||
|
|
||||||
static int debugger_wait(debugger_state *debugger, int *status, int options,
|
|
||||||
int (*syscall)(debugger_state *debugger, pid_t child),
|
|
||||||
int (*normal_return)(debugger_state *debugger,
|
|
||||||
pid_t unused),
|
|
||||||
int (*wait_return)(debugger_state *debugger,
|
|
||||||
pid_t unused))
|
|
||||||
{
|
|
||||||
if(debugger->real_wait){
|
|
||||||
debugger->handle_trace = normal_return;
|
|
||||||
syscall_continue(debugger->pid);
|
|
||||||
debugger->real_wait = 0;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
debugger->wait_status_ptr = status;
|
|
||||||
debugger->wait_options = options;
|
|
||||||
if((debugger->debugee != NULL) && debugger->debugee->event){
|
|
||||||
syscall_continue(debugger->pid);
|
|
||||||
wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL,
|
|
||||||
NULL);
|
|
||||||
(*wait_return)(debugger, -1);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
else if(debugger->wait_options & WNOHANG){
|
|
||||||
syscall_cancel(debugger->pid, 0);
|
|
||||||
debugger->handle_trace = syscall;
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
syscall_pause(debugger->pid);
|
|
||||||
debugger->handle_trace = wait_return;
|
|
||||||
debugger->waiting = 1;
|
|
||||||
}
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle debugger trap, i.e. syscall.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int debugger_syscall(debugger_state *debugger, pid_t child)
|
|
||||||
{
|
|
||||||
long arg1, arg2, arg3, arg4, arg5, result;
|
|
||||||
int syscall, ret = 0;
|
|
||||||
|
|
||||||
syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4,
|
|
||||||
&arg5);
|
|
||||||
|
|
||||||
switch(syscall){
|
|
||||||
case __NR_execve:
|
|
||||||
/* execve never returns */
|
|
||||||
debugger->handle_trace = debugger_syscall;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case __NR_ptrace:
|
|
||||||
if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid;
|
|
||||||
if(!debugger->debugee->in_context)
|
|
||||||
child = debugger->debugee->pid;
|
|
||||||
result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child,
|
|
||||||
&ret);
|
|
||||||
syscall_cancel(debugger->pid, result);
|
|
||||||
debugger->handle_trace = debugger_syscall;
|
|
||||||
return(ret);
|
|
||||||
|
|
||||||
#ifdef __NR_waitpid
|
|
||||||
case __NR_waitpid:
|
|
||||||
#endif
|
|
||||||
case __NR_wait4:
|
|
||||||
if(!debugger_wait(debugger, (int *) arg2, arg3,
|
|
||||||
debugger_syscall, debugger_normal_return,
|
|
||||||
proxy_wait_return))
|
|
||||||
return(0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case __NR_kill:
|
|
||||||
if(!debugger->debugee->in_context)
|
|
||||||
child = debugger->debugee->pid;
|
|
||||||
if(arg1 == debugger->debugee->pid){
|
|
||||||
result = kill(child, arg2);
|
|
||||||
syscall_cancel(debugger->pid, result);
|
|
||||||
debugger->handle_trace = debugger_syscall;
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
else debugger->handle_trace = debugger_normal_return;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
debugger->handle_trace = debugger_normal_return;
|
|
||||||
}
|
|
||||||
|
|
||||||
syscall_continue(debugger->pid);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Used by the tracing thread */
|
|
||||||
static debugger_state parent;
|
|
||||||
static int parent_syscall(debugger_state *debugger, int pid);
|
|
||||||
|
|
||||||
int init_parent_proxy(int pid)
|
|
||||||
{
|
|
||||||
parent = ((debugger_state) { .pid = pid,
|
|
||||||
.wait_options = 0,
|
|
||||||
.wait_status_ptr = NULL,
|
|
||||||
.waiting = 0,
|
|
||||||
.real_wait = 0,
|
|
||||||
.expecting_child = 0,
|
|
||||||
.handle_trace = parent_syscall,
|
|
||||||
.debugee = NULL } );
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int parent_normal_return(debugger_state *debugger, pid_t unused)
|
|
||||||
{
|
|
||||||
debugger->handle_trace = parent_syscall;
|
|
||||||
syscall_continue(debugger->pid);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parent_syscall(debugger_state *debugger, int pid)
|
|
||||||
{
|
|
||||||
long arg1, arg2, arg3, arg4, arg5;
|
|
||||||
int syscall;
|
|
||||||
|
|
||||||
syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
|
|
||||||
|
|
||||||
if((syscall == __NR_wait4)
|
|
||||||
#ifdef __NR_waitpid
|
|
||||||
|| (syscall == __NR_waitpid)
|
|
||||||
#endif
|
|
||||||
){
|
|
||||||
debugger_wait(&parent, (int *) arg2, arg3, parent_syscall,
|
|
||||||
parent_normal_return, parent_wait_return);
|
|
||||||
}
|
|
||||||
else ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int debugger_normal_return(debugger_state *debugger, pid_t unused)
|
|
||||||
{
|
|
||||||
debugger->handle_trace = debugger_syscall;
|
|
||||||
syscall_continue(debugger->pid);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void debugger_cancelled_return(debugger_state *debugger, int result)
|
|
||||||
{
|
|
||||||
debugger->handle_trace = debugger_syscall;
|
|
||||||
syscall_set_result(debugger->pid, result);
|
|
||||||
syscall_continue(debugger->pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Used by the tracing thread */
|
|
||||||
static debugger_state debugger;
|
|
||||||
static debugee_state debugee;
|
|
||||||
|
|
||||||
void init_proxy (pid_t debugger_pid, int stopped, int status)
|
|
||||||
{
|
|
||||||
debugger.pid = debugger_pid;
|
|
||||||
debugger.handle_trace = debugger_syscall;
|
|
||||||
debugger.debugee = &debugee;
|
|
||||||
debugger.waiting = 0;
|
|
||||||
debugger.real_wait = 0;
|
|
||||||
debugger.expecting_child = 0;
|
|
||||||
|
|
||||||
debugee.pid = 0;
|
|
||||||
debugee.traced = 0;
|
|
||||||
debugee.stopped = stopped;
|
|
||||||
debugee.event = 0;
|
|
||||||
debugee.zombie = 0;
|
|
||||||
debugee.died = 0;
|
|
||||||
debugee.wait_status = status;
|
|
||||||
debugee.in_context = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int debugger_proxy(int status, int pid)
|
|
||||||
{
|
|
||||||
int ret = 0, sig;
|
|
||||||
|
|
||||||
if(WIFSTOPPED(status)){
|
|
||||||
sig = WSTOPSIG(status);
|
|
||||||
if (sig == SIGTRAP)
|
|
||||||
ret = (*debugger.handle_trace)(&debugger, pid);
|
|
||||||
|
|
||||||
else if(sig == SIGCHLD){
|
|
||||||
if(debugger.expecting_child){
|
|
||||||
ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
|
|
||||||
debugger.expecting_child = 0;
|
|
||||||
}
|
|
||||||
else if(debugger.waiting)
|
|
||||||
real_wait_return(&debugger);
|
|
||||||
else {
|
|
||||||
ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
|
|
||||||
debugger.real_wait = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
|
|
||||||
}
|
|
||||||
else if(WIFEXITED(status)){
|
|
||||||
tracer_panic("debugger (pid %d) exited with status %d",
|
|
||||||
debugger.pid, WEXITSTATUS(status));
|
|
||||||
}
|
|
||||||
else if(WIFSIGNALED(status)){
|
|
||||||
tracer_panic("debugger (pid %d) exited with signal %d",
|
|
||||||
debugger.pid, WTERMSIG(status));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tracer_panic("proxy got unknown status (0x%x) on debugger "
|
|
||||||
"(pid %d)", status, debugger.pid);
|
|
||||||
}
|
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
void child_proxy(pid_t pid, int status)
|
|
||||||
{
|
|
||||||
debugee.event = 1;
|
|
||||||
debugee.wait_status = status;
|
|
||||||
|
|
||||||
if(WIFSTOPPED(status)){
|
|
||||||
debugee.stopped = 1;
|
|
||||||
debugger.expecting_child = 1;
|
|
||||||
kill(debugger.pid, SIGCHLD);
|
|
||||||
}
|
|
||||||
else if(WIFEXITED(status) || WIFSIGNALED(status)){
|
|
||||||
debugee.zombie = 1;
|
|
||||||
debugger.expecting_child = 1;
|
|
||||||
kill(debugger.pid, SIGCHLD);
|
|
||||||
}
|
|
||||||
else panic("proxy got unknown status (0x%x) on child (pid %d)",
|
|
||||||
status, pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void debugger_parent_signal(int status, int pid)
|
|
||||||
{
|
|
||||||
int sig;
|
|
||||||
|
|
||||||
if(WIFSTOPPED(status)){
|
|
||||||
sig = WSTOPSIG(status);
|
|
||||||
if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid);
|
|
||||||
else ptrace(PTRACE_SYSCALL, pid, 0, sig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void fake_child_exit(void)
|
|
||||||
{
|
|
||||||
int status, pid;
|
|
||||||
|
|
||||||
child_proxy(1, W_EXITCODE(0, 0));
|
|
||||||
while(debugger.waiting == 1){
|
|
||||||
CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
|
|
||||||
if(pid != debugger.pid){
|
|
||||||
printk("fake_child_exit - waitpid failed, "
|
|
||||||
"errno = %d\n", errno);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
debugger_proxy(status, debugger.pid);
|
|
||||||
}
|
|
||||||
CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
|
|
||||||
if(pid != debugger.pid){
|
|
||||||
printk("fake_child_exit - waitpid failed, "
|
|
||||||
"errno = %d\n", errno);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
|
|
||||||
printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
|
|
||||||
errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
char gdb_init_string[] =
|
|
||||||
"att 1 \n\
|
|
||||||
b panic \n\
|
|
||||||
b stop \n\
|
|
||||||
handle SIGWINCH nostop noprint pass \n\
|
|
||||||
";
|
|
||||||
|
|
||||||
int start_debugger(char *prog, int startup, int stop, int *fd_out)
|
|
||||||
{
|
|
||||||
int slave, child;
|
|
||||||
|
|
||||||
slave = open_gdb_chan();
|
|
||||||
child = fork();
|
|
||||||
if(child == 0){
|
|
||||||
char *tempname = NULL;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if(setsid() < 0) perror("setsid");
|
|
||||||
if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) ||
|
|
||||||
(dup2(slave, 2) < 0)){
|
|
||||||
printk("start_debugger : dup2 failed, errno = %d\n",
|
|
||||||
errno);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if(ioctl(0, TIOCSCTTY, 0) < 0){
|
|
||||||
printk("start_debugger : TIOCSCTTY failed, "
|
|
||||||
"errno = %d\n", errno);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if(tcsetpgrp (1, os_getpid()) < 0){
|
|
||||||
printk("start_debugger : tcsetpgrp failed, "
|
|
||||||
"errno = %d\n", errno);
|
|
||||||
#ifdef notdef
|
|
||||||
exit(1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
|
|
||||||
if(fd < 0){
|
|
||||||
printk("start_debugger : make_tempfile failed,"
|
|
||||||
"err = %d\n", -fd);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
os_write_file(fd, gdb_init_string,
|
|
||||||
sizeof(gdb_init_string) - 1);
|
|
||||||
if(startup){
|
|
||||||
if(stop){
|
|
||||||
os_write_file(fd, "b start_kernel\n",
|
|
||||||
strlen("b start_kernel\n"));
|
|
||||||
}
|
|
||||||
os_write_file(fd, "c\n", strlen("c\n"));
|
|
||||||
}
|
|
||||||
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
|
|
||||||
printk("start_debugger : PTRACE_TRACEME failed, "
|
|
||||||
"errno = %d\n", errno);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
execlp("gdb", "gdb", "--command", tempname, prog, NULL);
|
|
||||||
printk("start_debugger : exec of gdb failed, errno = %d\n",
|
|
||||||
errno);
|
|
||||||
}
|
|
||||||
if(child < 0){
|
|
||||||
printk("start_debugger : fork for gdb failed, errno = %d\n",
|
|
||||||
errno);
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
*fd_out = slave;
|
|
||||||
return(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,61 +0,0 @@
|
|||||||
/**********************************************************************
|
|
||||||
ptproxy.h
|
|
||||||
|
|
||||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
|
||||||
terms and conditions.
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
#ifndef __PTPROXY_H
|
|
||||||
#define __PTPROXY_H
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
typedef struct debugger debugger_state;
|
|
||||||
typedef struct debugee debugee_state;
|
|
||||||
|
|
||||||
struct debugger
|
|
||||||
{
|
|
||||||
pid_t pid;
|
|
||||||
int wait_options;
|
|
||||||
int *wait_status_ptr;
|
|
||||||
unsigned int waiting : 1;
|
|
||||||
unsigned int real_wait : 1;
|
|
||||||
unsigned int expecting_child : 1;
|
|
||||||
int (*handle_trace) (debugger_state *, pid_t);
|
|
||||||
|
|
||||||
debugee_state *debugee;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct debugee
|
|
||||||
{
|
|
||||||
pid_t pid;
|
|
||||||
int wait_status;
|
|
||||||
unsigned int died : 1;
|
|
||||||
unsigned int event : 1;
|
|
||||||
unsigned int stopped : 1;
|
|
||||||
unsigned int trace_singlestep : 1;
|
|
||||||
unsigned int trace_syscall : 1;
|
|
||||||
unsigned int traced : 1;
|
|
||||||
unsigned int zombie : 1;
|
|
||||||
unsigned int in_context : 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern int debugger_syscall(debugger_state *debugger, pid_t pid);
|
|
||||||
extern int debugger_normal_return (debugger_state *debugger, pid_t unused);
|
|
||||||
|
|
||||||
extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t,
|
|
||||||
int *strace_out);
|
|
||||||
extern void debugger_cancelled_return(debugger_state *debugger, int result);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,237 +0,0 @@
|
|||||||
/**********************************************************************
|
|
||||||
ptrace.c
|
|
||||||
|
|
||||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
|
||||||
terms and conditions.
|
|
||||||
|
|
||||||
Jeff Dike (jdike@karaya.com) : Modified for integration into uml
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
#include "ptproxy.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "kern_util.h"
|
|
||||||
#include "ptrace_user.h"
|
|
||||||
#include "tt.h"
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
|
|
||||||
long arg3, long arg4, pid_t child, int *ret)
|
|
||||||
{
|
|
||||||
sigset_t relay;
|
|
||||||
long result;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
*ret = 0;
|
|
||||||
if(debugger->debugee->died) return(-ESRCH);
|
|
||||||
|
|
||||||
switch(arg1){
|
|
||||||
case PTRACE_ATTACH:
|
|
||||||
if(debugger->debugee->traced) return(-EPERM);
|
|
||||||
|
|
||||||
debugger->debugee->pid = arg2;
|
|
||||||
debugger->debugee->traced = 1;
|
|
||||||
|
|
||||||
if(is_valid_pid(arg2) && (arg2 != child)){
|
|
||||||
debugger->debugee->in_context = 0;
|
|
||||||
kill(arg2, SIGSTOP);
|
|
||||||
debugger->debugee->event = 1;
|
|
||||||
debugger->debugee->wait_status = W_STOPCODE(SIGSTOP);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
debugger->debugee->in_context = 1;
|
|
||||||
if(debugger->debugee->stopped)
|
|
||||||
child_proxy(child, W_STOPCODE(SIGSTOP));
|
|
||||||
else kill(child, SIGSTOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
|
|
||||||
case PTRACE_DETACH:
|
|
||||||
if(!debugger->debugee->traced) return(-EPERM);
|
|
||||||
|
|
||||||
debugger->debugee->traced = 0;
|
|
||||||
debugger->debugee->pid = 0;
|
|
||||||
if(!debugger->debugee->in_context)
|
|
||||||
kill(child, SIGCONT);
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
|
|
||||||
case PTRACE_CONT:
|
|
||||||
if(!debugger->debugee->in_context) return(-EPERM);
|
|
||||||
*ret = PTRACE_CONT;
|
|
||||||
return(ptrace(PTRACE_CONT, child, arg3, arg4));
|
|
||||||
|
|
||||||
#ifdef UM_HAVE_GETFPREGS
|
|
||||||
case PTRACE_GETFPREGS:
|
|
||||||
{
|
|
||||||
long regs[FP_FRAME_SIZE];
|
|
||||||
int i, result;
|
|
||||||
|
|
||||||
result = ptrace(PTRACE_GETFPREGS, child, 0, regs);
|
|
||||||
if(result == -1) return(-errno);
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
|
||||||
ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
|
|
||||||
regs[i]);
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UM_HAVE_GETFPXREGS
|
|
||||||
case PTRACE_GETFPXREGS:
|
|
||||||
{
|
|
||||||
long regs[FPX_FRAME_SIZE];
|
|
||||||
int i, result;
|
|
||||||
|
|
||||||
result = ptrace(PTRACE_GETFPXREGS, child, 0, regs);
|
|
||||||
if(result == -1) return(-errno);
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
|
||||||
ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
|
|
||||||
regs[i]);
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UM_HAVE_GETREGS
|
|
||||||
case PTRACE_GETREGS:
|
|
||||||
{
|
|
||||||
long regs[FRAME_SIZE];
|
|
||||||
int i, result;
|
|
||||||
|
|
||||||
result = ptrace(PTRACE_GETREGS, child, 0, regs);
|
|
||||||
if(result == -1) return(-errno);
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
|
||||||
ptrace (PTRACE_POKEDATA, debugger->pid,
|
|
||||||
arg4 + 4 * i, regs[i]);
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case PTRACE_KILL:
|
|
||||||
result = ptrace(PTRACE_KILL, child, arg3, arg4);
|
|
||||||
if(result == -1) return(-errno);
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
|
|
||||||
case PTRACE_PEEKDATA:
|
|
||||||
case PTRACE_PEEKTEXT:
|
|
||||||
case PTRACE_PEEKUSR:
|
|
||||||
/* The value being read out could be -1, so we have to
|
|
||||||
* check errno to see if there's an error, and zero it
|
|
||||||
* beforehand so we're not faked out by an old error
|
|
||||||
*/
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
result = ptrace(arg1, child, arg3, 0);
|
|
||||||
if((result == -1) && (errno != 0)) return(-errno);
|
|
||||||
|
|
||||||
result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result);
|
|
||||||
if(result == -1) return(-errno);
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
|
|
||||||
case PTRACE_POKEDATA:
|
|
||||||
case PTRACE_POKETEXT:
|
|
||||||
case PTRACE_POKEUSR:
|
|
||||||
result = ptrace(arg1, child, arg3, arg4);
|
|
||||||
if(result == -1) return(-errno);
|
|
||||||
|
|
||||||
if(arg1 == PTRACE_POKEUSR) ptrace_pokeuser(arg3, arg4);
|
|
||||||
return(result);
|
|
||||||
|
|
||||||
#ifdef UM_HAVE_SETFPREGS
|
|
||||||
case PTRACE_SETFPREGS:
|
|
||||||
{
|
|
||||||
long regs[FP_FRAME_SIZE];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
|
||||||
regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
|
|
||||||
arg4 + 4 * i, 0);
|
|
||||||
result = ptrace(PTRACE_SETFPREGS, child, 0, regs);
|
|
||||||
if(result == -1) return(-errno);
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UM_HAVE_SETFPXREGS
|
|
||||||
case PTRACE_SETFPXREGS:
|
|
||||||
{
|
|
||||||
long regs[FPX_FRAME_SIZE];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
|
||||||
regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
|
|
||||||
arg4 + 4 * i, 0);
|
|
||||||
result = ptrace(PTRACE_SETFPXREGS, child, 0, regs);
|
|
||||||
if(result == -1) return(-errno);
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UM_HAVE_SETREGS
|
|
||||||
case PTRACE_SETREGS:
|
|
||||||
{
|
|
||||||
long regs[FRAME_SIZE];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
|
||||||
regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid,
|
|
||||||
arg4 + 4 * i, 0);
|
|
||||||
result = ptrace(PTRACE_SETREGS, child, 0, regs);
|
|
||||||
if(result == -1) return(-errno);
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case PTRACE_SINGLESTEP:
|
|
||||||
if(!debugger->debugee->in_context) return(-EPERM);
|
|
||||||
sigemptyset(&relay);
|
|
||||||
sigaddset(&relay, SIGSEGV);
|
|
||||||
sigaddset(&relay, SIGILL);
|
|
||||||
sigaddset(&relay, SIGBUS);
|
|
||||||
result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4);
|
|
||||||
if(result == -1) return(-errno);
|
|
||||||
|
|
||||||
status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP,
|
|
||||||
&relay);
|
|
||||||
child_proxy(child, status);
|
|
||||||
return(result);
|
|
||||||
|
|
||||||
case PTRACE_SYSCALL:
|
|
||||||
if(!debugger->debugee->in_context) return(-EPERM);
|
|
||||||
result = ptrace(PTRACE_SYSCALL, child, arg3, arg4);
|
|
||||||
if(result == -1) return(-errno);
|
|
||||||
|
|
||||||
*ret = PTRACE_SYSCALL;
|
|
||||||
return(result);
|
|
||||||
|
|
||||||
case PTRACE_TRACEME:
|
|
||||||
default:
|
|
||||||
return(-EINVAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,70 +0,0 @@
|
|||||||
/**********************************************************************
|
|
||||||
sysdep.c
|
|
||||||
|
|
||||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
|
||||||
terms and conditions.
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <linux/unistd.h>
|
|
||||||
#include "ptrace_user.h"
|
|
||||||
#include "user.h"
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4,
|
|
||||||
long *arg5)
|
|
||||||
{
|
|
||||||
*arg1 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG1_OFFSET, 0);
|
|
||||||
*arg2 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG2_OFFSET, 0);
|
|
||||||
*arg3 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG3_OFFSET, 0);
|
|
||||||
*arg4 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG4_OFFSET, 0);
|
|
||||||
*arg5 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG5_OFFSET, 0);
|
|
||||||
return(ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void syscall_cancel(pid_t pid, int result)
|
|
||||||
{
|
|
||||||
if((ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
|
|
||||||
__NR_getpid) < 0) ||
|
|
||||||
(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ||
|
|
||||||
(wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) ||
|
|
||||||
(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result) < 0) ||
|
|
||||||
(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0))
|
|
||||||
printk("ptproxy: couldn't cancel syscall: errno = %d\n",
|
|
||||||
errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
void syscall_set_result(pid_t pid, long result)
|
|
||||||
{
|
|
||||||
ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void syscall_continue(pid_t pid)
|
|
||||||
{
|
|
||||||
ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int syscall_pause(pid_t pid)
|
|
||||||
{
|
|
||||||
if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){
|
|
||||||
printk("syscall_change - ptrace failed, errno = %d\n", errno);
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,25 +0,0 @@
|
|||||||
/**********************************************************************
|
|
||||||
sysdep.h
|
|
||||||
|
|
||||||
Copyright (C) 1999 Lars Brinkhoff.
|
|
||||||
Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
|
|
||||||
See the file COPYING for licensing terms and conditions.
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3,
|
|
||||||
long *arg4, long *arg5);
|
|
||||||
extern void syscall_cancel (pid_t pid, long result);
|
|
||||||
extern void syscall_set_result (pid_t pid, long result);
|
|
||||||
extern void syscall_continue (pid_t pid);
|
|
||||||
extern int syscall_pause(pid_t pid);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,85 +0,0 @@
|
|||||||
/**********************************************************************
|
|
||||||
wait.c
|
|
||||||
|
|
||||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
|
||||||
terms and conditions.
|
|
||||||
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
#include "ptproxy.h"
|
|
||||||
#include "sysdep.h"
|
|
||||||
#include "wait.h"
|
|
||||||
#include "ptrace_user.h"
|
|
||||||
#include "sysdep/ptrace.h"
|
|
||||||
#include "sysdep/sigcontext.h"
|
|
||||||
|
|
||||||
int proxy_wait_return(struct debugger *debugger, pid_t unused)
|
|
||||||
{
|
|
||||||
debugger->waiting = 0;
|
|
||||||
|
|
||||||
if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){
|
|
||||||
debugger_cancelled_return(debugger, -ECHILD);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(debugger->debugee->zombie && debugger->debugee->event)
|
|
||||||
debugger->debugee->died = 1;
|
|
||||||
|
|
||||||
if(debugger->debugee->event){
|
|
||||||
debugger->debugee->event = 0;
|
|
||||||
ptrace(PTRACE_POKEDATA, debugger->pid,
|
|
||||||
debugger->wait_status_ptr,
|
|
||||||
debugger->debugee->wait_status);
|
|
||||||
/* if (wait4)
|
|
||||||
ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */
|
|
||||||
debugger_cancelled_return(debugger, debugger->debugee->pid);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pause will return -EINTR, which happens to be right for wait */
|
|
||||||
debugger_normal_return(debugger, -1);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int parent_wait_return(struct debugger *debugger, pid_t unused)
|
|
||||||
{
|
|
||||||
return(debugger_normal_return(debugger, -1));
|
|
||||||
}
|
|
||||||
|
|
||||||
int real_wait_return(struct debugger *debugger)
|
|
||||||
{
|
|
||||||
unsigned long ip;
|
|
||||||
int pid;
|
|
||||||
|
|
||||||
pid = debugger->pid;
|
|
||||||
|
|
||||||
ip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
|
|
||||||
IP_RESTART_SYSCALL(ip);
|
|
||||||
|
|
||||||
if(ptrace(PTRACE_POKEUSR, pid, PT_IP_OFFSET, ip) < 0)
|
|
||||||
tracer_panic("real_wait_return : Failed to restart system "
|
|
||||||
"call, errno = %d\n", errno);
|
|
||||||
|
|
||||||
if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) ||
|
|
||||||
(ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
|
|
||||||
(ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
|
|
||||||
debugger_normal_return(debugger, -1))
|
|
||||||
tracer_panic("real_wait_return : gdb failed to wait, "
|
|
||||||
"errno = %d\n", errno);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,15 +0,0 @@
|
|||||||
/**********************************************************************
|
|
||||||
wait.h
|
|
||||||
|
|
||||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
|
||||||
terms and conditions.
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
#ifndef __PTPROXY_WAIT_H
|
|
||||||
#define __PTPROXY_WAIT_H
|
|
||||||
|
|
||||||
extern int proxy_wait_return(struct debugger *debugger, pid_t unused);
|
|
||||||
extern int real_wait_return(struct debugger *debugger);
|
|
||||||
extern int parent_wait_return(struct debugger *debugger, pid_t unused);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "linux/types.h"
|
|
||||||
#include "linux/utime.h"
|
|
||||||
#include "linux/sys.h"
|
|
||||||
#include "linux/ptrace.h"
|
|
||||||
#include "asm/unistd.h"
|
|
||||||
#include "asm/ptrace.h"
|
|
||||||
#include "asm/uaccess.h"
|
|
||||||
#include "asm/stat.h"
|
|
||||||
#include "sysdep/syscalls.h"
|
|
||||||
#include "sysdep/sigcontext.h"
|
|
||||||
#include "kern_util.h"
|
|
||||||
#include "syscall.h"
|
|
||||||
|
|
||||||
void syscall_handler_tt(int sig, struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
void *sc;
|
|
||||||
long result;
|
|
||||||
int syscall;
|
|
||||||
|
|
||||||
sc = UPT_SC(®s->regs);
|
|
||||||
SC_START_SYSCALL(sc);
|
|
||||||
|
|
||||||
syscall = UPT_SYSCALL_NR(®s->regs);
|
|
||||||
syscall_trace(®s->regs, 0);
|
|
||||||
|
|
||||||
current->thread.nsyscalls++;
|
|
||||||
nsyscalls++;
|
|
||||||
|
|
||||||
if((syscall >= NR_syscalls) || (syscall < 0))
|
|
||||||
result = -ENOSYS;
|
|
||||||
else result = EXECUTE_SYSCALL(syscall, regs);
|
|
||||||
|
|
||||||
/* regs->sc may have changed while the system call ran (there may
|
|
||||||
* have been an interrupt or segfault), so it needs to be refreshed.
|
|
||||||
*/
|
|
||||||
UPT_SC(®s->regs) = sc;
|
|
||||||
|
|
||||||
SC_SET_SYSCALL_RETURN(sc, result);
|
|
||||||
|
|
||||||
syscall_trace(®s->regs, 1);
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <asm/unistd.h>
|
|
||||||
#include "sysdep/ptrace.h"
|
|
||||||
#include "sigcontext.h"
|
|
||||||
#include "ptrace_user.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "kern_util.h"
|
|
||||||
#include "syscall.h"
|
|
||||||
#include "tt.h"
|
|
||||||
|
|
||||||
void do_sigtrap(void *task)
|
|
||||||
{
|
|
||||||
UPT_SYSCALL_NR(TASK_REGS(task)) = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_syscall(void *task, int pid, int local_using_sysemu)
|
|
||||||
{
|
|
||||||
unsigned long proc_regs[FRAME_SIZE];
|
|
||||||
|
|
||||||
if(ptrace_getregs(pid, proc_regs) < 0)
|
|
||||||
tracer_panic("Couldn't read registers");
|
|
||||||
|
|
||||||
UPT_SYSCALL_NR(TASK_REGS(task)) = PT_SYSCALL_NR(proc_regs);
|
|
||||||
|
|
||||||
#ifdef UPT_ORIGGPR2
|
|
||||||
UPT_ORIGGPR2(TASK_REGS(task)) = REGS_ORIGGPR2(proc_regs);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(((unsigned long *) PT_IP(proc_regs) >= &_stext) &&
|
|
||||||
((unsigned long *) PT_IP(proc_regs) <= &_etext))
|
|
||||||
tracer_panic("I'm tracing myself and I can't get out");
|
|
||||||
|
|
||||||
/* advanced sysemu mode set syscall number to -1 automatically */
|
|
||||||
if (local_using_sysemu==2)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* syscall number -1 in sysemu skips syscall restarting in host */
|
|
||||||
if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
|
|
||||||
local_using_sysemu ? -1 : __NR_getpid) < 0)
|
|
||||||
tracer_panic("do_syscall : Nullifying syscall failed, "
|
|
||||||
"errno = %d", errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,120 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Copyright 2003 PathScale, Inc.
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "linux/stddef.h"
|
|
||||||
#include "linux/kernel.h"
|
|
||||||
#include "linux/sched.h"
|
|
||||||
#include "linux/mm.h"
|
|
||||||
#include "asm/page.h"
|
|
||||||
#include "asm/pgtable.h"
|
|
||||||
#include "asm/uaccess.h"
|
|
||||||
#include "asm/tlbflush.h"
|
|
||||||
#include "mem_user.h"
|
|
||||||
#include "os.h"
|
|
||||||
#include "tlb.h"
|
|
||||||
|
|
||||||
static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last,
|
|
||||||
int finished, void **flush)
|
|
||||||
{
|
|
||||||
struct host_vm_op *op;
|
|
||||||
int i, ret=0;
|
|
||||||
|
|
||||||
for(i = 0; i <= last && !ret; i++){
|
|
||||||
op = &ops[i];
|
|
||||||
switch(op->type){
|
|
||||||
case MMAP:
|
|
||||||
ret = os_map_memory((void *) op->u.mmap.addr,
|
|
||||||
op->u.mmap.fd, op->u.mmap.offset,
|
|
||||||
op->u.mmap.len, op->u.mmap.r,
|
|
||||||
op->u.mmap.w, op->u.mmap.x);
|
|
||||||
break;
|
|
||||||
case MUNMAP:
|
|
||||||
ret = os_unmap_memory((void *) op->u.munmap.addr,
|
|
||||||
op->u.munmap.len);
|
|
||||||
break;
|
|
||||||
case MPROTECT:
|
|
||||||
ret = protect_memory(op->u.mprotect.addr,
|
|
||||||
op->u.munmap.len,
|
|
||||||
op->u.mprotect.r,
|
|
||||||
op->u.mprotect.w,
|
|
||||||
op->u.mprotect.x, 1);
|
|
||||||
protect_memory(op->u.mprotect.addr, op->u.munmap.len,
|
|
||||||
op->u.mprotect.r, op->u.mprotect.w,
|
|
||||||
op->u.mprotect.x, 1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printk("Unknown op type %d in do_ops\n", op->type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fix_range(struct mm_struct *mm, unsigned long start_addr,
|
|
||||||
unsigned long end_addr, int force)
|
|
||||||
{
|
|
||||||
if((current->thread.mode.tt.extern_pid != -1) &&
|
|
||||||
(current->thread.mode.tt.extern_pid != os_getpid()))
|
|
||||||
panic("fix_range fixing wrong address space, current = 0x%p",
|
|
||||||
current);
|
|
||||||
|
|
||||||
fix_range_common(mm, start_addr, end_addr, force, do_ops);
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic_t vmchange_seq = ATOMIC_INIT(1);
|
|
||||||
|
|
||||||
void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end)
|
|
||||||
{
|
|
||||||
if(flush_tlb_kernel_range_common(start, end))
|
|
||||||
atomic_inc(&vmchange_seq);
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush_tlb_kernel_vm_tt(void)
|
|
||||||
{
|
|
||||||
flush_tlb_kernel_range(start_vm, end_vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __flush_tlb_one_tt(unsigned long addr)
|
|
||||||
{
|
|
||||||
flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start,
|
|
||||||
unsigned long end)
|
|
||||||
{
|
|
||||||
if(vma->vm_mm != current->mm) return;
|
|
||||||
|
|
||||||
/* Assumes that the range start ... end is entirely within
|
|
||||||
* either process memory or kernel vm
|
|
||||||
*/
|
|
||||||
if((start >= start_vm) && (start < end_vm)){
|
|
||||||
if(flush_tlb_kernel_range_common(start, end))
|
|
||||||
atomic_inc(&vmchange_seq);
|
|
||||||
}
|
|
||||||
else fix_range(vma->vm_mm, start, end, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush_tlb_mm_tt(struct mm_struct *mm)
|
|
||||||
{
|
|
||||||
unsigned long seq;
|
|
||||||
|
|
||||||
if(mm != current->mm) return;
|
|
||||||
|
|
||||||
fix_range(mm, 0, STACK_TOP, 0);
|
|
||||||
|
|
||||||
seq = atomic_read(&vmchange_seq);
|
|
||||||
if(current->thread.mode.tt.vm_seq == seq)
|
|
||||||
return;
|
|
||||||
current->thread.mode.tt.vm_seq = seq;
|
|
||||||
flush_tlb_kernel_range_common(start_vm, end_vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
void force_flush_all_tt(void)
|
|
||||||
{
|
|
||||||
fix_range(current->mm, 0, STACK_TOP, 1);
|
|
||||||
flush_tlb_kernel_range_common(start_vm, end_vm);
|
|
||||||
}
|
|
@ -1,461 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sched.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include "user.h"
|
|
||||||
#include "sysdep/ptrace.h"
|
|
||||||
#include "sigcontext.h"
|
|
||||||
#include "sysdep/sigcontext.h"
|
|
||||||
#include "os.h"
|
|
||||||
#include "mem_user.h"
|
|
||||||
#include "process.h"
|
|
||||||
#include "kern_util.h"
|
|
||||||
#include "chan_user.h"
|
|
||||||
#include "ptrace_user.h"
|
|
||||||
#include "irq_user.h"
|
|
||||||
#include "mode.h"
|
|
||||||
#include "tt.h"
|
|
||||||
|
|
||||||
static int tracer_winch[2];
|
|
||||||
|
|
||||||
int is_tracer_winch(int pid, int fd, void *data)
|
|
||||||
{
|
|
||||||
if(pid != os_getpgrp())
|
|
||||||
return(0);
|
|
||||||
|
|
||||||
register_winch_irq(tracer_winch[0], fd, -1, data);
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tracer_winch_handler(int sig)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
char c = 1;
|
|
||||||
|
|
||||||
n = os_write_file(tracer_winch[1], &c, sizeof(c));
|
|
||||||
if(n != sizeof(c))
|
|
||||||
printk("tracer_winch_handler - write failed, err = %d\n", -n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Called only by the tracing thread during initialization */
|
|
||||||
|
|
||||||
static void setup_tracer_winch(void)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = os_pipe(tracer_winch, 1, 1);
|
|
||||||
if(err < 0){
|
|
||||||
printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
signal(SIGWINCH, tracer_winch_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void attach_process(int pid)
|
|
||||||
{
|
|
||||||
if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
|
|
||||||
(ptrace(PTRACE_CONT, pid, 0, 0) < 0))
|
|
||||||
tracer_panic("OP_FORK failed to attach pid");
|
|
||||||
wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
|
|
||||||
if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
|
|
||||||
tracer_panic("OP_FORK: PTRACE_SETOPTIONS failed, errno = %d", errno);
|
|
||||||
if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
|
|
||||||
tracer_panic("OP_FORK failed to continue process");
|
|
||||||
}
|
|
||||||
|
|
||||||
void tracer_panic(char *format, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, format);
|
|
||||||
vprintf(format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
printf("\n");
|
|
||||||
while(1) pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tracer_segv(int sig, struct sigcontext sc)
|
|
||||||
{
|
|
||||||
struct faultinfo fi;
|
|
||||||
GET_FAULTINFO_FROM_SC(fi, &sc);
|
|
||||||
printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
|
|
||||||
FAULT_ADDRESS(fi), SC_IP(&sc));
|
|
||||||
while(1)
|
|
||||||
pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Changed early in boot, and then only read */
|
|
||||||
int debug = 0;
|
|
||||||
int debug_stop = 1;
|
|
||||||
int debug_parent = 0;
|
|
||||||
int honeypot = 0;
|
|
||||||
|
|
||||||
static int signal_tramp(void *arg)
|
|
||||||
{
|
|
||||||
int (*proc)(void *);
|
|
||||||
|
|
||||||
if(honeypot && munmap((void *) (host_task_size - 0x10000000),
|
|
||||||
0x10000000))
|
|
||||||
panic("Unmapping stack failed");
|
|
||||||
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
|
|
||||||
panic("ptrace PTRACE_TRACEME failed");
|
|
||||||
os_stop_process(os_getpid());
|
|
||||||
change_sig(SIGWINCH, 0);
|
|
||||||
signal(SIGUSR1, SIG_IGN);
|
|
||||||
change_sig(SIGCHLD, 0);
|
|
||||||
signal(SIGSEGV, (__sighandler_t) sig_handler);
|
|
||||||
set_cmdline("(idle thread)");
|
|
||||||
set_init_pid(os_getpid());
|
|
||||||
init_irq_signals(0);
|
|
||||||
proc = arg;
|
|
||||||
return((*proc)(NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sleeping_process_signal(int pid, int sig)
|
|
||||||
{
|
|
||||||
switch(sig){
|
|
||||||
/* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is
|
|
||||||
* right because the process must be in the kernel already.
|
|
||||||
*/
|
|
||||||
case SIGCONT:
|
|
||||||
case SIGTSTP:
|
|
||||||
if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
|
|
||||||
tracer_panic("sleeping_process_signal : Failed to "
|
|
||||||
"continue pid %d, signal = %d, "
|
|
||||||
"errno = %d\n", pid, sig, errno);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* This happens when the debugger (e.g. strace) is doing system call
|
|
||||||
* tracing on the kernel. During a context switch, the current task
|
|
||||||
* will be set to the incoming process and the outgoing process will
|
|
||||||
* hop into write and then read. Since it's not the current process
|
|
||||||
* any more, the trace of those will land here. So, we need to just
|
|
||||||
* PTRACE_SYSCALL it.
|
|
||||||
*/
|
|
||||||
case (SIGTRAP + 0x80):
|
|
||||||
if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
|
|
||||||
tracer_panic("sleeping_process_signal : Failed to "
|
|
||||||
"PTRACE_SYSCALL pid %d, errno = %d\n",
|
|
||||||
pid, errno);
|
|
||||||
break;
|
|
||||||
case SIGSTOP:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
tracer_panic("sleeping process %d got unexpected "
|
|
||||||
"signal : %d\n", pid, sig);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Accessed only by the tracing thread */
|
|
||||||
int debugger_pid = -1;
|
|
||||||
int debugger_parent = -1;
|
|
||||||
int debugger_fd = -1;
|
|
||||||
int gdb_pid = -1;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int pid;
|
|
||||||
int signal;
|
|
||||||
unsigned long addr;
|
|
||||||
struct timeval time;
|
|
||||||
} signal_record[1024][32];
|
|
||||||
|
|
||||||
int signal_index[32];
|
|
||||||
int nsignals = 0;
|
|
||||||
int debug_trace = 0;
|
|
||||||
|
|
||||||
extern void signal_usr1(int sig);
|
|
||||||
|
|
||||||
int tracing_pid = -1;
|
|
||||||
|
|
||||||
int tracer(int (*init_proc)(void *), void *sp)
|
|
||||||
{
|
|
||||||
void *task = NULL;
|
|
||||||
int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
|
|
||||||
int proc_id = 0, n, err, old_tracing = 0, strace = 0;
|
|
||||||
int local_using_sysemu = 0;
|
|
||||||
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
|
||||||
setup_tracer_winch();
|
|
||||||
tracing_pid = os_getpid();
|
|
||||||
printf("tracing thread pid = %d\n", tracing_pid);
|
|
||||||
|
|
||||||
pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
|
|
||||||
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
|
|
||||||
if(n < 0){
|
|
||||||
printf("waitpid on idle thread failed, errno = %d\n", errno);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) {
|
|
||||||
printf("Failed to PTRACE_SETOPTIONS for idle thread, errno = %d\n", errno);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
|
|
||||||
printf("Failed to continue idle thread, errno = %d\n", errno);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
signal(SIGSEGV, (sighandler_t) tracer_segv);
|
|
||||||
signal(SIGUSR1, signal_usr1);
|
|
||||||
if(debug_trace){
|
|
||||||
printf("Tracing thread pausing to be attached\n");
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
if(debug){
|
|
||||||
if(gdb_pid != -1)
|
|
||||||
debugger_pid = attach_debugger(pid, gdb_pid, 1);
|
|
||||||
else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
|
|
||||||
if(debug_parent){
|
|
||||||
debugger_parent = os_process_parent(debugger_pid);
|
|
||||||
init_parent_proxy(debugger_parent);
|
|
||||||
err = attach(debugger_parent);
|
|
||||||
if(err){
|
|
||||||
printf("Failed to attach debugger parent %d, "
|
|
||||||
"errno = %d\n", debugger_parent, -err);
|
|
||||||
debugger_parent = -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(ptrace(PTRACE_SYSCALL, debugger_parent,
|
|
||||||
0, 0) < 0){
|
|
||||||
printf("Failed to continue debugger "
|
|
||||||
"parent, errno = %d\n", errno);
|
|
||||||
debugger_parent = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set_cmdline("(tracing thread)");
|
|
||||||
while(1){
|
|
||||||
CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
|
|
||||||
if(pid <= 0){
|
|
||||||
if(errno != ECHILD){
|
|
||||||
printf("wait failed - errno = %d\n", errno);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(pid == debugger_pid){
|
|
||||||
int cont = 0;
|
|
||||||
|
|
||||||
if(WIFEXITED(status) || WIFSIGNALED(status))
|
|
||||||
debugger_pid = -1;
|
|
||||||
/* XXX Figure out how to deal with gdb and SMP */
|
|
||||||
else cont = debugger_signal(status, cpu_tasks[0].pid);
|
|
||||||
if(cont == PTRACE_SYSCALL) strace = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if(pid == debugger_parent){
|
|
||||||
debugger_parent_signal(status, pid);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
nsignals++;
|
|
||||||
if(WIFEXITED(status)) ;
|
|
||||||
#ifdef notdef
|
|
||||||
{
|
|
||||||
printf("Child %d exited with status %d\n", pid,
|
|
||||||
WEXITSTATUS(status));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else if(WIFSIGNALED(status)){
|
|
||||||
sig = WTERMSIG(status);
|
|
||||||
if(sig != 9){
|
|
||||||
printf("Child %d exited with signal %d\n", pid,
|
|
||||||
sig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(WIFSTOPPED(status)){
|
|
||||||
proc_id = pid_to_processor_id(pid);
|
|
||||||
sig = WSTOPSIG(status);
|
|
||||||
if(proc_id == -1){
|
|
||||||
sleeping_process_signal(pid, sig);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
task = cpu_tasks[proc_id].task;
|
|
||||||
tracing = is_tracing(task);
|
|
||||||
old_tracing = tracing;
|
|
||||||
|
|
||||||
/* Assume: no syscall, when coming from user */
|
|
||||||
if ( tracing )
|
|
||||||
do_sigtrap(task);
|
|
||||||
|
|
||||||
switch(sig){
|
|
||||||
case SIGUSR1:
|
|
||||||
sig = 0;
|
|
||||||
op = do_proc_op(task, proc_id);
|
|
||||||
switch(op){
|
|
||||||
/*
|
|
||||||
* This is called when entering user mode; after
|
|
||||||
* this, we start intercepting syscalls.
|
|
||||||
*
|
|
||||||
* In fact, a process is started in kernel mode,
|
|
||||||
* so with is_tracing() == 0 (and that is reset
|
|
||||||
* when executing syscalls, since UML kernel has
|
|
||||||
* the right to do syscalls);
|
|
||||||
*/
|
|
||||||
case OP_TRACE_ON:
|
|
||||||
arch_leave_kernel(task, pid);
|
|
||||||
tracing = 1;
|
|
||||||
break;
|
|
||||||
case OP_REBOOT:
|
|
||||||
case OP_HALT:
|
|
||||||
unmap_physmem();
|
|
||||||
kmalloc_ok = 0;
|
|
||||||
os_kill_ptraced_process(pid, 0);
|
|
||||||
/* Now let's reap remaining zombies */
|
|
||||||
errno = 0;
|
|
||||||
do {
|
|
||||||
waitpid(-1, &status,
|
|
||||||
WUNTRACED);
|
|
||||||
} while (errno != ECHILD);
|
|
||||||
return(op == OP_REBOOT);
|
|
||||||
case OP_NONE:
|
|
||||||
printf("Detaching pid %d\n", pid);
|
|
||||||
detach(pid, SIGSTOP);
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* OP_EXEC switches host processes on us,
|
|
||||||
* we want to continue the new one.
|
|
||||||
*/
|
|
||||||
pid = cpu_tasks[proc_id].pid;
|
|
||||||
break;
|
|
||||||
case (SIGTRAP + 0x80):
|
|
||||||
if(!tracing && (debugger_pid != -1)){
|
|
||||||
child_signal(pid, status & 0x7fff);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
tracing = 0;
|
|
||||||
/* local_using_sysemu has been already set
|
|
||||||
* below, since if we are here, is_tracing() on
|
|
||||||
* the traced task was 1, i.e. the process had
|
|
||||||
* already run through one iteration of the
|
|
||||||
* loop which executed a OP_TRACE_ON request.*/
|
|
||||||
do_syscall(task, pid, local_using_sysemu);
|
|
||||||
sig = SIGUSR2;
|
|
||||||
break;
|
|
||||||
case SIGTRAP:
|
|
||||||
if(!tracing && (debugger_pid != -1)){
|
|
||||||
child_signal(pid, status);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
tracing = 0;
|
|
||||||
break;
|
|
||||||
case SIGPROF:
|
|
||||||
if(tracing) sig = 0;
|
|
||||||
break;
|
|
||||||
case SIGCHLD:
|
|
||||||
case SIGHUP:
|
|
||||||
sig = 0;
|
|
||||||
break;
|
|
||||||
case SIGSEGV:
|
|
||||||
case SIGIO:
|
|
||||||
case SIGALRM:
|
|
||||||
case SIGVTALRM:
|
|
||||||
case SIGFPE:
|
|
||||||
case SIGBUS:
|
|
||||||
case SIGILL:
|
|
||||||
case SIGWINCH:
|
|
||||||
|
|
||||||
default:
|
|
||||||
tracing = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
set_tracing(task, tracing);
|
|
||||||
|
|
||||||
if(!tracing && old_tracing)
|
|
||||||
arch_enter_kernel(task, pid);
|
|
||||||
|
|
||||||
if(!tracing && (debugger_pid != -1) && (sig != 0) &&
|
|
||||||
(sig != SIGALRM) && (sig != SIGVTALRM) &&
|
|
||||||
(sig != SIGSEGV) && (sig != SIGTRAP) &&
|
|
||||||
(sig != SIGUSR2) && (sig != SIGIO) &&
|
|
||||||
(sig != SIGFPE)){
|
|
||||||
child_signal(pid, status);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
local_using_sysemu = get_using_sysemu();
|
|
||||||
|
|
||||||
if(tracing)
|
|
||||||
cont_type = SELECT_PTRACE_OPERATION(local_using_sysemu,
|
|
||||||
singlestepping(task));
|
|
||||||
else if((debugger_pid != -1) && strace)
|
|
||||||
cont_type = PTRACE_SYSCALL;
|
|
||||||
else
|
|
||||||
cont_type = PTRACE_CONT;
|
|
||||||
|
|
||||||
if(ptrace(cont_type, pid, 0, sig) != 0){
|
|
||||||
tracer_panic("ptrace failed to continue "
|
|
||||||
"process - errno = %d\n",
|
|
||||||
errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init uml_debug_setup(char *line, int *add)
|
|
||||||
{
|
|
||||||
char *next;
|
|
||||||
|
|
||||||
debug = 1;
|
|
||||||
*add = 0;
|
|
||||||
if(*line != '=') return(0);
|
|
||||||
line++;
|
|
||||||
|
|
||||||
while(line != NULL){
|
|
||||||
next = strchr(line, ',');
|
|
||||||
if(next) *next++ = '\0';
|
|
||||||
|
|
||||||
if(!strcmp(line, "go")) debug_stop = 0;
|
|
||||||
else if(!strcmp(line, "parent")) debug_parent = 1;
|
|
||||||
else printf("Unknown debug option : '%s'\n", line);
|
|
||||||
|
|
||||||
line = next;
|
|
||||||
}
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
__uml_setup("debug", uml_debug_setup,
|
|
||||||
"debug\n"
|
|
||||||
" Starts up the kernel under the control of gdb. See the \n"
|
|
||||||
" kernel debugging tutorial and the debugging session pages\n"
|
|
||||||
" at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
static int __init uml_debugtrace_setup(char *line, int *add)
|
|
||||||
{
|
|
||||||
debug_trace = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
__uml_setup("debugtrace", uml_debugtrace_setup,
|
|
||||||
"debugtrace\n"
|
|
||||||
" Causes the tracing thread to pause until it is attached by a\n"
|
|
||||||
" debugger and continued. This is mostly for debugging crashes\n"
|
|
||||||
" early during boot, and should be pretty much obsoleted by\n"
|
|
||||||
" the debug switch.\n\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include "sysdep/ptrace.h"
|
|
||||||
#include "sysdep/sigcontext.h"
|
|
||||||
#include "kern_util.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "tt.h"
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
void sig_handler_common_tt(int sig, void *sc_ptr)
|
|
||||||
{
|
|
||||||
struct sigcontext *sc = sc_ptr;
|
|
||||||
struct tt_regs save_regs, *r;
|
|
||||||
int save_errno = errno, is_user = 0;
|
|
||||||
void (*handler)(int, union uml_pt_regs *);
|
|
||||||
|
|
||||||
/* This is done because to allow SIGSEGV to be delivered inside a SEGV
|
|
||||||
* handler. This can happen in copy_user, and if SEGV is disabled,
|
|
||||||
* the process will die.
|
|
||||||
*/
|
|
||||||
if(sig == SIGSEGV)
|
|
||||||
change_sig(SIGSEGV, 1);
|
|
||||||
|
|
||||||
r = &TASK_REGS(get_current())->tt;
|
|
||||||
if ( sig == SIGFPE || sig == SIGSEGV ||
|
|
||||||
sig == SIGBUS || sig == SIGILL ||
|
|
||||||
sig == SIGTRAP ) {
|
|
||||||
GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
|
|
||||||
}
|
|
||||||
save_regs = *r;
|
|
||||||
if (sc)
|
|
||||||
is_user = user_context(SC_SP(sc));
|
|
||||||
r->sc = sc;
|
|
||||||
if(sig != SIGUSR2)
|
|
||||||
r->syscall = -1;
|
|
||||||
|
|
||||||
handler = sig_info[sig];
|
|
||||||
|
|
||||||
/* unblock SIGALRM, SIGVTALRM, SIGIO if sig isn't IRQ signal */
|
|
||||||
if (sig != SIGIO && sig != SIGWINCH &&
|
|
||||||
sig != SIGVTALRM && sig != SIGALRM)
|
|
||||||
unblock_signals();
|
|
||||||
|
|
||||||
handler(sig, (union uml_pt_regs *) r);
|
|
||||||
|
|
||||||
if(is_user){
|
|
||||||
interrupt_end();
|
|
||||||
block_signals();
|
|
||||||
set_user_mode(NULL);
|
|
||||||
}
|
|
||||||
*r = save_regs;
|
|
||||||
errno = save_errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "linux/sched.h"
|
|
||||||
#include "asm/uaccess.h"
|
|
||||||
|
|
||||||
int copy_from_user_tt(void *to, const void __user *from, int n)
|
|
||||||
{
|
|
||||||
if(!access_ok(VERIFY_READ, from, n))
|
|
||||||
return(n);
|
|
||||||
|
|
||||||
return(__do_copy_from_user(to, from, n, ¤t->thread.fault_addr,
|
|
||||||
¤t->thread.fault_catcher));
|
|
||||||
}
|
|
||||||
|
|
||||||
int copy_to_user_tt(void __user *to, const void *from, int n)
|
|
||||||
{
|
|
||||||
if(!access_ok(VERIFY_WRITE, to, n))
|
|
||||||
return(n);
|
|
||||||
|
|
||||||
return(__do_copy_to_user(to, from, n, ¤t->thread.fault_addr,
|
|
||||||
¤t->thread.fault_catcher));
|
|
||||||
}
|
|
||||||
|
|
||||||
int strncpy_from_user_tt(char *dst, const char __user *src, int count)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if(!access_ok(VERIFY_READ, src, 1))
|
|
||||||
return(-EFAULT);
|
|
||||||
|
|
||||||
n = __do_strncpy_from_user(dst, src, count,
|
|
||||||
¤t->thread.fault_addr,
|
|
||||||
¤t->thread.fault_catcher);
|
|
||||||
if(n < 0) return(-EFAULT);
|
|
||||||
return(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __clear_user_tt(void __user *mem, int len)
|
|
||||||
{
|
|
||||||
return(__do_clear_user(mem, len,
|
|
||||||
¤t->thread.fault_addr,
|
|
||||||
¤t->thread.fault_catcher));
|
|
||||||
}
|
|
||||||
|
|
||||||
int clear_user_tt(void __user *mem, int len)
|
|
||||||
{
|
|
||||||
if(!access_ok(VERIFY_WRITE, mem, len))
|
|
||||||
return(len);
|
|
||||||
|
|
||||||
return(__do_clear_user(mem, len, ¤t->thread.fault_addr,
|
|
||||||
¤t->thread.fault_catcher));
|
|
||||||
}
|
|
||||||
|
|
||||||
int strnlen_user_tt(const void __user *str, int len)
|
|
||||||
{
|
|
||||||
return(__do_strnlen_user(str, len,
|
|
||||||
¤t->thread.fault_addr,
|
|
||||||
¤t->thread.fault_catcher));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -1,105 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
|
|
||||||
* Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "uml_uaccess.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "kern_util.h"
|
|
||||||
#include "os.h"
|
|
||||||
#include "longjmp.h"
|
|
||||||
|
|
||||||
int __do_copy_from_user(void *to, const void *from, int n,
|
|
||||||
void **fault_addr, void **fault_catcher)
|
|
||||||
{
|
|
||||||
struct tt_regs save = TASK_REGS(get_current())->tt;
|
|
||||||
unsigned long fault;
|
|
||||||
int faulted;
|
|
||||||
|
|
||||||
fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
|
|
||||||
__do_copy, &faulted);
|
|
||||||
TASK_REGS(get_current())->tt = save;
|
|
||||||
|
|
||||||
if(!faulted)
|
|
||||||
return 0;
|
|
||||||
else if (fault)
|
|
||||||
return n - (fault - (unsigned long) from);
|
|
||||||
else
|
|
||||||
/* In case of a general protection fault, we don't have the
|
|
||||||
* fault address, so NULL is used instead. Pretend we didn't
|
|
||||||
* copy anything. */
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __do_strncpy(void *dst, const void *src, int count)
|
|
||||||
{
|
|
||||||
strncpy(dst, src, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
|
|
||||||
void **fault_addr, void **fault_catcher)
|
|
||||||
{
|
|
||||||
struct tt_regs save = TASK_REGS(get_current())->tt;
|
|
||||||
unsigned long fault;
|
|
||||||
int faulted;
|
|
||||||
|
|
||||||
fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
|
|
||||||
__do_strncpy, &faulted);
|
|
||||||
TASK_REGS(get_current())->tt = save;
|
|
||||||
|
|
||||||
if(!faulted) return(strlen(dst));
|
|
||||||
else return(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __do_clear(void *to, const void *from, int n)
|
|
||||||
{
|
|
||||||
memset(to, 0, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __do_clear_user(void *mem, unsigned long len,
|
|
||||||
void **fault_addr, void **fault_catcher)
|
|
||||||
{
|
|
||||||
struct tt_regs save = TASK_REGS(get_current())->tt;
|
|
||||||
unsigned long fault;
|
|
||||||
int faulted;
|
|
||||||
|
|
||||||
fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
|
|
||||||
__do_clear, &faulted);
|
|
||||||
TASK_REGS(get_current())->tt = save;
|
|
||||||
|
|
||||||
if(!faulted) return(0);
|
|
||||||
else return(len - (fault - (unsigned long) mem));
|
|
||||||
}
|
|
||||||
|
|
||||||
int __do_strnlen_user(const char *str, unsigned long n,
|
|
||||||
void **fault_addr, void **fault_catcher)
|
|
||||||
{
|
|
||||||
struct tt_regs save = TASK_REGS(get_current())->tt;
|
|
||||||
int ret;
|
|
||||||
unsigned long *faddrp = (unsigned long *)fault_addr;
|
|
||||||
jmp_buf jbuf;
|
|
||||||
|
|
||||||
*fault_catcher = &jbuf;
|
|
||||||
if(UML_SETJMP(&jbuf) == 0)
|
|
||||||
ret = strlen(str) + 1;
|
|
||||||
else ret = *faddrp - (unsigned long) str;
|
|
||||||
|
|
||||||
*fault_addr = NULL;
|
|
||||||
*fault_catcher = NULL;
|
|
||||||
|
|
||||||
TASK_REGS(get_current())->tt = save;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
||||||
* Emacs will notice this stuff at the end of the file and automatically
|
|
||||||
* adjust the settings for this buffer only. This must remain at the end
|
|
||||||
* of the file.
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
* Local variables:
|
|
||||||
* c-file-style: "linux"
|
|
||||||
* End:
|
|
||||||
*/
|
|
@ -38,9 +38,7 @@
|
|||||||
#include "choose-mode.h"
|
#include "choose-mode.h"
|
||||||
#include "mode_kern.h"
|
#include "mode_kern.h"
|
||||||
#include "mode.h"
|
#include "mode.h"
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
#include "skas.h"
|
#include "skas.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEFAULT_COMMAND_LINE "root=98:0"
|
#define DEFAULT_COMMAND_LINE "root=98:0"
|
||||||
|
|
||||||
@ -132,43 +130,12 @@ unsigned long end_vm;
|
|||||||
/* Set in uml_ncpus_setup */
|
/* Set in uml_ncpus_setup */
|
||||||
int ncpus = 1;
|
int ncpus = 1;
|
||||||
|
|
||||||
#ifdef CONFIG_CMDLINE_ON_HOST
|
|
||||||
/* Pointer set in linux_main, the array itself is private to each thread,
|
|
||||||
* and changed at address space creation time so this poses no concurrency
|
|
||||||
* problems.
|
|
||||||
*/
|
|
||||||
static char *argv1_begin = NULL;
|
|
||||||
static char *argv1_end = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Set in early boot */
|
/* Set in early boot */
|
||||||
static int have_root __initdata = 0;
|
static int have_root __initdata = 0;
|
||||||
|
|
||||||
/* Set in uml_mem_setup and modified in linux_main */
|
/* Set in uml_mem_setup and modified in linux_main */
|
||||||
long long physmem_size = 32 * 1024 * 1024;
|
long long physmem_size = 32 * 1024 * 1024;
|
||||||
|
|
||||||
void set_cmdline(char *cmd)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_CMDLINE_ON_HOST
|
|
||||||
char *umid, *ptr;
|
|
||||||
|
|
||||||
if(CHOOSE_MODE(honeypot, 0)) return;
|
|
||||||
|
|
||||||
umid = get_umid();
|
|
||||||
if(*umid != '\0'){
|
|
||||||
snprintf(argv1_begin,
|
|
||||||
(argv1_end - argv1_begin) * sizeof(*ptr),
|
|
||||||
"(%s) ", umid);
|
|
||||||
ptr = &argv1_begin[strlen(argv1_begin)];
|
|
||||||
}
|
|
||||||
else ptr = argv1_begin;
|
|
||||||
|
|
||||||
snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
|
|
||||||
memset(argv1_begin + strlen(argv1_begin), '\0',
|
|
||||||
argv1_end - argv1_begin - strlen(argv1_begin));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *usage_string =
|
static char *usage_string =
|
||||||
"User Mode Linux v%s\n"
|
"User Mode Linux v%s\n"
|
||||||
" available at http://user-mode-linux.sourceforge.net/\n\n";
|
" available at http://user-mode-linux.sourceforge.net/\n\n";
|
||||||
@ -201,13 +168,10 @@ __uml_setup("root=", uml_root_setup,
|
|||||||
" root=/dev/ubd5\n\n"
|
" root=/dev/ubd5\n\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
#ifndef CONFIG_MODE_TT
|
|
||||||
|
|
||||||
static int __init no_skas_debug_setup(char *line, int *add)
|
static int __init no_skas_debug_setup(char *line, int *add)
|
||||||
{
|
{
|
||||||
printf("'debug' is not necessary to gdb UML in skas mode - run \n");
|
printf("'debug' is not necessary to gdb UML in skas mode - run \n");
|
||||||
printf("'gdb linux' and disable CONFIG_CMDLINE_ON_HOST if gdb \n");
|
printf("'gdb linux'");
|
||||||
printf("doesn't work as expected\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -217,8 +181,6 @@ __uml_setup("debug", no_skas_debug_setup,
|
|||||||
" this flag is not needed to run gdb on UML in skas mode\n\n"
|
" this flag is not needed to run gdb on UML in skas mode\n\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
static int __init uml_ncpus_setup(char *line, int *add)
|
static int __init uml_ncpus_setup(char *line, int *add)
|
||||||
{
|
{
|
||||||
@ -236,52 +198,6 @@ __uml_setup("ncpus=", uml_ncpus_setup,
|
|||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int force_tt = 0;
|
|
||||||
|
|
||||||
#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
|
|
||||||
#define DEFAULT_TT 0
|
|
||||||
|
|
||||||
static int __init mode_tt_setup(char *line, int *add)
|
|
||||||
{
|
|
||||||
force_tt = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
|
|
||||||
#define DEFAULT_TT 0
|
|
||||||
|
|
||||||
static int __init mode_tt_setup(char *line, int *add)
|
|
||||||
{
|
|
||||||
printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
|
|
||||||
#define DEFAULT_TT 1
|
|
||||||
|
|
||||||
static int __init mode_tt_setup(char *line, int *add)
|
|
||||||
{
|
|
||||||
printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
__uml_setup("mode=tt", mode_tt_setup,
|
|
||||||
"mode=tt\n"
|
|
||||||
" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
|
|
||||||
" forces UML to run in tt (tracing thread) mode. It is not the default\n"
|
|
||||||
" because it's slower and less secure than skas mode.\n\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
int mode_tt = DEFAULT_TT;
|
|
||||||
|
|
||||||
static int __init Usage(char *line, int *add)
|
static int __init Usage(char *line, int *add)
|
||||||
{
|
{
|
||||||
const char **p;
|
const char **p;
|
||||||
@ -357,29 +273,13 @@ int __init linux_main(int argc, char **argv)
|
|||||||
add_arg(DEFAULT_COMMAND_LINE);
|
add_arg(DEFAULT_COMMAND_LINE);
|
||||||
|
|
||||||
os_early_checks();
|
os_early_checks();
|
||||||
if (force_tt)
|
|
||||||
clear_can_do_skas();
|
|
||||||
mode_tt = force_tt ? 1 : !can_do_skas();
|
|
||||||
#ifndef CONFIG_MODE_TT
|
|
||||||
if (mode_tt) {
|
|
||||||
/*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
|
|
||||||
* can_do_skas() returned 0, and the message is correct. */
|
|
||||||
printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CONFIG_MODE_SKAS
|
can_do_skas();
|
||||||
mode = "TT";
|
|
||||||
#else
|
if (proc_mm && ptrace_faultinfo)
|
||||||
/* Show to the user the result of selection */
|
|
||||||
if (mode_tt)
|
|
||||||
mode = "TT";
|
|
||||||
else if (proc_mm && ptrace_faultinfo)
|
|
||||||
mode = "SKAS3";
|
mode = "SKAS3";
|
||||||
else
|
else
|
||||||
mode = "SKAS0";
|
mode = "SKAS0";
|
||||||
#endif
|
|
||||||
|
|
||||||
printf("UML running in %s mode\n", mode);
|
printf("UML running in %s mode\n", mode);
|
||||||
|
|
||||||
@ -411,11 +311,6 @@ int __init linux_main(int argc, char **argv)
|
|||||||
|
|
||||||
setup_machinename(init_utsname()->machine);
|
setup_machinename(init_utsname()->machine);
|
||||||
|
|
||||||
#ifdef CONFIG_CMDLINE_ON_HOST
|
|
||||||
argv1_begin = argv[1];
|
|
||||||
argv1_end = &argv[1][strlen(argv[1])];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
highmem = 0;
|
highmem = 0;
|
||||||
iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
|
iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
|
||||||
max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
|
max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
|
||||||
|
@ -18,13 +18,6 @@ SECTIONS
|
|||||||
|
|
||||||
. = START + SIZEOF_HEADERS;
|
. = START + SIZEOF_HEADERS;
|
||||||
|
|
||||||
#ifdef MODE_TT
|
|
||||||
.remap_data : { UNMAP_PATH (.data .bss) }
|
|
||||||
.remap : { UNMAP_PATH (.text) }
|
|
||||||
|
|
||||||
. = ALIGN(4096); /* Init code and data */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_text = .;
|
_text = .;
|
||||||
_stext = .;
|
_stext = .;
|
||||||
__init_begin = .;
|
__init_begin = .;
|
||||||
|
@ -5,12 +5,7 @@
|
|||||||
|
|
||||||
obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \
|
obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \
|
||||||
registers.o sigio.o signal.o start_up.o time.o trap.o tty.o uaccess.o \
|
registers.o sigio.o signal.o start_up.o time.o trap.o tty.o uaccess.o \
|
||||||
umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/
|
umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/
|
||||||
|
|
||||||
obj-$(CONFIG_MODE_SKAS) += skas/
|
|
||||||
|
|
||||||
obj-$(CONFIG_MODE_TT) += tt.o
|
|
||||||
user-objs-$(CONFIG_MODE_TT) += tt.o
|
|
||||||
|
|
||||||
obj-$(CONFIG_TTY_LOG) += tty_log.o
|
obj-$(CONFIG_TTY_LOG) += tty_log.o
|
||||||
user-objs-$(CONFIG_TTY_LOG) += tty_log.o
|
user-objs-$(CONFIG_TTY_LOG) += tty_log.o
|
||||||
|
@ -25,9 +25,6 @@
|
|||||||
#include "um_malloc.h"
|
#include "um_malloc.h"
|
||||||
#include "kern_constants.h"
|
#include "kern_constants.h"
|
||||||
|
|
||||||
/* Set in main, unchanged thereafter */
|
|
||||||
char *linux_prog;
|
|
||||||
|
|
||||||
#define PGD_BOUND (4 * 1024 * 1024)
|
#define PGD_BOUND (4 * 1024 * 1024)
|
||||||
#define STACKSIZE (8 * 1024 * 1024)
|
#define STACKSIZE (8 * 1024 * 1024)
|
||||||
#define THREAD_NAME_LEN (256)
|
#define THREAD_NAME_LEN (256)
|
||||||
@ -125,35 +122,6 @@ int __init main(int argc, char **argv, char **envp)
|
|||||||
char **new_argv;
|
char **new_argv;
|
||||||
int ret, i, err;
|
int ret, i, err;
|
||||||
|
|
||||||
#ifdef UML_CONFIG_CMDLINE_ON_HOST
|
|
||||||
/* Allocate memory for thread command lines */
|
|
||||||
if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
|
|
||||||
|
|
||||||
char padding[THREAD_NAME_LEN] = {
|
|
||||||
[ 0 ... THREAD_NAME_LEN - 2] = ' ', '\0'
|
|
||||||
};
|
|
||||||
|
|
||||||
new_argv = malloc((argc + 2) * sizeof(char*));
|
|
||||||
if(!new_argv) {
|
|
||||||
perror("Allocating extended argv");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
new_argv[0] = argv[0];
|
|
||||||
new_argv[1] = padding;
|
|
||||||
|
|
||||||
for(i = 2; i <= argc; i++)
|
|
||||||
new_argv[i] = argv[i - 1];
|
|
||||||
new_argv[argc + 1] = NULL;
|
|
||||||
|
|
||||||
execvp(new_argv[0], new_argv);
|
|
||||||
perror("execing with extended args");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
linux_prog = argv[0];
|
|
||||||
|
|
||||||
set_stklim();
|
set_stklim();
|
||||||
|
|
||||||
setup_env_path();
|
setup_env_path();
|
||||||
|
@ -133,13 +133,6 @@ void os_kill_ptraced_process(int pid, int reap_child)
|
|||||||
CATCH_EINTR(waitpid(pid, NULL, 0));
|
CATCH_EINTR(waitpid(pid, NULL, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
void os_usr1_process(int pid)
|
|
||||||
{
|
|
||||||
kill(pid, SIGUSR1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Don't use the glibc version, which caches the result in TLS. It misses some
|
/* Don't use the glibc version, which caches the result in TLS. It misses some
|
||||||
* syscalls, and also breaks with clone(), which does not unshare the TLS.
|
* syscalls, and also breaks with clone(), which does not unshare the TLS.
|
||||||
*/
|
*/
|
||||||
@ -239,30 +232,6 @@ out:
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
|
|
||||||
{
|
|
||||||
int flags = 0, pages;
|
|
||||||
|
|
||||||
if(sig_stack != NULL){
|
|
||||||
pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
|
|
||||||
set_sigstack(sig_stack, pages * UM_KERN_PAGE_SIZE);
|
|
||||||
flags = SA_ONSTACK;
|
|
||||||
}
|
|
||||||
if(usr1_handler){
|
|
||||||
struct sigaction sa;
|
|
||||||
|
|
||||||
sa.sa_handler = usr1_handler;
|
|
||||||
sigemptyset(&sa.sa_mask);
|
|
||||||
sa.sa_flags = flags;
|
|
||||||
sa.sa_restorer = NULL;
|
|
||||||
if(sigaction(SIGUSR1, &sa, NULL) < 0)
|
|
||||||
panic("init_new_thread_stack - sigaction failed - "
|
|
||||||
"errno = %d\n", errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void init_new_thread_signals(void)
|
void init_new_thread_signals(void)
|
||||||
{
|
{
|
||||||
set_handler(SIGSEGV, (__sighandler_t) sig_handler, SA_ONSTACK,
|
set_handler(SIGSEGV, (__sighandler_t) sig_handler, SA_ONSTACK,
|
||||||
|
@ -35,12 +35,9 @@
|
|||||||
#include "mode.h"
|
#include "mode.h"
|
||||||
#include "tempfile.h"
|
#include "tempfile.h"
|
||||||
#include "kern_constants.h"
|
#include "kern_constants.h"
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
#include "skas.h"
|
#include "skas.h"
|
||||||
#include "skas_ptrace.h"
|
#include "skas_ptrace.h"
|
||||||
#include "registers.h"
|
#include "registers.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
static int ptrace_child(void *arg)
|
static int ptrace_child(void *arg)
|
||||||
{
|
{
|
||||||
@ -407,7 +404,6 @@ __uml_setup("noptraceldt", noptraceldt_cmd_param,
|
|||||||
" To support PTRACE_LDT, the host needs to be patched using\n"
|
" To support PTRACE_LDT, the host needs to be patched using\n"
|
||||||
" the current skas3 patch.\n\n");
|
" the current skas3 patch.\n\n");
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
static inline void check_skas3_ptrace_faultinfo(void)
|
static inline void check_skas3_ptrace_faultinfo(void)
|
||||||
{
|
{
|
||||||
struct ptrace_faultinfo fi;
|
struct ptrace_faultinfo fi;
|
||||||
@ -504,12 +500,6 @@ int can_do_skas(void)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
int can_do_skas(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int __init parse_iomem(char *str, int *add)
|
int __init parse_iomem(char *str, int *add)
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# Licensed under the GPL
|
# Licensed under the GPL
|
||||||
#
|
#
|
||||||
|
|
||||||
obj-$(CONFIG_MODE_SKAS) = registers.o signal.o tls.o
|
obj-y = registers.o signal.o tls.o
|
||||||
|
|
||||||
USER_OBJS := $(obj-y)
|
USER_OBJS := $(obj-y)
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# Licensed under the GPL
|
# Licensed under the GPL
|
||||||
#
|
#
|
||||||
|
|
||||||
obj-$(CONFIG_MODE_SKAS) = registers.o prctl.o signal.o
|
obj-y = registers.o prctl.o signal.o
|
||||||
|
|
||||||
USER_OBJS := $(obj-y)
|
USER_OBJS := $(obj-y)
|
||||||
|
|
||||||
|
@ -30,13 +30,6 @@ int set_interval(int is_virtual)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
void enable_timer(void)
|
|
||||||
{
|
|
||||||
set_interval(1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void disable_timer(void)
|
void disable_timer(void)
|
||||||
{
|
{
|
||||||
struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
|
struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
|
||||||
@ -71,18 +64,6 @@ void switch_timers(int to_real)
|
|||||||
errno);
|
errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
void uml_idle_timer(void)
|
|
||||||
{
|
|
||||||
if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
|
|
||||||
panic("Couldn't unset SIGVTALRM handler");
|
|
||||||
|
|
||||||
set_handler(SIGALRM, (__sighandler_t) alarm_handler,
|
|
||||||
SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
|
|
||||||
set_interval(0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
unsigned long long os_nsecs(void)
|
unsigned long long os_nsecs(void)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
@ -8,11 +8,6 @@
|
|||||||
|
|
||||||
/* TLS support - we basically rely on the host's one.*/
|
/* TLS support - we basically rely on the host's one.*/
|
||||||
|
|
||||||
/* In TT mode, this should be called only by the tracing thread, and makes sense
|
|
||||||
* only for PTRACE_SET_THREAD_AREA. In SKAS mode, it's used normally.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PTRACE_GET_THREAD_AREA
|
#ifndef PTRACE_GET_THREAD_AREA
|
||||||
#define PTRACE_GET_THREAD_AREA 25
|
#define PTRACE_GET_THREAD_AREA 25
|
||||||
#endif
|
#endif
|
||||||
@ -32,8 +27,6 @@ int os_set_thread_area(user_desc_t *info, int pid)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_SKAS
|
|
||||||
|
|
||||||
int os_get_thread_area(user_desc_t *info, int pid)
|
int os_get_thread_area(user_desc_t *info, int pid)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -44,32 +37,3 @@ int os_get_thread_area(user_desc_t *info, int pid)
|
|||||||
ret = -errno;
|
ret = -errno;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
#include "linux/unistd.h"
|
|
||||||
|
|
||||||
int do_set_thread_area_tt(user_desc_t *info)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = syscall(__NR_set_thread_area,info);
|
|
||||||
if (ret < 0) {
|
|
||||||
ret = -errno;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int do_get_thread_area_tt(user_desc_t *info)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = syscall(__NR_get_thread_area,info);
|
|
||||||
if (ret < 0) {
|
|
||||||
ret = -errno;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* UML_CONFIG_MODE_TT */
|
|
||||||
|
@ -21,7 +21,7 @@ $(UNPROFILE_OBJS:.o=.%): \
|
|||||||
$(UNPROFILE_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \
|
$(UNPROFILE_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \
|
||||||
-Dunix -D__unix__ -D__$(SUBARCH)__ $(CF)
|
-Dunix -D__unix__ -D__$(SUBARCH)__ $(CF)
|
||||||
|
|
||||||
# The stubs and unmap.o can't try to call mcount or update basic block data
|
# The stubs can't try to call mcount or update basic block data
|
||||||
define unprofile
|
define unprofile
|
||||||
$(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
|
$(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
|
||||||
endef
|
endef
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
|
obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
|
||||||
ptrace_user.o setjmp.o signal.o sigcontext.o syscalls.o sysrq.o \
|
ptrace_user.o setjmp.o signal.o sigcontext.o stub.o stub_segv.o \
|
||||||
sys_call_table.o tls.o
|
syscalls.o sysrq.o sys_call_table.o tls.o
|
||||||
|
|
||||||
obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
|
|
||||||
|
|
||||||
subarch-obj-y = lib/bitops_32.o lib/semaphore_32.o lib/string_32.o
|
subarch-obj-y = lib/bitops_32.o lib/semaphore_32.o lib/string_32.o
|
||||||
subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o
|
subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o
|
||||||
@ -13,11 +11,7 @@ USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
|
|||||||
USER_OBJS += user-offsets.s
|
USER_OBJS += user-offsets.s
|
||||||
extra-y += user-offsets.s
|
extra-y += user-offsets.s
|
||||||
|
|
||||||
extra-$(CONFIG_MODE_TT) += unmap.o
|
|
||||||
|
|
||||||
UNPROFILE_OBJS := stub_segv.o
|
UNPROFILE_OBJS := stub_segv.o
|
||||||
CFLAGS_stub_segv.o := $(CFLAGS_NO_HARDENING)
|
CFLAGS_stub_segv.o := $(CFLAGS_NO_HARDENING)
|
||||||
|
|
||||||
include arch/um/scripts/Makefile.rules
|
include arch/um/scripts/Makefile.rules
|
||||||
|
|
||||||
$(obj)/unmap.%: _c_flags = $(call unprofile,$(CFLAGS))
|
|
||||||
|
@ -19,72 +19,6 @@
|
|||||||
|
|
||||||
extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
|
extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
|
|
||||||
static long do_modify_ldt_tt(int func, void __user *ptr,
|
|
||||||
unsigned long bytecount)
|
|
||||||
{
|
|
||||||
struct user_desc info;
|
|
||||||
int res = 0;
|
|
||||||
void *buf = NULL;
|
|
||||||
void *p = NULL; /* What we pass to host. */
|
|
||||||
|
|
||||||
switch(func){
|
|
||||||
case 1:
|
|
||||||
case 0x11: /* write_ldt */
|
|
||||||
/* Do this check now to avoid overflows. */
|
|
||||||
if (bytecount != sizeof(struct user_desc)) {
|
|
||||||
res = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(copy_from_user(&info, ptr, sizeof(info))) {
|
|
||||||
res = -EFAULT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = &info;
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
case 2: /* read_ldt */
|
|
||||||
|
|
||||||
/* The use of info avoids kmalloc on the write case, not on the
|
|
||||||
* read one. */
|
|
||||||
buf = kmalloc(bytecount, GFP_KERNEL);
|
|
||||||
if (!buf) {
|
|
||||||
res = -ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
p = buf;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
res = -ENOSYS;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = modify_ldt(func, p, bytecount);
|
|
||||||
if(res < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
switch(func){
|
|
||||||
case 0:
|
|
||||||
case 2:
|
|
||||||
/* Modify_ldt was for reading and returned the number of read
|
|
||||||
* bytes.*/
|
|
||||||
if(copy_to_user(ptr, p, res))
|
|
||||||
res = -EFAULT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
kfree(buf);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
|
|
||||||
#include "skas.h"
|
#include "skas.h"
|
||||||
#include "skas_ptrace.h"
|
#include "skas_ptrace.h"
|
||||||
#include "asm/mmu_context.h"
|
#include "asm/mmu_context.h"
|
||||||
@ -569,7 +503,6 @@ void free_ldt(struct mmu_context_skas * mm)
|
|||||||
}
|
}
|
||||||
mm->ldt.entry_count = 0;
|
mm->ldt.entry_count = 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
|
int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
|
||||||
{
|
{
|
||||||
|
@ -14,12 +14,6 @@
|
|||||||
#include "sysdep/sigcontext.h"
|
#include "sysdep/sigcontext.h"
|
||||||
#include "sysdep/sc.h"
|
#include "sysdep/sc.h"
|
||||||
|
|
||||||
void arch_switch_to_tt(struct task_struct *from, struct task_struct *to)
|
|
||||||
{
|
|
||||||
update_debugregs(to->thread.arch.debugregs_seq);
|
|
||||||
arch_switch_tls_tt(from, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_switch_to_skas(struct task_struct *from, struct task_struct *to)
|
void arch_switch_to_skas(struct task_struct *from, struct task_struct *to)
|
||||||
{
|
{
|
||||||
int err = arch_switch_tls_skas(from, to);
|
int err = arch_switch_tls_skas(from, to);
|
||||||
@ -233,79 +227,12 @@ static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* FXSR floating point environment conversions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
static inline int convert_fxsr_to_user_tt(struct _fpstate __user *buf,
|
|
||||||
struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
|
|
||||||
unsigned long env[7];
|
|
||||||
struct _fpreg __user *to;
|
|
||||||
struct _fpxreg *from;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
env[0] = (unsigned long)fxsave->cwd | 0xffff0000;
|
|
||||||
env[1] = (unsigned long)fxsave->swd | 0xffff0000;
|
|
||||||
env[2] = twd_fxsr_to_i387(fxsave);
|
|
||||||
env[3] = fxsave->fip;
|
|
||||||
env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
|
|
||||||
env[5] = fxsave->foo;
|
|
||||||
env[6] = fxsave->fos;
|
|
||||||
|
|
||||||
if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
to = &buf->_st[0];
|
|
||||||
from = (struct _fpxreg *) &fxsave->st_space[0];
|
|
||||||
for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
|
|
||||||
if ( __copy_to_user( to, from, sizeof(*to) ) )
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline int convert_fxsr_to_user(struct _fpstate __user *buf,
|
static inline int convert_fxsr_to_user(struct _fpstate __user *buf,
|
||||||
struct pt_regs *regs)
|
struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0));
|
return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
static inline int convert_fxsr_from_user_tt(struct pt_regs *regs,
|
|
||||||
struct _fpstate __user *buf)
|
|
||||||
{
|
|
||||||
struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
|
|
||||||
unsigned long env[7];
|
|
||||||
struct _fpxreg *to;
|
|
||||||
struct _fpreg __user *from;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
fxsave->cwd = (unsigned short)(env[0] & 0xffff);
|
|
||||||
fxsave->swd = (unsigned short)(env[1] & 0xffff);
|
|
||||||
fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
|
|
||||||
fxsave->fip = env[3];
|
|
||||||
fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16);
|
|
||||||
fxsave->fcs = (env[4] & 0xffff);
|
|
||||||
fxsave->foo = env[5];
|
|
||||||
fxsave->fos = env[6];
|
|
||||||
|
|
||||||
to = (struct _fpxreg *) &fxsave->st_space[0];
|
|
||||||
from = &buf->_st[0];
|
|
||||||
for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
|
|
||||||
if ( __copy_from_user( to, from, sizeof(*from) ) )
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline int convert_fxsr_from_user(struct pt_regs *regs,
|
static inline int convert_fxsr_from_user(struct pt_regs *regs,
|
||||||
struct _fpstate __user *buf)
|
struct _fpstate __user *buf)
|
||||||
{
|
{
|
||||||
@ -332,39 +259,11 @@ int set_fpregs(unsigned long buf, struct task_struct *child)
|
|||||||
else return(0);
|
else return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
|
|
||||||
{
|
|
||||||
struct pt_regs *regs = &tsk->thread.regs;
|
|
||||||
struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = __copy_to_user((void __user *) buf, fxsave,
|
|
||||||
sizeof(struct user_fxsr_struct));
|
|
||||||
if(err) return -EFAULT;
|
|
||||||
else return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int get_fpxregs(unsigned long buf, struct task_struct *tsk)
|
int get_fpxregs(unsigned long buf, struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0));
|
return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
|
|
||||||
{
|
|
||||||
struct pt_regs *regs = &tsk->thread.regs;
|
|
||||||
struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = __copy_from_user(fxsave, (void __user *) buf,
|
|
||||||
sizeof(struct user_fxsr_struct) );
|
|
||||||
if(err) return -EFAULT;
|
|
||||||
else return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int set_fpxregs(unsigned long buf, struct task_struct *tsk)
|
int set_fpxregs(unsigned long buf, struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0));
|
return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0));
|
||||||
@ -387,25 +286,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
static inline void copy_fpu_fxsave_tt(struct pt_regs *regs,
|
|
||||||
struct user_i387_struct *buf)
|
|
||||||
{
|
|
||||||
struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs));
|
|
||||||
unsigned short *to;
|
|
||||||
unsigned short *from;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
memcpy( buf, fpu, 7 * sizeof(long) );
|
|
||||||
|
|
||||||
to = (unsigned short *) &buf->st_space[0];
|
|
||||||
from = (unsigned short *) &fpu->st_space[0];
|
|
||||||
for ( i = 0 ; i < 8 ; i++, to += 5, from += 8 ) {
|
|
||||||
memcpy( to, from, 5 * sizeof(unsigned short) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline void copy_fpu_fxsave(struct pt_regs *regs,
|
static inline void copy_fpu_fxsave(struct pt_regs *regs,
|
||||||
struct user_i387_struct *buf)
|
struct user_i387_struct *buf)
|
||||||
{
|
{
|
||||||
|
@ -43,89 +43,3 @@ int ptrace_setfpregs(long pid, unsigned long *regs)
|
|||||||
return -errno;
|
return -errno;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UML_CONFIG_MODE_TT
|
|
||||||
|
|
||||||
static void write_debugregs(int pid, unsigned long *regs)
|
|
||||||
{
|
|
||||||
struct user *dummy;
|
|
||||||
int nregs, i;
|
|
||||||
|
|
||||||
dummy = NULL;
|
|
||||||
nregs = ARRAY_SIZE(dummy->u_debugreg);
|
|
||||||
for(i = 0; i < nregs; i++){
|
|
||||||
if((i == 4) || (i == 5)) continue;
|
|
||||||
if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i],
|
|
||||||
regs[i]) < 0)
|
|
||||||
printk("write_debugregs - ptrace failed on "
|
|
||||||
"register %d, value = 0x%lx, errno = %d\n", i,
|
|
||||||
regs[i], errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read_debugregs(int pid, unsigned long *regs)
|
|
||||||
{
|
|
||||||
struct user *dummy;
|
|
||||||
int nregs, i;
|
|
||||||
|
|
||||||
dummy = NULL;
|
|
||||||
nregs = ARRAY_SIZE(dummy->u_debugreg);
|
|
||||||
for(i = 0; i < nregs; i++){
|
|
||||||
regs[i] = ptrace(PTRACE_PEEKUSR, pid,
|
|
||||||
&dummy->u_debugreg[i], 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Accessed only by the tracing thread */
|
|
||||||
static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 };
|
|
||||||
|
|
||||||
void arch_enter_kernel(void *task, int pid)
|
|
||||||
{
|
|
||||||
read_debugregs(pid, TASK_DEBUGREGS(task));
|
|
||||||
write_debugregs(pid, kernel_debugregs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_leave_kernel(void *task, int pid)
|
|
||||||
{
|
|
||||||
read_debugregs(pid, kernel_debugregs);
|
|
||||||
write_debugregs(pid, TASK_DEBUGREGS(task));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef UML_CONFIG_PT_PROXY
|
|
||||||
/* Accessed only by the tracing thread */
|
|
||||||
static int debugregs_seq;
|
|
||||||
|
|
||||||
/* Only called by the ptrace proxy */
|
|
||||||
void ptrace_pokeuser(unsigned long addr, unsigned long data)
|
|
||||||
{
|
|
||||||
if((addr < offsetof(struct user, u_debugreg[0])) ||
|
|
||||||
(addr > offsetof(struct user, u_debugreg[7])))
|
|
||||||
return;
|
|
||||||
addr -= offsetof(struct user, u_debugreg[0]);
|
|
||||||
addr = addr >> 2;
|
|
||||||
if(kernel_debugregs[addr] == data) return;
|
|
||||||
|
|
||||||
kernel_debugregs[addr] = data;
|
|
||||||
debugregs_seq++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_debugregs_cb(void *arg)
|
|
||||||
{
|
|
||||||
int pid = *((int *) arg);
|
|
||||||
|
|
||||||
write_debugregs(pid, kernel_debugregs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Optimized out in its header when not defined */
|
|
||||||
void update_debugregs(int seq)
|
|
||||||
{
|
|
||||||
int me;
|
|
||||||
|
|
||||||
if(seq == debugregs_seq) return;
|
|
||||||
|
|
||||||
me = os_getpid();
|
|
||||||
initial_thread_cb(update_debugregs_cb, &me);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -13,9 +13,6 @@
|
|||||||
#include "sigcontext.h"
|
#include "sigcontext.h"
|
||||||
#include "registers.h"
|
#include "registers.h"
|
||||||
#include "mode.h"
|
#include "mode.h"
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
|
|
||||||
#include "skas.h"
|
#include "skas.h"
|
||||||
|
|
||||||
void copy_sc(union uml_pt_regs *regs, void *from)
|
void copy_sc(union uml_pt_regs *regs, void *from)
|
||||||
@ -108,61 +105,6 @@ int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *t
|
|||||||
return copy_to_user(to, &sc, sizeof(sc)) ||
|
return copy_to_user(to, &sc, sizeof(sc)) ||
|
||||||
copy_to_user(to_fp, fpregs, sizeof(fpregs));
|
copy_to_user(to_fp, fpregs, sizeof(fpregs));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
|
|
||||||
/* These copy a sigcontext to/from userspace. They copy the fpstate pointer,
|
|
||||||
* blowing away the old, good one. So, that value is saved, and then restored
|
|
||||||
* after the sigcontext copy. In copy_from, the variable holding the saved
|
|
||||||
* fpstate pointer, and the sigcontext that it should be restored to are both
|
|
||||||
* in the kernel, so we can just restore using an assignment. In copy_to, the
|
|
||||||
* saved pointer is in the kernel, but the sigcontext is in userspace, so we
|
|
||||||
* copy_to_user it.
|
|
||||||
*/
|
|
||||||
int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from,
|
|
||||||
int fpsize)
|
|
||||||
{
|
|
||||||
struct _fpstate *to_fp;
|
|
||||||
struct _fpstate __user *from_fp;
|
|
||||||
unsigned long sigs;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
to_fp = to->fpstate;
|
|
||||||
sigs = to->oldmask;
|
|
||||||
err = copy_from_user(to, from, sizeof(*to));
|
|
||||||
from_fp = to->fpstate;
|
|
||||||
to->oldmask = sigs;
|
|
||||||
to->fpstate = to_fp;
|
|
||||||
if(to_fp != NULL)
|
|
||||||
err |= copy_from_user(to_fp, from_fp, fpsize);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp,
|
|
||||||
struct sigcontext *from, int fpsize, unsigned long sp)
|
|
||||||
{
|
|
||||||
struct _fpstate __user *to_fp;
|
|
||||||
struct _fpstate *from_fp;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
to_fp = (fp ? fp : (struct _fpstate __user *) (to + 1));
|
|
||||||
from_fp = from->fpstate;
|
|
||||||
err = copy_to_user(to, from, sizeof(*to));
|
|
||||||
|
|
||||||
/* The SP in the sigcontext is the updated one for the signal
|
|
||||||
* delivery. The sp passed in is the original, and this needs
|
|
||||||
* to be restored, so we stick it in separately.
|
|
||||||
*/
|
|
||||||
err |= copy_to_user(&SC_SP(to), &sp, sizeof(sp));
|
|
||||||
|
|
||||||
if(from_fp != NULL){
|
|
||||||
err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
|
|
||||||
err |= copy_to_user(to_fp, from_fp, fpsize);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int copy_sc_from_user(struct pt_regs *to, void __user *from)
|
static int copy_sc_from_user(struct pt_regs *to, void __user *from)
|
||||||
{
|
{
|
||||||
|
@ -18,10 +18,7 @@
|
|||||||
#include "mode_kern.h"
|
#include "mode_kern.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "mode.h"
|
#include "mode.h"
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
#include "skas.h"
|
#include "skas.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If needed we can detect when it's uninitialized.
|
* If needed we can detect when it's uninitialized.
|
||||||
@ -31,7 +28,6 @@
|
|||||||
static int host_supports_tls = -1;
|
static int host_supports_tls = -1;
|
||||||
int host_gdt_entry_tls_min;
|
int host_gdt_entry_tls_min;
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
int do_set_thread_area_skas(struct user_desc *info)
|
int do_set_thread_area_skas(struct user_desc *info)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -53,7 +49,6 @@ int do_get_thread_area_skas(struct user_desc *info)
|
|||||||
put_cpu();
|
put_cpu();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sys_get_thread_area: get a yet unused TLS descriptor index.
|
* sys_get_thread_area: get a yet unused TLS descriptor index.
|
||||||
@ -187,17 +182,6 @@ int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to)
|
|
||||||
{
|
|
||||||
if (!host_supports_tls)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (needs_TLS_update(to))
|
|
||||||
return load_TLS(0, to);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int set_tls_entry(struct task_struct* task, struct user_desc *info,
|
static int set_tls_entry(struct task_struct* task, struct user_desc *info,
|
||||||
int idx, int flushed)
|
int idx, int flushed)
|
||||||
{
|
{
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/mman.h>
|
|
||||||
#include <asm/unistd.h>
|
|
||||||
|
|
||||||
static int errno;
|
|
||||||
|
|
||||||
static inline _syscall2(int,munmap,void *,start,size_t,len)
|
|
||||||
static inline _syscall6(void *,mmap2,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset)
|
|
||||||
int switcheroo(int fd, int prot, void *from, void *to, int size)
|
|
||||||
{
|
|
||||||
if(munmap(to, size) < 0){
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
if(mmap2(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1 ){
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
if(munmap(from, size) < 0){
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
return(0);
|
|
||||||
}
|
|
@ -5,10 +5,9 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
|
obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
|
||||||
setjmp.o sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o \
|
setjmp.o sigcontext.o signal.o stub.o stub_segv.o syscalls.o \
|
||||||
ksyms.o tls.o
|
syscall_table.o sysrq.o ksyms.o tls.o
|
||||||
|
|
||||||
obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
|
|
||||||
obj-$(CONFIG_MODULES) += um_module.o
|
obj-$(CONFIG_MODULES) += um_module.o
|
||||||
|
|
||||||
subarch-obj-y = lib/bitops_64.o lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o
|
subarch-obj-y = lib/bitops_64.o lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o
|
||||||
@ -21,11 +20,7 @@ USER_OBJS := ptrace_user.o sigcontext.o
|
|||||||
USER_OBJS += user-offsets.s
|
USER_OBJS += user-offsets.s
|
||||||
extra-y += user-offsets.s
|
extra-y += user-offsets.s
|
||||||
|
|
||||||
extra-$(CONFIG_MODE_TT) += unmap.o
|
|
||||||
|
|
||||||
UNPROFILE_OBJS := stub_segv.o
|
UNPROFILE_OBJS := stub_segv.o
|
||||||
CFLAGS_stub_segv.o := $(CFLAGS_NO_HARDENING)
|
CFLAGS_stub_segv.o := $(CFLAGS_NO_HARDENING)
|
||||||
|
|
||||||
include arch/um/scripts/Makefile.rules
|
include arch/um/scripts/Makefile.rules
|
||||||
|
|
||||||
$(obj)/unmap.%: _c_flags = $(call unprofile,$(CFLAGS))
|
|
||||||
|
@ -15,9 +15,6 @@
|
|||||||
#include "choose-mode.h"
|
#include "choose-mode.h"
|
||||||
#include "sysdep/ptrace.h"
|
#include "sysdep/ptrace.h"
|
||||||
#include "frame_kern.h"
|
#include "frame_kern.h"
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
|
|
||||||
#include "skas.h"
|
#include "skas.h"
|
||||||
|
|
||||||
void copy_sc(union uml_pt_regs *regs, void *from)
|
void copy_sc(union uml_pt_regs *regs, void *from)
|
||||||
@ -134,53 +131,6 @@ int copy_sc_to_user_skas(struct sigcontext __user *to,
|
|||||||
return(err);
|
return(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from,
|
|
||||||
int fpsize)
|
|
||||||
{
|
|
||||||
struct _fpstate *to_fp;
|
|
||||||
struct _fpstate __user *from_fp;
|
|
||||||
unsigned long sigs;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
to_fp = to->fpstate;
|
|
||||||
sigs = to->oldmask;
|
|
||||||
err = copy_from_user(to, from, sizeof(*to));
|
|
||||||
from_fp = to->fpstate;
|
|
||||||
to->fpstate = to_fp;
|
|
||||||
to->oldmask = sigs;
|
|
||||||
if(to_fp != NULL)
|
|
||||||
err |= copy_from_user(to_fp, from_fp, fpsize);
|
|
||||||
return(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp,
|
|
||||||
struct sigcontext *from, int fpsize, unsigned long sp)
|
|
||||||
{
|
|
||||||
struct _fpstate __user *to_fp;
|
|
||||||
struct _fpstate *from_fp;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
to_fp = (fp ? fp : (struct _fpstate __user *) (to + 1));
|
|
||||||
from_fp = from->fpstate;
|
|
||||||
err = copy_to_user(to, from, sizeof(*to));
|
|
||||||
/* The SP in the sigcontext is the updated one for the signal
|
|
||||||
* delivery. The sp passed in is the original, and this needs
|
|
||||||
* to be restored, so we stick it in separately.
|
|
||||||
*/
|
|
||||||
err |= copy_to_user(&SC_SP(to), &sp, sizeof(sp));
|
|
||||||
|
|
||||||
if(from_fp != NULL){
|
|
||||||
err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
|
|
||||||
err |= copy_to_user(to_fp, from_fp, fpsize);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int copy_sc_from_user(struct pt_regs *to, void __user *from)
|
static int copy_sc_from_user(struct pt_regs *to, void __user *from)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -29,36 +29,6 @@ asmlinkage long sys_uname64(struct new_utsname __user * name)
|
|||||||
return err ? -EFAULT : 0;
|
return err ? -EFAULT : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
extern long arch_prctl(int code, unsigned long addr);
|
|
||||||
|
|
||||||
static long arch_prctl_tt(int code, unsigned long addr)
|
|
||||||
{
|
|
||||||
unsigned long tmp;
|
|
||||||
long ret;
|
|
||||||
|
|
||||||
switch(code){
|
|
||||||
case ARCH_SET_GS:
|
|
||||||
case ARCH_SET_FS:
|
|
||||||
ret = arch_prctl(code, addr);
|
|
||||||
break;
|
|
||||||
case ARCH_GET_FS:
|
|
||||||
case ARCH_GET_GS:
|
|
||||||
ret = arch_prctl(code, (unsigned long) &tmp);
|
|
||||||
if(!ret)
|
|
||||||
ret = put_user(tmp, (long __user *)addr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
|
|
||||||
long arch_prctl_skas(struct task_struct *task, int code,
|
long arch_prctl_skas(struct task_struct *task, int code,
|
||||||
unsigned long __user *addr)
|
unsigned long __user *addr)
|
||||||
{
|
{
|
||||||
@ -119,7 +89,6 @@ long arch_prctl_skas(struct task_struct *task, int code,
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
long sys_arch_prctl(int code, unsigned long addr)
|
long sys_arch_prctl(int code, unsigned long addr)
|
||||||
{
|
{
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
|
|
||||||
* Licensed under the GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/mman.h>
|
|
||||||
#include <asm/unistd.h>
|
|
||||||
|
|
||||||
static int errno;
|
|
||||||
|
|
||||||
static inline _syscall2(int,munmap,void *,start,size_t,len)
|
|
||||||
static inline _syscall6(void *,mmap,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset)
|
|
||||||
int switcheroo(int fd, int prot, void *from, void *to, int size)
|
|
||||||
{
|
|
||||||
if(munmap(to, size) < 0){
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1){
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
if(munmap(from, size) < 0){
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
return(0);
|
|
||||||
}
|
|
@ -56,12 +56,6 @@ static inline void enter_lazy_tlb(struct mm_struct *mm,
|
|||||||
extern int init_new_context_skas(struct task_struct *task,
|
extern int init_new_context_skas(struct task_struct *task,
|
||||||
struct mm_struct *mm);
|
struct mm_struct *mm);
|
||||||
|
|
||||||
static inline int init_new_context_tt(struct task_struct *task,
|
|
||||||
struct mm_struct *mm)
|
|
||||||
{
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int init_new_context(struct task_struct *task,
|
static inline int init_new_context(struct task_struct *task,
|
||||||
struct mm_struct *mm)
|
struct mm_struct *mm)
|
||||||
{
|
{
|
||||||
|
@ -34,20 +34,10 @@ struct thread_struct {
|
|||||||
void *exec_buf;
|
void *exec_buf;
|
||||||
struct arch_thread arch;
|
struct arch_thread arch;
|
||||||
union {
|
union {
|
||||||
#ifdef CONFIG_MODE_TT
|
|
||||||
struct {
|
|
||||||
int extern_pid;
|
|
||||||
int tracing;
|
|
||||||
int switch_pipe[2];
|
|
||||||
int vm_seq;
|
|
||||||
} tt;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
struct {
|
struct {
|
||||||
jmp_buf switch_buf;
|
jmp_buf switch_buf;
|
||||||
int mm_count;
|
int mm_count;
|
||||||
} skas;
|
} skas;
|
||||||
#endif
|
|
||||||
} mode;
|
} mode;
|
||||||
struct {
|
struct {
|
||||||
int op;
|
int op;
|
||||||
@ -136,12 +126,8 @@ extern struct cpuinfo_um cpu_data[];
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_MODE_SKAS
|
|
||||||
#define KSTK_REG(tsk, reg) \
|
#define KSTK_REG(tsk, reg) \
|
||||||
get_thread_reg(reg, &tsk->thread.mode.skas.switch_buf)
|
get_thread_reg(reg, &tsk->thread.mode.skas.switch_buf)
|
||||||
#else
|
|
||||||
#define KSTK_REG(tsk, reg) (0xbadbabe)
|
|
||||||
#endif
|
|
||||||
#define get_wchan(p) (0)
|
#define get_wchan(p) (0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user